mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-28 11:16:52 +01:00
feature (tags): UI for tag page
This commit is contained in:
parent
ce935525db
commit
9fa8428a28
3 changed files with 111 additions and 18 deletions
|
|
@ -38,11 +38,8 @@ class TagManager {
|
|||
}
|
||||
return Promise.resolve(tags);
|
||||
}
|
||||
// const path = this._tagPathStringToArray(tagPath);
|
||||
// Object.keys(DB.tags);
|
||||
// console.log(path);
|
||||
return Promise.resolve([
|
||||
"Bookmark", "wiki", "B", "C", "D", "E", "F"
|
||||
// "Bookmark", "wiki", "B", "C", "D", "E", "F"
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +65,7 @@ class TagManager {
|
|||
.filter((r) => r !== "" && (removeFirst ? r !== "All" : true));
|
||||
}
|
||||
|
||||
add(tag, path) {
|
||||
addTagToFile(tag, path) {
|
||||
if(Object.keys(DB.tags).indexOf(tag) === -1) {
|
||||
DB.tags[tag] = [];
|
||||
}
|
||||
|
|
@ -77,8 +74,19 @@ class TagManager {
|
|||
}
|
||||
}
|
||||
|
||||
removeTagFromFile(tag, path) {
|
||||
if(!DB.tags[tag]) return;
|
||||
const idx = DB.tags[tag].indexOf(path);
|
||||
DB.tags[tag].splice(idx, 1);
|
||||
}
|
||||
|
||||
import(_DB) {
|
||||
DB = _DB;
|
||||
return new Promise((done) => {
|
||||
setTimeout(() => {
|
||||
done();
|
||||
}, 5000);
|
||||
})
|
||||
}
|
||||
|
||||
export() {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import { Link } from "react-router-dom";
|
|||
import ReactCSSTransitionGroup from "react-addons-css-transition-group";
|
||||
import {
|
||||
NgIf, NgShow, Loader, LoggedInOnly, BreadCrumb, Card, Icon,
|
||||
Dropdown, DropdownButton, DropdownList, DropdownItem,
|
||||
} from "../components/";
|
||||
import { URL_TAGS, URL_FILES, URL_VIEWER, basename, filetype } from "../helpers/";
|
||||
import { URL_TAGS, URL_FILES, URL_VIEWER, basename, filetype, prompt, notify } from "../helpers/";
|
||||
import { Tags } from "../model/";
|
||||
import { t } from "../locales/";
|
||||
|
||||
|
|
@ -18,6 +19,7 @@ export function TagsPageComponent({ match }) {
|
|||
const [tags, setTags] = useState(null);
|
||||
const [files, setFiles] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [refresh, setRefresh] = useState(0);
|
||||
|
||||
const path = (match.url.replace(URL_TAGS, "") || "/");
|
||||
useEffect(() => {
|
||||
|
|
@ -30,12 +32,72 @@ export function TagsPageComponent({ match }) {
|
|||
setTags(t);
|
||||
setFiles(f);
|
||||
});
|
||||
}, [match.url]);
|
||||
}, [match.url, refresh]);
|
||||
|
||||
if(match.url.slice(-1) != "/") {
|
||||
return (<Redirect to={match.url + "/"} />);
|
||||
}
|
||||
|
||||
const onClickRemoveFile = (file) => {
|
||||
prompt.now(
|
||||
t("Confirm by typing") + ": remove",
|
||||
() => {
|
||||
Tags.removeTagFromFile(
|
||||
path.split("/").filter((r) => !!r).slice(-1)[0],
|
||||
file,
|
||||
);
|
||||
setRefresh(refresh + 1);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {},
|
||||
);
|
||||
}
|
||||
|
||||
const onClickMoreDropdown = (what) => {
|
||||
switch(what) {
|
||||
case "import":
|
||||
let $input = document.getElementById("import_tags");
|
||||
$input.click();
|
||||
$input.onchange = () => {
|
||||
if($input.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
let jsonObject = null;
|
||||
try {
|
||||
jsonObject = JSON.parse(reader.result);
|
||||
} catch (err) {
|
||||
notify.send(t("Not Valid"), "error");
|
||||
return;
|
||||
}
|
||||
if(JSON.stringify(Object.keys(jsonObject)) !== JSON.stringify(["tags", "weight", "share", "backend"])) {
|
||||
notify.send(t("Not Valid"), "error");
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
Tags.import(jsonObject).then(() => {
|
||||
setLoading(false);
|
||||
setRefresh(refresh + 1);
|
||||
}).catch((err) => {
|
||||
setLoading(false);
|
||||
notify.send(err, "error")
|
||||
});
|
||||
};
|
||||
reader.readAsText($input.files[0]);
|
||||
};
|
||||
break;
|
||||
case "export":
|
||||
Tags.export().then((db) => {
|
||||
const $link = document.getElementById("export_tags");
|
||||
$link.href = window.URL.createObjectURL(new Blob([JSON.stringify(db, null, 4)]));
|
||||
$link.click();
|
||||
window.URL.revokeObjectURL($link.href);
|
||||
}).catch((err) => notify.send(err, "error"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const isAFolder = (_path) => (filetype(_path) === "directory");
|
||||
|
||||
return (
|
||||
|
|
@ -45,16 +107,35 @@ export function TagsPageComponent({ match }) {
|
|||
<div className="scroll-y">
|
||||
<div className="component_submenu">
|
||||
<div className="component_container">
|
||||
<h1>
|
||||
{
|
||||
path.split("/").filter((r) => r).map((tag, idx) => (
|
||||
<React.Fragment key={idx}>#{tag} </React.Fragment>
|
||||
))
|
||||
}
|
||||
</h1>
|
||||
<div className="menubar">
|
||||
<div className="view list-grid" onClick={Tags.export}>
|
||||
<Icon name="download_white" />
|
||||
</div>
|
||||
<div className="view list-grid" onClick={Tags.import}>
|
||||
<Icon name="upload_white" />
|
||||
</div>
|
||||
<Dropdown
|
||||
className="view"
|
||||
onChange={onClickMoreDropdown}>
|
||||
<DropdownButton>
|
||||
<Icon name="more"/>
|
||||
</DropdownButton>
|
||||
<DropdownList>
|
||||
<DropdownItem name="import">
|
||||
{ t("Import Tags") }
|
||||
</DropdownItem>
|
||||
<DropdownItem name="export">
|
||||
{ t("Export Tags") }
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
<form style={{display:"none"}}><input type="file" id="import_tags" /></form>
|
||||
<div style={{display:"none"}}><a id="export_tags" download="tags.json"></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br style={{clear: "both"}}/>
|
||||
<NgShow className="component_container" cond={!loading}>
|
||||
<NgIf cond={!loading} className="list">
|
||||
<ReactCSSTransitionGroup
|
||||
|
|
@ -92,6 +173,9 @@ export function TagsPageComponent({ match }) {
|
|||
<div className="component_thing view-list" key={idx}>
|
||||
<Link to={(isAFolder(file) ? URL_FILES : URL_VIEWER) + file}>
|
||||
<Card>
|
||||
<span className="component_action" style={{float: "right"}} onClick={(e) => { e.preventDefault(); onClickRemoveFile(file)}}>
|
||||
<Icon name="close" />
|
||||
</span>
|
||||
<span><Icon name={filetype(file)} /></span>
|
||||
<span className="component_filename">
|
||||
<span className="file-details">
|
||||
|
|
|
|||
|
|
@ -15,11 +15,12 @@
|
|||
-webkit-overflow-scrolling: touch;
|
||||
.component_submenu {
|
||||
margin: 10px;
|
||||
.view {
|
||||
border-left: 5px solid var(--bg-color);
|
||||
border-radius: 3px;
|
||||
background: rgba(0,0,0,0.3);
|
||||
border-radius: 3px;
|
||||
h1 {
|
||||
font-weight: 100;
|
||||
text-transform: uppercase;
|
||||
margin: -7px 0 0 0;
|
||||
float: left;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
& > .component_container {
|
||||
|
|
|
|||
Loading…
Reference in a new issue