mirror of
https://github.com/filecoin-project/slate.git
synced 2024-11-23 14:07:20 +03:00
feat: handle tag overflow
This commit is contained in:
parent
7d769f6e41
commit
1adad7d273
@ -19,6 +19,7 @@ import { GroupSelectable, Selectable } from "~/components/core/Selectable/";
|
||||
|
||||
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
||||
import FilePreviewBubble from "~/components/core/FilePreviewBubble";
|
||||
import isEqual from "lodash/isEqual";
|
||||
|
||||
const STYLES_CONTAINER_HOVER = css`
|
||||
display: flex;
|
||||
@ -233,6 +234,70 @@ const STYLES_TAG = css`
|
||||
}
|
||||
`;
|
||||
|
||||
class Tags extends React.Component {
|
||||
state = {
|
||||
isTruncated: false,
|
||||
truncateIndex: 0,
|
||||
};
|
||||
|
||||
listWrapper = React.createRef();
|
||||
listEl = React.createRef();
|
||||
|
||||
componentDidMount() {
|
||||
this._handleTruncate();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (!isEqual(prevProps.tags, this.props.tags)) {
|
||||
this._handleTruncate();
|
||||
}
|
||||
}
|
||||
|
||||
_handleTruncate = () => {
|
||||
const listWrapper = this.listWrapper.current?.getBoundingClientRect();
|
||||
const tagNodes = this.listEl.current?.querySelectorAll("li");
|
||||
const tagElems = Array.from(tagNodes);
|
||||
|
||||
let total = 0;
|
||||
const truncateIndex = tagElems.findIndex((tagElem) => {
|
||||
const { width } = tagElem?.getBoundingClientRect();
|
||||
total += width;
|
||||
|
||||
if (total >= listWrapper.width - 50) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (truncateIndex > 0) {
|
||||
this.setState({ isTruncated: true, truncateIndex });
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ isTruncated: false, truncateIndex: tagElems.length });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { tags } = this.props;
|
||||
|
||||
return (
|
||||
<div css={STYLES_TAGS_WRAPPER}>
|
||||
<div ref={this.listWrapper} style={{ width: 340 }}>
|
||||
<ul css={STYLES_LIST} ref={this.listEl}>
|
||||
{(this.state.isTruncated ? tags.slice(0, this.state.truncateIndex) : tags).map(
|
||||
(tag) => (
|
||||
<li key={tag} css={STYLES_TAG}>
|
||||
<span>{tag}</span>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
{this.state.isTruncated && <span>...</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default class DataView extends React.Component {
|
||||
_mounted = false;
|
||||
|
||||
@ -514,27 +579,6 @@ export default class DataView extends React.Component {
|
||||
e.dataTransfer.setData("DownloadURL", `${type}:${title}:${url}`);
|
||||
};
|
||||
|
||||
_checkTagsOverflow = (i) => {
|
||||
let nodes = document.querySelectorAll(`[data-tag-list="${i}"]`)[0]?.childNodes;
|
||||
if (nodes) {
|
||||
let items = Array.from(nodes);
|
||||
|
||||
let total = 0;
|
||||
let sliceIndex;
|
||||
|
||||
for (let [index, item] of Object.entries(items)) {
|
||||
if (total >= 220) {
|
||||
sliceIndex = index;
|
||||
break;
|
||||
}
|
||||
|
||||
total += item.offsetWidth;
|
||||
}
|
||||
|
||||
return sliceIndex;
|
||||
}
|
||||
};
|
||||
|
||||
getCommonTagFromSelectedItems = () => {
|
||||
const { items } = this.props;
|
||||
const { checked } = this.state;
|
||||
@ -634,7 +678,7 @@ export default class DataView extends React.Component {
|
||||
});
|
||||
}}
|
||||
>
|
||||
Edit tags
|
||||
Edit tag{numChecked > 1 ? "s" : ""}
|
||||
</ButtonPrimary>
|
||||
<ButtonWarning
|
||||
transparent
|
||||
@ -845,7 +889,7 @@ export default class DataView extends React.Component {
|
||||
{
|
||||
key: "tags",
|
||||
name: <div style={{ fontSize: "0.9rem", padding: "18px 0" }}>Tags</div>,
|
||||
width: "341px",
|
||||
width: "360px",
|
||||
},
|
||||
{
|
||||
key: "size",
|
||||
@ -900,21 +944,7 @@ export default class DataView extends React.Component {
|
||||
</FilePreviewBubble>
|
||||
</Selectable>
|
||||
),
|
||||
tags: (
|
||||
<>
|
||||
{each.tags && (
|
||||
<div css={STYLES_TAGS_WRAPPER}>
|
||||
<ul css={STYLES_LIST} data-tag-list={index}>
|
||||
{each.tags.map((tag, i) => (
|
||||
<li key={tag} css={STYLES_TAG}>
|
||||
<span>{tag}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
tags: <>{each.tags && <Tags tags={each.tags} />}</>,
|
||||
size: <div css={STYLES_VALUE}>{Strings.bytesToSize(each.size)}</div>,
|
||||
more: (
|
||||
<div
|
||||
|
@ -20,7 +20,7 @@ const STYLES_GROUPING = css`
|
||||
|
||||
export default class SidebarEditTags extends React.Component {
|
||||
state = {
|
||||
newTags:
|
||||
tags:
|
||||
!Array.isArray(this.props.sidebarData.commonTags) ||
|
||||
this.props.sidebarData.commonTags?.length === 0
|
||||
? []
|
||||
@ -38,10 +38,10 @@ export default class SidebarEditTags extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
/* updateSuggestions = () => {
|
||||
let newSuggestions = new Set([...this.props.sidebarData.suggestions, ...this.state.newTags]);
|
||||
updateSuggestions = () => {
|
||||
let newSuggestions = new Set([...this.props.sidebarData.suggestions, ...this.state.tags]);
|
||||
this.setState({ suggestions: Array.from(newSuggestions) });
|
||||
}; */
|
||||
};
|
||||
|
||||
_handleSave = async (details, index) => {
|
||||
let { objects } = this.props.sidebarData;
|
||||
@ -51,40 +51,55 @@ export default class SidebarEditTags extends React.Component {
|
||||
id: this.props.viewer.id,
|
||||
data: objects[index],
|
||||
});
|
||||
console.log(response);
|
||||
|
||||
this.props.onUpdateViewer({ tags: this.state.suggestions });
|
||||
|
||||
Events.hasError(response);
|
||||
};
|
||||
|
||||
_handleSubmit = async () => {
|
||||
let { checked, objects, commonTags } = this.props.sidebarData;
|
||||
this.props.onCancel();
|
||||
|
||||
let { checked, objects, commonTags } = this.props.sidebarData;
|
||||
const checkedIndexes = Object.keys(checked);
|
||||
/* data must be fixed */
|
||||
/* let data = { tags: this.state.newTags }; */
|
||||
let data;
|
||||
|
||||
await Promise.all(
|
||||
checkedIndexes.map(async (checkedIndex) => {
|
||||
let prevTags = objects[checkedIndex]?.tags;
|
||||
console.log({ prevTags });
|
||||
let newTags = this.state.newTags;
|
||||
console.log({ newTags });
|
||||
console.log({ commonTags });
|
||||
/* commonTags */
|
||||
let objectTags = Array.isArray(objects[checkedIndex]?.tags)
|
||||
? objects[checkedIndex].tags
|
||||
: [];
|
||||
let newTags = this.state.tags;
|
||||
|
||||
/*
|
||||
1. If there is an item in newTags which is not in commonTag, add to prevTags;
|
||||
2. If there is an item in commonTag which is not in newTags, remove it from prevTags;
|
||||
*/
|
||||
let data;
|
||||
|
||||
if (newTags.length > commonTags.length) {
|
||||
let update = new Set([...prevTags, ...newTags, ...commonTags]);
|
||||
data = { tags: Array.from(update) };
|
||||
/* NOTE(daniel): since there are no common tags, we are simply adding new tags to the files */
|
||||
if (!commonTags.length) {
|
||||
data = { tags: [...new Set([...objectTags, ...newTags])] };
|
||||
return await this._handleSave(data, checkedIndex);
|
||||
}
|
||||
|
||||
this._handleSave(data, checkedIndex);
|
||||
/* NOTE(daniel): symmetrical difference between new tags and common tags */
|
||||
let diff = newTags
|
||||
.filter((i) => !commonTags.includes(i))
|
||||
.concat(commonTags.filter((i) => !newTags.includes(i)));
|
||||
|
||||
let update = diff.reduce((acc, cur) => {
|
||||
if (!commonTags.includes(cur) && newTags.includes(cur)) {
|
||||
acc.push(cur);
|
||||
} else if (commonTags.includes(cur) && !newTags.includes(cur)) {
|
||||
let removalIndex = acc.findIndex((item) => item === cur);
|
||||
acc.splice(removalIndex, 1);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, objectTags);
|
||||
|
||||
data = { tags: update };
|
||||
|
||||
return await this._handleSave(data, checkedIndex);
|
||||
})
|
||||
);
|
||||
|
||||
this.updateSuggestions();
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -125,9 +140,8 @@ export default class SidebarEditTags extends React.Component {
|
||||
<Tag
|
||||
name="tags"
|
||||
placeholder={`Edit tags for ${`${numChecked} file${numChecked === 1 ? "" : "s"}`} `}
|
||||
tags={this.state.newTags}
|
||||
tags={this.state.tags}
|
||||
suggestions={this.state.suggestions}
|
||||
style={{ margin: "0 0 16px" }}
|
||||
onChange={this._handleChange}
|
||||
/* handleTagDelete={this._handleTagDelete} */
|
||||
/>
|
||||
|
Loading…
Reference in New Issue
Block a user