+
+
+
All
+
{
tags && tags.map((tag, index) => {
return (
diff --git a/client/pages/filespage/tag.js b/client/pages/filespage/tag.js
new file mode 100644
index 00000000..1f9339ff
--- /dev/null
+++ b/client/pages/filespage/tag.js
@@ -0,0 +1,139 @@
+import React, { useState, useRef, useEffect } from "react";
+
+import {
+ Icon, Input,
+} from "../../components/";
+import { Tags } from "../../model/";
+import { t } from "../../locales/";
+import "./tag.scss";
+
+export function TagComponent({ path }) {
+ const [DB, setDB] = useState(null);
+ const [input, setInput] = useState("");
+
+ useEffect(() => {
+ Tags.export().then((db) => {
+ setDB(db);
+ });
+ }, []);
+
+ const onFormSubmit = (e) => {
+ if (!DB) return;
+ else if(!DB.tags) return;
+
+ e.preventDefault();
+ const it = input.trim().toLowerCase();
+ if (it === "") return;
+
+ const newDB = {...DB};
+ newDB.tags = {};
+ newDB.tags[it] = [path];
+ Object.keys(DB.tags).forEach((tag) => {
+ newDB.tags[tag] = DB.tags[tag];
+ });
+ setDB(newDB);
+ setInput("");
+ Tags.import(newDB);
+ };
+ const onClickTag = (tagName) => {
+ if (!DB) return;
+ else if(!DB.tags) return;
+ console.log("CLICK ON ", tagName, "idx", DB.tags[tagName].indexOf(path));
+
+ const newDB = {...DB};
+ if (isTagActive(tagName)) {
+ newDB.tags[tagName].splice(DB.tags[tagName].indexOf(path), 1);
+ } else {
+ newDB.tags[tagName].push(path);
+ }
+ setDB(newDB);
+ Tags.import(newDB);
+ };
+ const onClickMoveUp = (tagName) => {
+ if (!DB) return;
+ else if(!DB.tags) return;
+
+ const newDB = {...DB};
+ const keys = Object.keys(DB.tags) || [];
+ const n = keys.indexOf(tagName);
+ if (n === 0) return;
+
+ newDB.tags = {};
+ for (let i=0; i
{
+ if (!DB) return;
+ else if(!DB.tags) return;
+
+ const newDB = {...DB};
+ const keys = Object.keys(DB.tags) || [];
+ const n = keys.indexOf(tagName);
+ if (n === keys.length - 1) return;
+
+ newDB.tags = {};
+ for (let i=0; i {
+ const newDB = {...DB};
+ delete newDB.tags[tagName];
+ Tags.import(newDB);
+ setDB(newDB);
+ };
+
+ const isTagActive = (tagName) => {
+ if (!DB) return false;
+ else if(!DB.tags) return false;
+ return DB.tags[tagName].indexOf(path) !== -1;
+ }
+
+ const TAGS = DB && Object.keys(DB.tags);
+ return (
+
+
+
+ {
+ TAGS && TAGS.length > 0 ?
+ Object.keys(DB.tags).map((tag) => (
+
+
onClickTag(tag)}>{ tag } { (DB.tags[tag] || []).length }
+
onClickMoveUp(tag)} />
+ onClickMoveDown(tag)} />
+ onClickRemove(tag)} />
+
+ )) : (
+
+
onClickTag(t("Bookmark"))}>{ t("Bookmark") }
+
+ )
+ }
+
+
+ );
+}
diff --git a/client/pages/filespage/tag.scss b/client/pages/filespage/tag.scss
new file mode 100644
index 00000000..ec183d8a
--- /dev/null
+++ b/client/pages/filespage/tag.scss
@@ -0,0 +1,43 @@
+.component_tag {
+ input {
+ font-size: 1.2em;
+ }
+ input::placeholder {
+ font-weight: 100;
+ }
+ .box {
+ display: flex;
+ background: var(--bg-color);
+ transition: background 0.1s ease;
+ &.active{ background: var(--primary); color: var(--color); }
+ padding: 5px 10px;
+ border-radius: 3px;
+
+ > div {
+ flex-grow: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ img {
+ width: 20px;
+ background: rgba(0,0,0,0.05);
+ border-radius: 50%;
+ margin-left: 5px;
+ &[alt="close"] {
+ width: 14px;
+ padding: 3px;
+ }
+ }
+ .count {
+ opacity: 0.5;
+ font-size: 0.9rem;
+ &:before { content: "["; }
+ &:after { content: "]"; }
+ }
+ }
+ .scroll-y {
+ overflow-y: auto !important;
+ max-height: 200px;
+ }
+}
diff --git a/client/pages/filespage/thing-existing.js b/client/pages/filespage/thing-existing.js
index bbbc5a47..2ec4bcf8 100644
--- a/client/pages/filespage/thing-existing.js
+++ b/client/pages/filespage/thing-existing.js
@@ -8,6 +8,7 @@ import { Card, NgIf, Icon, EventEmitter, img_placeholder, Input } from "../../co
import { pathBuilder, basename, filetype, prompt, alert, leftPad, getMimeType, debounce, memory } from "../../helpers/";
import { Files } from "../../model/";
import { ShareComponent } from "./share";
+import { TagComponent } from "./tag";
import { t } from "../../locales/";
@@ -227,6 +228,13 @@ class ExistingThingComponent extends React.Component {
this.setState({ delete_request: false });
}
+ onTagRequest() {
+ alert.now(
+ ,
+ () => {},
+ )
+ }
+
onShareRequest(filename) {
alert.now(
,
@@ -321,6 +329,7 @@ class ExistingThingComponent extends React.Component {
onClickRename={this.onRenameRequest.bind(this)}
onClickDelete={this.onDeleteRequest.bind(this)}
onClickShare={this.onShareRequest.bind(this)}
+ onClickTag={this.onTagRequest.bind(this)}
is_renaming={this.state.is_renaming}
can_rename={this.props.metadata.can_rename !== false}
can_delete={this.props.metadata.can_delete !== false}
@@ -371,6 +380,7 @@ class Filename extends React.Component {
e.preventDefault();
e.stopPropagation();
this.props.onRename(this.state.filename);
+ return false;
}
onCancel() {
@@ -380,6 +390,7 @@ class Filename extends React.Component {
preventSelect(e) {
e.preventDefault();
+ e.stopPropagation();
}
render() {
@@ -412,7 +423,7 @@ class Filename extends React.Component {