Merge pull request #3796 from lbryio/limit_tags_on_publishes

overhaul tags
This commit is contained in:
jessopb 2020-03-06 17:39:36 -05:00 committed by GitHub
commit f07182bca3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 34 deletions

View file

@ -989,8 +989,6 @@
"Share usage data with LBRY inc.": "Share usage data with LBRY inc.",
"Required": "Required",
"Email %help_link% or join our %chat_link% if you encounter any trouble verifying.": "Email %help_link% or join our %chat_link% if you encounter any trouble verifying.",
"Only apply a few tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.": "Only apply a few tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.",
"Add relevant tags...": "Add relevant tags...",
"try again in a few seconds.": "try again in a few seconds.",
"Any": "Any",
"Video": "Video",
@ -1005,5 +1003,19 @@
"Model": "Model",
"Binary": "Binary",
"Other": "Other",
"For video content, use MP4s in H264/AAC format and a friendly bitrate (720p) for more reliable streaming.": "For video content, use MP4s in H264/AAC format and a friendly bitrate (720p) for more reliable streaming."
}
"For video content, use MP4s in H264/AAC format and a friendly bitrate (720p) for more reliable streaming.": "For video content, use MP4s in H264/AAC format and a friendly bitrate (720p) for more reliable streaming.",
"Show reposts": "Show reposts",
"Show reposts from the creators you follow.": "Show reposts from the creators you follow.",
"You can try refreshing to fix it. If you still have issues, your anti-virus software or firewall may be preventing startup.": "You can try refreshing to fix it. If you still have issues, your anti-virus software or firewall may be preventing startup.",
"Only apply a few tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.": "Only apply a few tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.",
"Add relevant tags...": "Add relevant tags...",
"Enter up to five (5) tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.": "Enter up to five (5) tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.",
"Sorry, your request timed out. Modify your options or %again%": "Sorry, your request timed out. Modify your options or %again%",
"gaming, crypto": "gaming, crypto",
"Autocomplete": "Autocomplete",
"Followed Tags": "Followed Tags",
"Add tags that are relevant to your content. If mature content, ensure it is tagged mature. Tag abuse and missing mature tags will not be tolerated.": "Add tags that are relevant to your content. If mature content, ensure it is tagged mature. Tag abuse and missing mature tags will not be tolerated.",
"%selectTagsLabel% (%number% left)": "%selectTagsLabel% (%number% left)",
"Matching": "Matching",
"No matching tags": "No matching tags"
}

View file

@ -87,6 +87,7 @@ function PublishForm(props: Props) {
publish,
disabled = false,
} = props;
const TAGS_LIMIT = 5;
const formDisabled = (!filePath && !editingURI) || publishing;
const isInProgress = filePath || editingURI || name || title;
@ -152,10 +153,11 @@ function PublishForm(props: Props) {
hideHeader
label={__('Selected Tags')}
empty={__('No tags added')}
limit={TAGS_LIMIT}
help={__(
'Only apply a few tags that are relevant to your content, and use the Mature tag as appropriate. Tag abuse will not be tolerated.'
'Add tags that are relevant to your content. If mature content, ensure it is tagged mature. Tag abuse and missing mature tags will not be tolerated.'
)}
placeholder={__('Add relevant tags...')}
placeholder={__('gaming, crypto')}
onSelect={newTags => {
const validatedTags = [];
newTags.forEach(newTag => {

View file

@ -31,6 +31,7 @@ export default function Tag(props: Props) {
disabled={disabled}
title={title}
className={classnames('tag', {
'tag--disabled': disabled === true,
'tag--large': type === 'large',
'tag--remove': type === 'remove',
// tag--add only adjusts the color, which causes issues with mature tag color clashing

View file

@ -3,6 +3,7 @@ import React, { useState } from 'react';
import { Form, FormField } from 'component/common/form';
import Tag from 'component/tag';
import { setUnion, setDifference } from 'util/set-operations';
import I18nMessage from 'component/i18nMessage';
type Props = {
tagsPassedIn: Array<Tag>,
@ -16,6 +17,8 @@ type Props = {
onRemove: Tag => void,
placeholder?: string,
label?: string,
disabled?: boolean,
limit?: number,
};
/*
@ -38,6 +41,8 @@ export default function TagsSearch(props: Props) {
disableAutoFocus,
placeholder,
label,
disabled,
limit,
} = props;
const [newTag, setNewTag] = useState('');
const doesTagMatch = name => {
@ -54,6 +59,8 @@ export default function TagsSearch(props: Props) {
const remainingFollowedTagsSet = setDifference(followedTagsSet, selectedTagsSet);
const suggestedTagsSet = setUnion(remainingFollowedTagsSet, unfollowedTagsSet);
const countWithoutMature = selectedTagsSet.has('mature') ? selectedTagsSet.size - 1 : selectedTagsSet.size;
const maxed = Boolean(limit && countWithoutMature >= limit);
const suggestedTags = Array.from(suggestedTagsSet)
.filter(doesTagMatch)
.slice(0, 5);
@ -108,37 +115,70 @@ export default function TagsSearch(props: Props) {
return (
<React.Fragment>
<Form className="tags__input-wrapper" onSubmit={handleSubmit}>
<label>{label || __('Following')}</label>
<ul className="tags--remove">
{tagsPassedIn.map(tag => (
<Tag
key={`passed${tag.name}`}
name={tag.name}
type="remove"
onClick={() => {
onRemove(tag);
<label>
{limit ? (
<I18nMessage
tokens={{
number: 5 - countWithoutMature,
selectTagsLabel: label,
}}
/>
))}
<li>
<FormField
autoFocus={!disableAutoFocus}
className="tag__input"
onChange={onChange}
placeholder={placeholder || __('Follow more tags')}
type="text"
value={newTag}
/>
</li>
>
%selectTagsLabel% (%number% left)
</I18nMessage>
) : (
label || __('Following')
)}
</label>
<ul className="tags--remove">
{!tagsPassedIn.length && <Tag key={`placeholder-tag`} name={'example'} disabled type={'remove'} />}
{Boolean(tagsPassedIn.length) &&
tagsPassedIn.map(tag => (
<Tag
key={`passed${tag.name}`}
name={tag.name}
type="remove"
onClick={() => {
onRemove(tag);
}}
/>
))}
</ul>
<FormField
autoFocus={!disableAutoFocus}
className="tag__input"
onChange={onChange}
placeholder={placeholder || __('gaming, crypto')}
type="text"
value={newTag}
disabled={disabled}
label={'Add Tags'}
/>
<section>
<label>{newTag.length ? __('Matching') : __('Followed Tags')}</label>
<ul className="tags">
{Boolean(newTag.length) && !suggestedTags.includes(newTag) && (
<Tag
disabled={newTag !== 'mature' && maxed}
key={`entered${newTag}`}
name={newTag}
type="add"
onClick={newTag.includes('') ? e => handleSubmit(e) : e => handleTagClick(newTag)}
/>
)}
{suggestedTags.map(tag => (
<Tag
disabled={tag !== 'mature' && maxed}
key={`suggested${tag}`}
name={tag}
type="add"
onClick={() => handleTagClick(tag)}
/>
))}
{!suggestedTags.length && <p className="empty tags__empty-message">{__('No matching tags')}</p>}
</ul>
</section>
</Form>
<label>{__('Suggested')}</label>
<ul className="tags">
{suggestedTags.map(tag => (
<Tag key={`suggested${tag}`} name={tag} type="add" onClick={() => handleTagClick(tag)} />
))}
{!suggestedTags.length && <p className="empty tags__empty-message">No suggested tags</p>}
</ul>
</React.Fragment>
);
}

View file

@ -24,6 +24,7 @@ type Props = {
placeholder?: string,
disableAutoFocus?: boolean,
hideHeader?: boolean,
limit?: number,
};
/*
@ -44,6 +45,7 @@ export default function TagsSelect(props: Props) {
placeholder,
hideHeader,
label,
limit,
} = props;
const [hasClosed, setHasClosed] = usePersistedState('tag-select:has-closed', false);
const tagsToDisplay = tagsChosen || followedTags;
@ -105,6 +107,7 @@ export default function TagsSelect(props: Props) {
disableAutoFocus={disableAutoFocus}
tagsPassedIn={tagsToDisplay}
placeholder={placeholder}
limit={limit}
/>
</React.Fragment>
}

View file

@ -43,6 +43,7 @@
height: var(--tag-height);
padding: calc(var(--spacing-miniscule) + 1px) var(--spacing-small);
background-color: var(--color-input-bg);
margin-bottom: var(--spacing-medium);
}
}
@ -55,6 +56,10 @@
max-width: 20rem;
}
.tag--disabled {
opacity: 0.3;
}
.tag--large {
height: var(--height-input);
padding: 0 var(--spacing-s);