feature (tags): UI for tag page

This commit is contained in:
Mickael Kerjean 2022-10-10 22:15:13 +11:00
parent ce935525db
commit 9fa8428a28
3 changed files with 111 additions and 18 deletions

View file

@ -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() {

View file

@ -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">

View file

@ -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 {