mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-03-11 07:27:22 -04:00
Bulk actions support (#1418)
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
#page-profile-media,
|
||||
#page-profile-playlists,
|
||||
#page-profile-about,
|
||||
#page-profile-shared-by-me,
|
||||
#page-profile-shared-with-me,
|
||||
#page-liked.profile-page-liked,
|
||||
#page-history.profile-page-history {
|
||||
.page-main {
|
||||
@@ -33,6 +35,7 @@
|
||||
li {
|
||||
a {
|
||||
color: var(--profile-page-nav-link-text-color);
|
||||
text-transform: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--profile-page-nav-link-hover-text-color);
|
||||
@@ -189,49 +192,151 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
a.edit-channel,
|
||||
a.edit-profile {
|
||||
a.edit-channel-icon {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
a.edit-channel,
|
||||
a.edit-profile,
|
||||
.delete-profile-wrap > button {
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
color: #fff;
|
||||
border: 0;
|
||||
line-height: inherit;
|
||||
|
||||
padding: 6px 12px;
|
||||
border-radius: 1px;
|
||||
|
||||
background-color: var(--brand-color, var(--default-brand-color));
|
||||
|
||||
@media screen and (min-width: 710px) {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
a.edit-channel,
|
||||
a.edit-profile {
|
||||
}
|
||||
|
||||
a.edit-channel {
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
border: 0;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(40, 167, 69, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
|
||||
@media screen and (min-width: 710px) {
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-size: 22px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(40, 167, 69, 1);
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.dark_theme & {
|
||||
background-color: rgba(40, 167, 69, 0.9);
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(40, 167, 69, 1);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.edit-profile {
|
||||
top: 0;
|
||||
right: 0;
|
||||
a.edit-profile-icon {
|
||||
text-decoration: none;
|
||||
color: #666;
|
||||
border: 0;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
|
||||
.material-icons {
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
.material-icons {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
color: #333;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.dark_theme & {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: #aaa;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.delete-profile-wrap > button {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
border: 0;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(220, 53, 69, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
|
||||
.material-icons {
|
||||
font-size: 22px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(220, 53, 69, 1);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.dark_theme & {
|
||||
background-color: rgba(255, 107, 107, 0.9);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 107, 107, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.delete-profile-wrap {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
@@ -250,6 +355,13 @@
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
|
||||
// Reduce padding on mobile
|
||||
@media screen and (max-width: 480px) {
|
||||
padding-top: 12px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 710px) {
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
@@ -297,6 +409,20 @@
|
||||
font-weight: 400;
|
||||
line-height: 1.25;
|
||||
margin: 0;
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-name-edit-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-info-inner {
|
||||
@@ -341,6 +467,9 @@
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
clear: both;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
.sliding-sidebar & {
|
||||
transition-property: width;
|
||||
@@ -348,54 +477,115 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.items-list-outer .previous-slide,
|
||||
&.items-list-outer .next-slide {
|
||||
top: 4px;
|
||||
bottom: 4px;
|
||||
padding: 0 !important;
|
||||
.previous-slide,
|
||||
.next-slide {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 4px !important;
|
||||
margin: 0;
|
||||
background-color: var(--profile-page-header-bg-color);
|
||||
height: $_authorPage-navHeight;
|
||||
flex-shrink: 0;
|
||||
z-index: 2;
|
||||
|
||||
.circle-icon-button {
|
||||
margin: 0;
|
||||
background-color: var(--profile-page-header-bg-color);
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.items-list-outer .previous-slide {
|
||||
left: -0.75em;
|
||||
left: -1px;
|
||||
.previous-slide {
|
||||
padding-right: 8px !important;
|
||||
}
|
||||
|
||||
&.items-list-outer .next-slide {
|
||||
right: -0.75em;
|
||||
right: -1px;
|
||||
.next-slide {
|
||||
padding-left: 8px !important;
|
||||
}
|
||||
|
||||
ul {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
float: left;
|
||||
flex: 1;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
font-size: 0;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
scroll-behavior: smooth;
|
||||
min-width: 0; // Allow flex item to shrink
|
||||
|
||||
// Hide scrollbar but keep functionality
|
||||
scrollbar-width: none; // Firefox
|
||||
-ms-overflow-style: none; // IE/Edge
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none; // Chrome/Safari
|
||||
}
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: bottom;
|
||||
flex-shrink: 0;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
line-height: $_authorPage-navHeight;
|
||||
width: 109px;
|
||||
width: auto;
|
||||
padding: 0 16px;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
text-transform: none !important;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.007px;
|
||||
|
||||
// Mobile optimization - remove padding and reduce width
|
||||
@media screen and (max-width: 768px) {
|
||||
width: auto;
|
||||
font-size: 11px;
|
||||
padding: 0 8px;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
width: auto;
|
||||
font-size: 10px;
|
||||
padding: 0 6px;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 360px) {
|
||||
width: auto;
|
||||
font-size: 9px;
|
||||
padding: 0 4px;
|
||||
margin: 0;
|
||||
letter-spacing: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure icon buttons are visible on mobile
|
||||
&.media-search,
|
||||
&.media-filters-toggle,
|
||||
&.media-tags-toggle,
|
||||
&.media-sorting-toggle {
|
||||
@media screen and (max-width: 768px) {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
@@ -411,36 +601,54 @@
|
||||
}
|
||||
|
||||
&.media-search {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
|
||||
> * {
|
||||
position: relative;
|
||||
display: table;
|
||||
float: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
height: 3rem;
|
||||
|
||||
> span {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: transparent;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
width: 178px;
|
||||
max-width: 178px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
font-weight: 500;
|
||||
border-width: 0 0 2px;
|
||||
border-color: var(--profile-page-nav-link-text-color);
|
||||
background-color: transparent;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
box-shadow: none;
|
||||
font-size: 14px;
|
||||
color: var(--profile-page-nav-link-text-color);
|
||||
|
||||
&::placeholder {
|
||||
color: var(--profile-page-nav-link-text-color);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-bottom-color: var(--profile-page-nav-link-active-after-bg-color);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,7 +662,7 @@
|
||||
}
|
||||
|
||||
.profile-nav {
|
||||
z-index: +2;
|
||||
z-index: 3;
|
||||
position: fixed;
|
||||
top: var(--header-height);
|
||||
left: 0;
|
||||
@@ -480,6 +688,8 @@
|
||||
#page-profile-media &,
|
||||
#page-profile-about &,
|
||||
#page-profile-playlists &,
|
||||
#page-profile-shared-by-me &,
|
||||
#page-profile-shared-with-me &,
|
||||
#page-liked.profile-page-liked &,
|
||||
#page-history.profile-page-history & {
|
||||
padding-bottom: 0;
|
||||
|
||||
@@ -5,7 +5,6 @@ import { LinksContext, MemberContext, SiteContext } from '../../utils/contexts/'
|
||||
import { PageStore, ProfilePageStore } from '../../utils/stores/';
|
||||
import { PageActions, ProfilePageActions } from '../../utils/actions/';
|
||||
import { CircleIconButton, PopupMain } from '../_shared';
|
||||
import ItemsInlineSlider from '../item-list/includes/itemLists/ItemsInlineSlider';
|
||||
import { translateString } from '../../utils/helpers/';
|
||||
|
||||
class ProfileSearchBar extends React.PureComponent {
|
||||
@@ -26,6 +25,7 @@ class ProfileSearchBar extends React.PureComponent {
|
||||
|
||||
this.updateTimeout = null;
|
||||
this.pendingUpdate = false;
|
||||
this.justShown = false;
|
||||
}
|
||||
|
||||
updateQuery(value) {
|
||||
@@ -45,10 +45,11 @@ class ProfileSearchBar extends React.PureComponent {
|
||||
|
||||
onChange(ev) {
|
||||
this.pendingEvent = ev;
|
||||
const newValue = ev.target.value || '';
|
||||
|
||||
this.setState(
|
||||
{
|
||||
queryVal: ev.target.value || '',
|
||||
queryVal: newValue,
|
||||
},
|
||||
function () {
|
||||
if (this.updateTimeout) {
|
||||
@@ -57,8 +58,11 @@ class ProfileSearchBar extends React.PureComponent {
|
||||
|
||||
this.pendingEvent = null;
|
||||
|
||||
// Only trigger search if 3+ characters or empty (to reset)
|
||||
if ('function' === typeof this.props.onQueryChange) {
|
||||
this.props.onQueryChange(this.state.queryVal);
|
||||
if (newValue.length >= 3 || newValue.length === 0) {
|
||||
this.props.onQueryChange(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
this.updateTimeout = setTimeout(
|
||||
@@ -100,10 +104,15 @@ class ProfileSearchBar extends React.PureComponent {
|
||||
}
|
||||
|
||||
onInputBlur() {
|
||||
// Don't hide immediately after showing to prevent race condition
|
||||
if (this.justShown) {
|
||||
return;
|
||||
}
|
||||
this.hideForm();
|
||||
}
|
||||
|
||||
showForm() {
|
||||
this.justShown = true;
|
||||
this.setState(
|
||||
{
|
||||
visibleForm: true,
|
||||
@@ -112,6 +121,10 @@ class ProfileSearchBar extends React.PureComponent {
|
||||
if ('function' === typeof this.props.toggleSearchField) {
|
||||
this.props.toggleSearchField();
|
||||
}
|
||||
// Reset the flag after a short delay
|
||||
setTimeout(() => {
|
||||
this.justShown = false;
|
||||
}, 200);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -137,24 +150,56 @@ class ProfileSearchBar extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const hasSearchText = this.state.queryVal && this.state.queryVal.length > 0;
|
||||
|
||||
// Determine the correct action URL based on page type
|
||||
let actionUrl = LinksContext._currentValue.profile.media;
|
||||
if (this.props.type === 'shared_by_me') {
|
||||
actionUrl = LinksContext._currentValue.profile.shared_by_me;
|
||||
} else if (this.props.type === 'shared_with_me') {
|
||||
actionUrl = LinksContext._currentValue.profile.shared_with_me;
|
||||
}
|
||||
|
||||
if (!this.state.visibleForm) {
|
||||
return (
|
||||
<div>
|
||||
<span>
|
||||
<CircleIconButton buttonShadow={false} onClick={this.showForm}>
|
||||
<i className="material-icons">search</i>
|
||||
</CircleIconButton>
|
||||
</span>
|
||||
</div>
|
||||
<span style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', position: 'relative' }} onClick={this.showForm}>
|
||||
<CircleIconButton buttonShadow={false}>
|
||||
<i className="material-icons">search</i>
|
||||
</CircleIconButton>
|
||||
{hasSearchText ? (
|
||||
<span style={{
|
||||
position: 'absolute',
|
||||
top: '8px',
|
||||
right: '8px',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'var(--default-theme-color)',
|
||||
border: '2px solid white',
|
||||
}}></span>
|
||||
) : null}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<form method="get" action={LinksContext._currentValue.profile.media} onSubmit={this.onFormSubmit}>
|
||||
<span>
|
||||
<form method="get" action={actionUrl} onSubmit={this.onFormSubmit}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', position: 'relative' }}>
|
||||
<CircleIconButton buttonShadow={false}>
|
||||
<i className="material-icons">search</i>
|
||||
</CircleIconButton>
|
||||
{hasSearchText ? (
|
||||
<span style={{
|
||||
position: 'absolute',
|
||||
top: '8px',
|
||||
right: '8px',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'var(--default-theme-color)',
|
||||
border: '2px solid white',
|
||||
}}></span>
|
||||
) : null}
|
||||
</span>
|
||||
<span>
|
||||
<input
|
||||
@@ -177,6 +222,7 @@ class ProfileSearchBar extends React.PureComponent {
|
||||
|
||||
ProfileSearchBar.propTypes = {
|
||||
onQueryChange: PropTypes.func,
|
||||
type: PropTypes.string,
|
||||
};
|
||||
|
||||
ProfileSearchBar.defaultProps = {};
|
||||
@@ -207,12 +253,11 @@ class NavMenuInlineTabs extends React.PureComponent {
|
||||
displayPrev: false,
|
||||
};
|
||||
|
||||
this.inlineSlider = null;
|
||||
|
||||
this.nextSlide = this.nextSlide.bind(this);
|
||||
this.prevSlide = this.prevSlide.bind(this);
|
||||
|
||||
this.updateSlider = this.updateSlider.bind(this, false);
|
||||
this.updateSlider = this.updateSlider.bind(this);
|
||||
this.updateSliderButtonsView = this.updateSliderButtonsView.bind(this);
|
||||
|
||||
this.onToggleSearchField = this.onToggleSearchField.bind(this);
|
||||
|
||||
@@ -266,44 +311,57 @@ class NavMenuInlineTabs extends React.PureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
this.updateSlider();
|
||||
if (this.refs.itemsListWrap) {
|
||||
this.refs.itemsListWrap.addEventListener('scroll', this.updateSliderButtonsView.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.refs.itemsListWrap) {
|
||||
this.refs.itemsListWrap.removeEventListener('scroll', this.updateSliderButtonsView.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
nextSlide() {
|
||||
this.inlineSlider.nextSlide();
|
||||
this.updateSliderButtonsView();
|
||||
this.inlineSlider.scrollToCurrentSlide();
|
||||
if (!this.refs.itemsListWrap) return;
|
||||
const scrollAmount = this.refs.itemsListWrap.offsetWidth * 0.7; // Scroll 70% of visible width
|
||||
this.refs.itemsListWrap.scrollLeft += scrollAmount;
|
||||
setTimeout(() => this.updateSliderButtonsView(), 50);
|
||||
}
|
||||
|
||||
prevSlide() {
|
||||
this.inlineSlider.previousSlide();
|
||||
this.updateSliderButtonsView();
|
||||
this.inlineSlider.scrollToCurrentSlide();
|
||||
if (!this.refs.itemsListWrap) return;
|
||||
const scrollAmount = this.refs.itemsListWrap.offsetWidth * 0.7; // Scroll 70% of visible width
|
||||
this.refs.itemsListWrap.scrollLeft -= scrollAmount;
|
||||
setTimeout(() => this.updateSliderButtonsView(), 50);
|
||||
}
|
||||
|
||||
updateSlider(afterItemsUpdate) {
|
||||
if (!this.inlineSlider) {
|
||||
this.inlineSlider = new ItemsInlineSlider(this.refs.itemsListWrap, '.profile-nav ul li');
|
||||
}
|
||||
|
||||
this.inlineSlider.updateDataState(document.querySelectorAll('.profile-nav ul li').length, true, !afterItemsUpdate);
|
||||
|
||||
this.updateSliderButtonsView();
|
||||
|
||||
if (this.pendingChangeSlide) {
|
||||
this.pendingChangeSlide = false;
|
||||
this.inlineSlider.scrollToCurrentSlide();
|
||||
}
|
||||
}
|
||||
|
||||
updateSliderButtonsView() {
|
||||
if (!this.refs.itemsListWrap) return;
|
||||
|
||||
const container = this.refs.itemsListWrap;
|
||||
const scrollLeft = container.scrollLeft;
|
||||
const scrollWidth = container.scrollWidth;
|
||||
const clientWidth = container.clientWidth;
|
||||
|
||||
// Show prev arrow if we can scroll left
|
||||
const canScrollLeft = scrollLeft > 1;
|
||||
|
||||
// Show next arrow if we can scroll right
|
||||
const canScrollRight = scrollLeft < scrollWidth - clientWidth - 1;
|
||||
|
||||
this.setState({
|
||||
displayPrev: this.inlineSlider.hasPreviousSlide(),
|
||||
displayNext: this.inlineSlider.hasNextSlide(),
|
||||
displayPrev: canScrollLeft,
|
||||
displayNext: canScrollRight,
|
||||
});
|
||||
}
|
||||
|
||||
onToggleSearchField() {
|
||||
this.updateSlider();
|
||||
setTimeout(() => this.updateSlider(), 100);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -322,9 +380,25 @@ class NavMenuInlineTabs extends React.PureComponent {
|
||||
<InlineTab
|
||||
id="media"
|
||||
isActive={'media' === this.props.type}
|
||||
label={translateString('Media')}
|
||||
label={translateString(this.userIsAuthor ? 'Media I own' : 'Media')}
|
||||
link={LinksContext._currentValue.profile.media}
|
||||
/>
|
||||
{this.userIsAuthor ? (
|
||||
<InlineTab
|
||||
id="shared_by_me"
|
||||
isActive={'shared_by_me' === this.props.type}
|
||||
label={translateString('Shared by me')}
|
||||
link={LinksContext._currentValue.profile.shared_by_me}
|
||||
/>
|
||||
) : null}
|
||||
{this.userIsAuthor ? (
|
||||
<InlineTab
|
||||
id="shared_with_me"
|
||||
isActive={'shared_with_me' === this.props.type}
|
||||
label={translateString('Shared with me')}
|
||||
link={LinksContext._currentValue.profile.shared_with_me}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{MemberContext._currentValue.can.saveMedia ? (
|
||||
<InlineTab
|
||||
@@ -351,9 +425,74 @@ class NavMenuInlineTabs extends React.PureComponent {
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<li className="media-search">
|
||||
<ProfileSearchBar onQueryChange={this.props.onQueryChange} toggleSearchField={this.onToggleSearchField} />
|
||||
</li>
|
||||
{!['about', 'playlists'].includes(this.props.type) ? (
|
||||
<li className="media-search">
|
||||
<ProfileSearchBar onQueryChange={this.props.onQueryChange} toggleSearchField={this.onToggleSearchField} type={this.props.type} />
|
||||
</li>
|
||||
) : null}
|
||||
{this.props.onToggleFiltersClick && ['media', 'shared_by_me', 'shared_with_me'].includes(this.props.type) ? (
|
||||
<li className="media-filters-toggle">
|
||||
<span style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', position: 'relative' }} onClick={this.props.onToggleFiltersClick} title={translateString('Filters')}>
|
||||
<CircleIconButton buttonShadow={false}>
|
||||
<i className="material-icons">filter_list</i>
|
||||
</CircleIconButton>
|
||||
{this.props.hasActiveFilters ? (
|
||||
<span style={{
|
||||
position: 'absolute',
|
||||
top: '8px',
|
||||
right: '8px',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'var(--default-theme-color)',
|
||||
border: '2px solid white',
|
||||
}}></span>
|
||||
) : null}
|
||||
</span>
|
||||
</li>
|
||||
) : null}
|
||||
{this.props.onToggleTagsClick && ['media', 'shared_by_me', 'shared_with_me'].includes(this.props.type) ? (
|
||||
<li className="media-tags-toggle">
|
||||
<span style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', position: 'relative' }} onClick={this.props.onToggleTagsClick} title={translateString('Tags')}>
|
||||
<CircleIconButton buttonShadow={false}>
|
||||
<i className="material-icons">local_offer</i>
|
||||
</CircleIconButton>
|
||||
{this.props.hasActiveTags ? (
|
||||
<span style={{
|
||||
position: 'absolute',
|
||||
top: '8px',
|
||||
right: '8px',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'var(--default-theme-color)',
|
||||
border: '2px solid white',
|
||||
}}></span>
|
||||
) : null}
|
||||
</span>
|
||||
</li>
|
||||
) : null}
|
||||
{this.props.onToggleSortingClick && ['media', 'shared_by_me', 'shared_with_me'].includes(this.props.type) ? (
|
||||
<li className="media-sorting-toggle">
|
||||
<span style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', position: 'relative' }} onClick={this.props.onToggleSortingClick} title={translateString('Sort By')}>
|
||||
<CircleIconButton buttonShadow={false}>
|
||||
<i className="material-icons">swap_vert</i>
|
||||
</CircleIconButton>
|
||||
{this.props.hasActiveSort ? (
|
||||
<span style={{
|
||||
position: 'absolute',
|
||||
top: '8px',
|
||||
right: '8px',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'var(--default-theme-color)',
|
||||
border: '2px solid white',
|
||||
}}></span>
|
||||
) : null}
|
||||
</span>
|
||||
</li>
|
||||
) : null}
|
||||
</ul>
|
||||
|
||||
{this.state.displayNext ? this.nextBtn : null}
|
||||
@@ -366,6 +505,12 @@ class NavMenuInlineTabs extends React.PureComponent {
|
||||
NavMenuInlineTabs.propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
onQueryChange: PropTypes.func,
|
||||
onToggleFiltersClick: PropTypes.func,
|
||||
onToggleTagsClick: PropTypes.func,
|
||||
onToggleSortingClick: PropTypes.func,
|
||||
hasActiveFilters: PropTypes.bool,
|
||||
hasActiveTags: PropTypes.bool,
|
||||
hasActiveSort: PropTypes.bool,
|
||||
};
|
||||
|
||||
function AddBannerButton(props) {
|
||||
@@ -375,8 +520,8 @@ function AddBannerButton(props) {
|
||||
link = '/edit-channel.html';
|
||||
}
|
||||
return (
|
||||
<a href={link} className="edit-channel" title="Add banner">
|
||||
ADD BANNER
|
||||
<a href={link} className="edit-channel-icon" title="Add banner">
|
||||
<i className="material-icons">add_photo_alternate</i>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -388,8 +533,8 @@ function EditBannerButton(props) {
|
||||
link = '/edit-channel.html';
|
||||
}
|
||||
return (
|
||||
<a href={link} className="edit-channel" title="Edit banner">
|
||||
EDIT BANNER
|
||||
<a href={link} className="edit-channel-icon" title="Edit banner">
|
||||
<i className="material-icons">edit</i>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -402,8 +547,8 @@ function EditProfileButton(props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<a href={link} className="edit-profile" title="Edit profile">
|
||||
EDIT PROFILE
|
||||
<a href={link} className="edit-profile-icon" title="Edit profile">
|
||||
<i className="material-icons">edit</i>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -528,11 +673,11 @@ export default function ProfilePagesHeader(props) {
|
||||
></span>
|
||||
) : null}
|
||||
|
||||
{userCanDeleteProfile ? (
|
||||
{userCanDeleteProfile && !userIsAuthor ? (
|
||||
<span className="delete-profile-wrap">
|
||||
<PopupTrigger contentRef={popupContentRef}>
|
||||
<button className="delete-profile" title="">
|
||||
REMOVE PROFILE
|
||||
<button className="delete-profile" title="Remove profile">
|
||||
<i className="material-icons">delete</i>
|
||||
</button>
|
||||
</PopupTrigger>
|
||||
|
||||
@@ -556,7 +701,7 @@ export default function ProfilePagesHeader(props) {
|
||||
</span>
|
||||
) : null}
|
||||
|
||||
{userCanEditProfile ? (
|
||||
{userCanEditProfile && userIsAuthor ? (
|
||||
props.author.banner_thumbnail_url ? (
|
||||
<EditBannerButton link={ProfilePageStore.get('author-data').default_channel_edit_url} />
|
||||
) : (
|
||||
@@ -571,14 +716,28 @@ export default function ProfilePagesHeader(props) {
|
||||
<div className="profile-info-inner">
|
||||
<div>{props.author.thumbnail_url ? <img src={props.author.thumbnail_url} alt="" /> : null}</div>
|
||||
<div>
|
||||
{props.author.name ? <h1>{props.author.name}</h1> : null}
|
||||
{userCanEditProfile ? <EditProfileButton link={ProfilePageStore.get('author-data').edit_url} /> : null}
|
||||
{props.author.name ? (
|
||||
<div className="profile-name-edit-wrapper">
|
||||
<h1>{props.author.name}</h1>
|
||||
{userCanEditProfile && !userIsAuthor ? <EditProfileButton link={ProfilePageStore.get('author-data').edit_url} /> : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<NavMenuInlineTabs ref={profileNavRef} type={props.type} onQueryChange={props.onQueryChange} />
|
||||
<NavMenuInlineTabs
|
||||
ref={profileNavRef}
|
||||
type={props.type}
|
||||
onQueryChange={props.onQueryChange}
|
||||
onToggleFiltersClick={props.onToggleFiltersClick}
|
||||
onToggleTagsClick={props.onToggleTagsClick}
|
||||
onToggleSortingClick={props.onToggleSortingClick}
|
||||
hasActiveFilters={props.hasActiveFilters}
|
||||
hasActiveTags={props.hasActiveTags}
|
||||
hasActiveSort={props.hasActiveSort}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -588,6 +747,12 @@ ProfilePagesHeader.propTypes = {
|
||||
author: PropTypes.object.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
onQueryChange: PropTypes.func,
|
||||
onToggleFiltersClick: PropTypes.func,
|
||||
onToggleTagsClick: PropTypes.func,
|
||||
onToggleSortingClick: PropTypes.func,
|
||||
hasActiveFilters: PropTypes.bool,
|
||||
hasActiveTags: PropTypes.bool,
|
||||
hasActiveSort: PropTypes.bool,
|
||||
};
|
||||
|
||||
ProfilePagesHeader.defaultProps = {
|
||||
|
||||
Reference in New Issue
Block a user