mature tags
This commit is contained in:
parent
fd181ebde2
commit
52bc0e7a1a
13 changed files with 58 additions and 37 deletions
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import Button from 'component/button';
|
||||
import Tag from 'component/tag';
|
||||
|
||||
const SLIM_TAGS = 1;
|
||||
const NORMAL_TAGS = 4;
|
||||
|
@ -45,7 +45,7 @@ export default function ClaimTags(props: Props) {
|
|||
return (
|
||||
<div className={classnames('file-properties', { 'file-properties--large': type === 'large' })}>
|
||||
{tagsToDisplay.map(tag => (
|
||||
<Button key={tag} title={tag} navigate={`$/tags?t=${tag}`} className="tag" label={tag} />
|
||||
<Tag key={tag} title={tag} name={tag} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -44,7 +44,7 @@ class CreditAmount extends React.PureComponent<Props> {
|
|||
|
||||
let amountText;
|
||||
if (showFree && isFree) {
|
||||
amountText = __('FREE');
|
||||
amountText = __('Free');
|
||||
} else {
|
||||
amountText = formattedAmount;
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ function PublishForm(props: Props) {
|
|||
<div className="card">
|
||||
<TagSelect
|
||||
title={false}
|
||||
suggestMature
|
||||
help={__('The better your tags are, the easier it will be for people to discover your content.')}
|
||||
empty={__('No tags added')}
|
||||
onSelect={tag => updatePublishForm({ tags: [...tags, tag] })}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { MATURE_TAGS } from 'lbry-redux';
|
||||
import Button from 'component/button';
|
||||
|
||||
type Props = {
|
||||
|
@ -13,8 +14,9 @@ type Props = {
|
|||
|
||||
export default function Tag(props: Props) {
|
||||
const { name, onClick, type = 'link', disabled = false } = props;
|
||||
|
||||
const isMature = MATURE_TAGS.includes(name);
|
||||
const clickProps = onClick ? { onClick } : { navigate: `/$/tags?t=${name}` };
|
||||
|
||||
let title;
|
||||
if (!onClick) {
|
||||
title = __('View tag');
|
||||
|
@ -28,8 +30,10 @@ export default function Tag(props: Props) {
|
|||
disabled={disabled}
|
||||
title={title}
|
||||
className={classnames('tag', {
|
||||
'tag--add': type === 'add',
|
||||
'tag--remove': type === 'remove',
|
||||
// tag--add only adjusts the color, which causes issues with mature tag color clashing
|
||||
'tag--add': !isMature && type === 'add',
|
||||
'tag--mature': isMature,
|
||||
})}
|
||||
label={name}
|
||||
iconSize={12}
|
||||
|
|
|
@ -16,10 +16,11 @@ type Props = {
|
|||
doToggleTagFollow: string => void,
|
||||
doAddTag: string => void,
|
||||
onSelect?: Tag => void,
|
||||
suggestMature?: boolean,
|
||||
};
|
||||
|
||||
export default function TagSelect(props: Props) {
|
||||
const { unfollowedTags = [], followedTags = [], doToggleTagFollow, doAddTag, onSelect } = props;
|
||||
const { unfollowedTags = [], followedTags = [], doToggleTagFollow, doAddTag, onSelect, suggestMature } = props;
|
||||
const [newTag, setNewTag] = useState('');
|
||||
|
||||
let tags = unfollowedTags.slice();
|
||||
|
@ -34,6 +35,10 @@ export default function TagSelect(props: Props) {
|
|||
.filter(doesTagMatch)
|
||||
.slice(0, 5);
|
||||
|
||||
if (!newTag && suggestMature) {
|
||||
suggestedTags.push('mature');
|
||||
}
|
||||
|
||||
const suggestedTransitions = useTransition(suggestedTags, tag => tag, unfollowedTagsAnimation);
|
||||
|
||||
function onChange(e) {
|
||||
|
|
|
@ -11,6 +11,7 @@ type Props = {
|
|||
showClose: boolean,
|
||||
followedTags: Array<Tag>,
|
||||
doToggleTagFollow: string => void,
|
||||
suggestMature: boolean,
|
||||
|
||||
// Ovverides
|
||||
// The default component is for following tags
|
||||
|
@ -29,10 +30,22 @@ const tagsAnimation = {
|
|||
};
|
||||
|
||||
export default function TagSelect(props: Props) {
|
||||
const { showClose, followedTags, doToggleTagFollow, title, help, empty, tagsChosen, onSelect, onRemove } = props;
|
||||
const {
|
||||
showClose,
|
||||
followedTags,
|
||||
doToggleTagFollow,
|
||||
title,
|
||||
help,
|
||||
empty,
|
||||
tagsChosen,
|
||||
onSelect,
|
||||
onRemove,
|
||||
suggestMature,
|
||||
} = props;
|
||||
const [hasClosed, setHasClosed] = usePersistedState('tag-select:has-closed', false);
|
||||
const tagsToDisplay = tagsChosen || followedTags;
|
||||
const transitions = useTransition(tagsToDisplay, tag => tag.name, tagsAnimation);
|
||||
const hasMatureTag = tagsToDisplay.map(tag => tag.name).includes('mature');
|
||||
|
||||
function handleClose() {
|
||||
setHasClosed(true);
|
||||
|
@ -73,7 +86,7 @@ export default function TagSelect(props: Props) {
|
|||
<div className="empty">{empty || __("You aren't following any tags, try searching for one.")}</div>
|
||||
)}
|
||||
</ul>
|
||||
<TagsSearch onSelect={onSelect} />
|
||||
<TagsSearch onSelect={onSelect} suggestMature={suggestMature && !hasMatureTag} />
|
||||
{help !== false && (
|
||||
<p className="help">{help || __("The tags you follow will change what's trending for you.")}</p>
|
||||
)}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
export const defaultFollowedTags = [
|
||||
'blockchain',
|
||||
'news',
|
||||
'learning',
|
||||
'technology',
|
||||
'automotive',
|
||||
'economics',
|
||||
'food',
|
||||
'science',
|
||||
'art',
|
||||
'nature',
|
||||
];
|
||||
|
||||
export const defaultKnownTags = ['beliefs', 'funny', 'gaming', 'pop culture', 'music', 'sports', 'weapons'];
|
|
@ -312,7 +312,7 @@ class FilePage extends React.Component<Props> {
|
|||
/>
|
||||
<div className="file-properties">
|
||||
{isRewardContent && <Icon size={20} iconColor="red" icon={icons.FEATURED} />}
|
||||
{nsfw && <div className="badge badge--nsfw">MATURE</div>}
|
||||
{nsfw && <div className="badge badge--mature">{__('Mature')}</div>}
|
||||
<FilePrice badge uri={normalizeURI(uri)} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
searchReducer,
|
||||
walletReducer,
|
||||
notificationsReducer,
|
||||
tagsReducerBuilder,
|
||||
tagsReducer,
|
||||
commentReducer,
|
||||
} from 'lbry-redux';
|
||||
import { userReducer, rewardsReducer, costInfoReducer, blacklistReducer, homepageReducer, statsReducer } from 'lbryinc';
|
||||
|
@ -16,17 +16,6 @@ import contentReducer from 'redux/reducers/content';
|
|||
import settingsReducer from 'redux/reducers/settings';
|
||||
import subscriptionsReducer from 'redux/reducers/subscriptions';
|
||||
import publishReducer from 'redux/reducers/publish';
|
||||
import { defaultKnownTags, defaultFollowedTags } from 'constants/tags';
|
||||
|
||||
function getDefaultKnownTags() {
|
||||
return defaultFollowedTags.concat(defaultKnownTags).reduce(
|
||||
(tagsMap, tag) => ({
|
||||
...tagsMap,
|
||||
[tag]: { name: tag },
|
||||
}),
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
export default history =>
|
||||
combineReducers({
|
||||
|
@ -47,7 +36,7 @@ export default history =>
|
|||
settings: settingsReducer,
|
||||
stats: statsReducer,
|
||||
subscriptions: subscriptionsReducer,
|
||||
tags: tagsReducerBuilder({ followedTags: defaultFollowedTags, knownTags: getDefaultKnownTags() }),
|
||||
tags: tagsReducer,
|
||||
user: userReducer,
|
||||
wallet: walletReducer,
|
||||
});
|
||||
|
|
|
@ -155,6 +155,7 @@ export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileLis
|
|||
license_url: licenseUrl,
|
||||
thumbnail,
|
||||
title,
|
||||
tags,
|
||||
} = value;
|
||||
|
||||
const publishData: UpdatePublishFormData = {
|
||||
|
@ -171,6 +172,7 @@ export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileLis
|
|||
uploadThumbnailStatus: thumbnail ? THUMBNAIL_STATUSES.MANUAL : undefined,
|
||||
licenseUrl,
|
||||
nsfw: isClaimNsfw(claim),
|
||||
tags: tags ? tags.map(tag => ({ name: tag })) : [],
|
||||
};
|
||||
|
||||
if (channelName) {
|
||||
|
|
|
@ -19,3 +19,12 @@
|
|||
background-color: $lbry-red-2;
|
||||
color: $lbry-white;
|
||||
}
|
||||
|
||||
.badge--mature {
|
||||
background-color: lighten($lbry-grape-1, 10%);
|
||||
color: $lbry-black;
|
||||
|
||||
svg {
|
||||
stroke: $lbry-black;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ $main: $lbry-teal-5;
|
|||
}
|
||||
|
||||
.tag {
|
||||
@extend .badge;
|
||||
@extend .badge--tag;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
|
@ -61,12 +62,20 @@ $main: $lbry-teal-5;
|
|||
}
|
||||
|
||||
.tag--remove {
|
||||
@extend .tag;
|
||||
max-width: 20rem;
|
||||
}
|
||||
|
||||
.tag--add {
|
||||
background-color: lighten($lbry-teal-5, 60%);
|
||||
|
||||
&.tag--mature {
|
||||
@extend .badge--mature;
|
||||
}
|
||||
}
|
||||
|
||||
.tag--mature {
|
||||
@extend .badge--mature;
|
||||
// Lighten the color a little so it doesn't stand out as much on claim previews
|
||||
}
|
||||
|
||||
.tag__action-label {
|
||||
|
|
|
@ -74,6 +74,7 @@ const appFilter = createFilter('app', ['hasClickedComment', 'searchOptionsExpand
|
|||
// We only need to persist the receiveAddress for the wallet
|
||||
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
||||
const searchFilter = createFilter('search', ['options']);
|
||||
const tagsFilter = createFilter('tags', ['followedTags']);
|
||||
const whiteListedReducers = [
|
||||
// @if TARGET='app'
|
||||
'publish',
|
||||
|
@ -86,6 +87,7 @@ const whiteListedReducers = [
|
|||
'search',
|
||||
'tags',
|
||||
];
|
||||
|
||||
const persistOptions = {
|
||||
whitelist: whiteListedReducers,
|
||||
// Order is important. Needs to be compressed last or other transforms can't
|
||||
|
@ -98,6 +100,7 @@ const persistOptions = {
|
|||
// @endif
|
||||
appFilter,
|
||||
searchFilter,
|
||||
tagsFilter,
|
||||
compressor,
|
||||
],
|
||||
debounce: 5000,
|
||||
|
|
Loading…
Reference in a new issue