feat: Implement persistent "Embed Mode" to hide UI shell via Session Storage (#1484)

* initial implementation

* updates in ViewerInfoVideoTitleBanner component

* Implement persistent "Embed Mode" to hide UI shell via Session Storage

---------

Co-authored-by: Yiannis <1515939+styiannis@users.noreply.github.com>
This commit is contained in:
Markos Gogoulos
2026-01-31 15:27:40 +02:00
committed by GitHub
parent 1c15880ae3
commit 223e87073f
50 changed files with 5116 additions and 4798 deletions

View File

@@ -1 +1 @@
VERSION = "7.6"
VERSION = "7.7"

View File

@@ -1,6 +1,6 @@
@use "sass:math";
@import '../../../css/includes/_variables.scss';
@import '../../../css/includes/_variables_dimensions.scss';
@import "../../../css/includes/_variables.scss";
@import "../../../css/includes/_variables_dimensions.scss";
.visible-sidebar .page-main-wrap {
padding-left: 0;
@@ -119,7 +119,7 @@
background-color: var(--media-actions-share-copy-field-bg-color);
}
input[type='text'] {
input[type="text"] {
color: var(--media-actions-share-copy-field-input-text-color);
}
}
@@ -180,7 +180,7 @@
color: var(--report-form-field-label-text-color);
}
input[type='text'],
input[type="text"],
textarea {
color: var(--report-form-field-input-text-color);
border-color: var(--report-form-field-input-border-color);
@@ -479,7 +479,7 @@
&.audio-player-container {
&:before {
content: '\E3A1';
content: "\E3A1";
position: absolute;
top: 50%;
left: 50%;
@@ -490,12 +490,11 @@
line-height: 1;
padding: 0;
font-family: 'Material Icons';
font-family: "Material Icons";
text-decoration: none;
color: #888;
}
.vjs-big-play-button {
}
@@ -514,6 +513,13 @@
}
}
.embedded-app {
.viewer-container,
.viewer-info {
width: 100%;
}
}
.viewer-image-container {
position: relative;
display: block;
@@ -550,8 +556,6 @@
max-width: 90%;
}
.slideshow-image img {
display: block;
width: auto;
@@ -560,7 +564,9 @@
max-height: 90vh;
border-radius: 0;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
transition: transform 60s ease-in-out, opacity 60 ease-in-out;
transition:
transform 60s ease-in-out,
opacity 60 ease-in-out;
}
.slideshow-title {
@@ -572,7 +578,6 @@
z-index: 1200;
}
.arrow {
position: absolute;
display: flex;
@@ -590,7 +595,9 @@
padding: 10px;
border-radius: 50%;
z-index: 1000;
transition: background-color 0.2s ease, transform 0.2s ease;
transition:
background-color 0.2s ease,
transform 0.2s ease;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
}
@@ -685,18 +692,19 @@
width: 100%; // Default width for mobile
height: 400px; // Default height for mobile
@media (min-width: 768px) and (max-width: 1023px) { // Tablets
@media (min-width: 768px) and (max-width: 1023px) {
// Tablets
width: 90%;
height: 600px;
}
@media (min-width: 1024px) { // Desktop
@media (min-width: 1024px) {
// Desktop
width: 85%;
height: 900px;
}
}
.viewer-container .player-container.viewer-pdf-container,
.viewer-container .player-container.viewer-attachment-container {
background-color: var(--item-thumb-bg-color);
@@ -1006,7 +1014,7 @@
&.like,
&.dislike {
&:before {
content: '';
content: "";
position: absolute;
bottom: 0;
left: -4px;
@@ -1146,7 +1154,7 @@
border-radius: 2px;
}
input[type='text'] {
input[type="text"] {
width: 100%;
height: 42px;
padding: 1px 0 1px 16px;
@@ -1206,13 +1214,18 @@
width: 220px;
}
box-shadow: 0 16px 24px 2px rgba(#000, 0.14), 0 6px 30px 5px rgba(#000, 0.12),
box-shadow:
0 16px 24px 2px rgba(#000, 0.14),
0 6px 30px 5px rgba(#000, 0.12),
0 8px 10px -5px rgba(#000, 0.4);
&.main-options,
&.video-download-options {
width: 240px;
box-shadow: 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12), 0 3px 1px -2px rgba(#000, 0.2);
box-shadow:
0 2px 2px 0 rgba(#000, 0.14),
0 1px 5px 0 rgba(#000, 0.12),
0 3px 1px -2px rgba(#000, 0.2);
}
}
}
@@ -1270,7 +1283,9 @@
padding: 24px;
text-align: initial;
box-shadow: rgba(#000, 0.14) 0px 16px 24px 2px, rgba(#000, 0.12) 0px 6px 30px 5px,
box-shadow:
rgba(#000, 0.14) 0px 16px 24px 2px,
rgba(#000, 0.12) 0px 6px 30px 5px,
rgba(#000, 0.4) 0px 8px 10px;
}
}
@@ -1303,13 +1318,18 @@
width: 220px;
}
box-shadow: 0 16px 24px 2px rgba(#000, 0.14), 0 6px 30px 5px rgba(#000, 0.12),
box-shadow:
0 16px 24px 2px rgba(#000, 0.14),
0 6px 30px 5px rgba(#000, 0.12),
0 8px 10px -5px rgba(#000, 0.4);
&.main-options,
&.video-download-options {
width: 240px;
box-shadow: 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12), 0 3px 1px -2px rgba(#000, 0.2);
box-shadow:
0 2px 2px 0 rgba(#000, 0.14),
0 1px 5px 0 rgba(#000, 0.12),
0 3px 1px -2px rgba(#000, 0.2);
.popup-main {
min-height: 0;
@@ -1412,7 +1432,7 @@
font-weight: 500;
}
input[type='text'],
input[type="text"],
textarea {
min-width: 100%;
width: 100%;
@@ -1435,7 +1455,7 @@
cursor: not-allowed;
}
input[type='text'] {
input[type="text"] {
font-size: 14px;
}
@@ -1732,7 +1752,7 @@
border-width: 0 0 1px;
&:after {
content: '';
content: "";
position: absolute;
bottom: -5px;
right: 0;
@@ -1788,7 +1808,7 @@
max-height: 100%;
padding: 16px;
cursor: text;
font-family: 'Roboto Mono', monospace;
font-family: "Roboto Mono", monospace;
font-size: 14px;
line-height: 1.714285714;
outline: 0;
@@ -1822,7 +1842,7 @@
vertical-align: top;
input {
&[type='checkbox'] {
&[type="checkbox"] {
margin-left: 0;
}
}
@@ -1834,7 +1854,7 @@
width: 100%;
input {
&[type='checkbox'] {
&[type="checkbox"] {
margin-left: 0;
}
}
@@ -1979,8 +1999,8 @@
}
.item-date:before {
content: '';
content: '\2022';
content: "";
content: "\2022";
margin: 0 4px;
}
@@ -2017,14 +2037,14 @@
margin-right: 4px;
&:after {
content: ',';
content: ",";
}
&:last-child {
margin-right: 0;
&:after {
content: '';
content: "";
}
}
}

View File

@@ -3,7 +3,7 @@ import { SiteContext } from '../../utils/contexts/';
import { useUser, usePopup } from '../../utils/hooks/';
import { PageStore, MediaPageStore } from '../../utils/stores/';
import { PageActions, MediaPageActions } from '../../utils/actions/';
import { formatInnerLink, publishedOnDate } from '../../utils/helpers/';
import { formatInnerLink, inEmbeddedApp, publishedOnDate } from '../../utils/helpers/';
import { PopupMain } from '../_shared/';
import CommentsList from '../comments/Comments';
import { replaceString } from '../../utils/helpers/';
@@ -125,7 +125,9 @@ export default function ViewerInfoContent(props) {
PageActions.addNotification('Media removed. Redirecting...', 'mediaDelete');
setTimeout(function () {
window.location.href =
SiteContext._currentValue.url + '/' + MediaPageStore.get('media-data').author_profile.replace(/^\//g, '');
SiteContext._currentValue.url +
'/' +
MediaPageStore.get('media-data').author_profile.replace(/^\//g, '');
}, 2000);
}, 100);
@@ -185,7 +187,12 @@ export default function ViewerInfoContent(props) {
{void 0 === PageStore.get('config-media-item').displayAuthor ||
null === PageStore.get('config-media-item').displayAuthor ||
!!PageStore.get('config-media-item').displayAuthor ? (
<MediaAuthorBanner link={authorLink} thumb={authorThumb} name={props.author.name} published={props.published} />
<MediaAuthorBanner
link={authorLink}
thumb={authorThumb}
name={props.author.name}
published={props.published}
/>
) : null}
<div className="media-content-banner">
@@ -212,14 +219,20 @@ export default function ViewerInfoContent(props) {
{categoriesContent.length ? (
<MediaMetaField
value={categoriesContent}
title={1 < categoriesContent.length ? translateString('Categories') : translateString('Category')}
title={
1 < categoriesContent.length
? translateString('Categories')
: translateString('Category')
}
id="categories"
/>
) : null}
{userCan.editMedia ? (
<div className="media-author-actions">
{userCan.editMedia ? <EditMediaButton link={MediaPageStore.get('media-data').edit_url} /> : null}
{userCan.editMedia ? (
<EditMediaButton link={MediaPageStore.get('media-data').edit_url} />
) : null}
{userCan.deleteMedia ? (
<PopupTrigger contentRef={popupContentRef}>
@@ -234,14 +247,22 @@ export default function ViewerInfoContent(props) {
<PopupMain>
<div className="popup-message">
<span className="popup-message-title">Media removal</span>
<span className="popup-message-main">You're willing to remove media permanently?</span>
<span className="popup-message-main">
You're willing to remove media permanently?
</span>
</div>
<hr />
<span className="popup-message-bottom">
<button className="button-link cancel-comment-removal" onClick={cancelMediaRemoval}>
<button
className="button-link cancel-comment-removal"
onClick={cancelMediaRemoval}
>
CANCEL
</button>
<button className="button-link proceed-comment-removal" onClick={proceedMediaRemoval}>
<button
className="button-link proceed-comment-removal"
onClick={proceedMediaRemoval}
>
PROCEED
</button>
</span>
@@ -253,7 +274,7 @@ export default function ViewerInfoContent(props) {
</div>
</div>
<CommentsList />
{!inEmbeddedApp() && <CommentsList />}
</div>
);
}

View File

@@ -1,8 +1,16 @@
import React from 'react';
import { formatViewsNumber } from '../../utils/helpers/';
import { formatViewsNumber, inEmbeddedApp } from '../../utils/helpers/';
import { PageStore, MediaPageStore } from '../../utils/stores/';
import { MemberContext, PlaylistsContext } from '../../utils/contexts/';
import { MediaLikeIcon, MediaDislikeIcon, OtherMediaDownloadLink, VideoMediaDownloadLink, MediaSaveButton, MediaShareButton, MediaMoreOptionsIcon } from '../media-actions/';
import {
MediaLikeIcon,
MediaDislikeIcon,
OtherMediaDownloadLink,
VideoMediaDownloadLink,
MediaSaveButton,
MediaShareButton,
MediaMoreOptionsIcon,
} from '../media-actions/';
import ViewerInfoTitleBanner from './ViewerInfoTitleBanner';
import { translateString } from '../../utils/helpers/';
@@ -74,7 +82,8 @@ export default class ViewerInfoVideoTitleBanner extends ViewerInfoTitleBanner {
{displayViews ? (
<div className="media-views">
{formatViewsNumber(this.props.views, true)} {1 >= this.props.views ? translateString('view') : translateString('views')}
{formatViewsNumber(this.props.views, true)}{' '}
{1 >= this.props.views ? translateString('view') : translateString('views')}
</div>
) : null}
@@ -82,9 +91,12 @@ export default class ViewerInfoVideoTitleBanner extends ViewerInfoTitleBanner {
<div>
{MemberContext._currentValue.can.likeMedia ? <MediaLikeIcon /> : null}
{MemberContext._currentValue.can.dislikeMedia ? <MediaDislikeIcon /> : null}
{MemberContext._currentValue.can.shareMedia ? <MediaShareButton isVideo={true} /> : null}
{!inEmbeddedApp() && MemberContext._currentValue.can.shareMedia ? (
<MediaShareButton isVideo={true} />
) : null}
{!MemberContext._currentValue.is.anonymous &&
{!inEmbeddedApp() &&
!MemberContext._currentValue.is.anonymous &&
MemberContext._currentValue.can.saveMedia &&
-1 < PlaylistsContext._currentValue.mediaTypes.indexOf(MediaPageStore.get('media-type')) ? (
<MediaSaveButton />

View File

@@ -23,6 +23,11 @@
transition-property: padding-left;
transition-duration: 0.2s;
}
.embedded-app & {
padding-top: 0;
padding-left: 0;
}
}
#page-profile-media,

View File

@@ -162,12 +162,16 @@ class ProfileSearchBar extends React.PureComponent {
if (!this.state.visibleForm) {
return (
<span style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', position: 'relative' }} onClick={this.showForm}>
<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={{
<span
style={{
position: 'absolute',
top: '8px',
right: '8px',
@@ -176,7 +180,8 @@ class ProfileSearchBar extends React.PureComponent {
borderRadius: '50%',
backgroundColor: 'var(--default-theme-color)',
border: '2px solid white',
}}></span>
}}
></span>
) : null}
</span>
);
@@ -189,7 +194,8 @@ class ProfileSearchBar extends React.PureComponent {
<i className="material-icons">search</i>
</CircleIconButton>
{hasSearchText ? (
<span style={{
<span
style={{
position: 'absolute',
top: '8px',
right: '8px',
@@ -198,7 +204,8 @@ class ProfileSearchBar extends React.PureComponent {
borderRadius: '50%',
backgroundColor: 'var(--default-theme-color)',
border: '2px solid white',
}}></span>
}}
></span>
) : null}
</span>
<span>
@@ -427,17 +434,32 @@ class NavMenuInlineTabs extends React.PureComponent {
{!['about', 'playlists'].includes(this.props.type) ? (
<li className="media-search">
<ProfileSearchBar onQueryChange={this.props.onQueryChange} toggleSearchField={this.onToggleSearchField} type={this.props.type} />
<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) ? (
{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')}>
<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={{
<span
style={{
position: 'absolute',
top: '8px',
right: '8px',
@@ -446,19 +468,31 @@ class NavMenuInlineTabs extends React.PureComponent {
borderRadius: '50%',
backgroundColor: 'var(--default-theme-color)',
border: '2px solid white',
}}></span>
}}
></span>
) : null}
</span>
</li>
) : null}
{this.props.onToggleTagsClick && ['media', 'shared_by_me', 'shared_with_me'].includes(this.props.type) ? (
{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')}>
<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={{
<span
style={{
position: 'absolute',
top: '8px',
right: '8px',
@@ -467,19 +501,31 @@ class NavMenuInlineTabs extends React.PureComponent {
borderRadius: '50%',
backgroundColor: 'var(--default-theme-color)',
border: '2px solid white',
}}></span>
}}
></span>
) : null}
</span>
</li>
) : null}
{this.props.onToggleSortingClick && ['media', 'shared_by_me', 'shared_with_me'].includes(this.props.type) ? (
{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')}>
<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={{
<span
style={{
position: 'absolute',
top: '8px',
right: '8px',
@@ -488,7 +534,8 @@ class NavMenuInlineTabs extends React.PureComponent {
borderRadius: '50%',
backgroundColor: 'var(--default-theme-color)',
border: '2px solid white',
}}></span>
}}
></span>
) : null}
</span>
</li>
@@ -658,6 +705,7 @@ export default function ProfilePagesHeader(props) {
return (
<div ref={profilePageHeaderRef} className={'profile-page-header' + (fixedNav ? ' fixed-nav' : '')}>
{!props.hideChannelBanner && (
<span className="profile-banner-wrap">
{props.author.banner_thumbnail_url ? (
<span
@@ -685,14 +733,22 @@ export default function ProfilePagesHeader(props) {
<PopupMain>
<div className="popup-message">
<span className="popup-message-title">Profile removal</span>
<span className="popup-message-main">You're willing to remove profile permanently?</span>
<span className="popup-message-main">
You're willing to remove profile permanently?
</span>
</div>
<hr />
<span className="popup-message-bottom">
<button className="button-link cancel-profile-removal" onClick={cancelProfileRemoval}>
<button
className="button-link cancel-profile-removal"
onClick={cancelProfileRemoval}
>
CANCEL
</button>
<button className="button-link proceed-profile-removal" onClick={proceedMediaRemoval}>
<button
className="button-link proceed-profile-removal"
onClick={proceedMediaRemoval}
>
PROCEED
</button>
</span>
@@ -709,17 +765,22 @@ export default function ProfilePagesHeader(props) {
)
) : null}
</span>
)}
<div className="profile-info-nav-wrap">
{props.author.thumbnail_url || props.author.name ? (
<div className="profile-info">
<div className="profile-info-inner">
<div>{props.author.thumbnail_url ? <img src={props.author.thumbnail_url} alt="" /> : null}</div>
<div>
{props.author.thumbnail_url ? <img src={props.author.thumbnail_url} alt="" /> : null}
</div>
<div>
{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}
{userCanEditProfile && !userIsAuthor ? (
<EditProfileButton link={ProfilePageStore.get('author-data').edit_url} />
) : null}
</div>
) : null}
</div>

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import UrlParse from 'url-parse';
import { ApiUrlContext, MemberContext, SiteContext } from '../utils/contexts/';
import { formatInnerLink, csrfToken, postRequest } from '../utils/helpers/';
import { formatInnerLink, csrfToken, postRequest, inEmbeddedApp } from '../utils/helpers/';
import { PageActions } from '../utils/actions/';
import { PageStore, ProfilePageStore } from '../utils/stores/';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
@@ -268,7 +268,7 @@ export class ProfileAboutPage extends ProfileMediaPage {
return [
this.state.author ? (
<ProfilePagesHeader key="ProfilePagesHeader" author={this.state.author} type="about" />
<ProfilePagesHeader key="ProfilePagesHeader" author={this.state.author} type="about" hideChannelBanner={inEmbeddedApp()} />
) : null,
this.state.author ? (
<ProfilePagesContent key="ProfilePagesContent" enabledContactForm={this.enabledContactForm}>

View File

@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { ApiUrlConsumer } from '../utils/contexts/';
import { PageStore } from '../utils/stores/';
import { inEmbeddedApp } from '../utils/helpers/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
@@ -28,7 +29,7 @@ export class ProfileHistoryPage extends ProfileMediaPage {
pageContent() {
return [
this.state.author ? (
<ProfilePagesHeader key="ProfilePagesHeader" author={this.state.author} type="history" />
<ProfilePagesHeader key="ProfilePagesHeader" author={this.state.author} type="history" hideChannelBanner={inEmbeddedApp()} />
) : null,
this.state.author ? (
<ProfilePagesContent key="ProfilePagesContent">

View File

@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { ApiUrlConsumer } from '../utils/contexts/';
import { PageStore } from '../utils/stores/';
import { inEmbeddedApp } from '../utils/helpers/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
@@ -28,7 +29,7 @@ export class ProfileLikedPage extends ProfileMediaPage {
pageContent() {
return [
this.state.author ? (
<ProfilePagesHeader key="ProfilePagesHeader" author={this.state.author} type="liked" />
<ProfilePagesHeader key="ProfilePagesHeader" author={this.state.author} type="liked" hideChannelBanner={inEmbeddedApp()} />
) : null,
this.state.author ? (
<ProfilePagesContent key="ProfilePagesContent">

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { ApiUrlContext, LinksConsumer, MemberContext } from '../utils/contexts';
import { PageStore, ProfilePageStore } from '../utils/stores';
import { ProfilePageActions, PageActions } from '../utils/actions';
import { translateString } from '../utils/helpers/';
import { inEmbeddedApp, translateString } from '../utils/helpers/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
@@ -120,7 +120,13 @@ export class ProfileMediaPage extends Page {
if (author) {
if (this.state.query) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
author.id +
'&q=' +
encodeURIComponent(this.state.query) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + this.state.filterArgs;
}
@@ -171,7 +177,13 @@ export class ProfileMediaPage extends Page {
let requestUrl;
if (newQuery) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&q=' + encodeURIComponent(newQuery) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&q=' +
encodeURIComponent(newQuery) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + this.state.filterArgs;
}
@@ -212,37 +224,55 @@ export class ProfileMediaPage extends Page {
this.setState({
showConfirmModal: true,
pendingAction: action,
confirmMessage: translateString('You are going to delete') + ` ${selectedCount} ` + translateString('media, are you sure?'),
confirmMessage:
translateString('You are going to delete') +
` ${selectedCount} ` +
translateString('media, are you sure?'),
});
} else if (action === 'enable-comments') {
this.setState({
showConfirmModal: true,
pendingAction: action,
confirmMessage: translateString('You are going to enable comments to') + ` ${selectedCount} ` + translateString('media, are you sure?'),
confirmMessage:
translateString('You are going to enable comments to') +
` ${selectedCount} ` +
translateString('media, are you sure?'),
});
} else if (action === 'disable-comments') {
this.setState({
showConfirmModal: true,
pendingAction: action,
confirmMessage: translateString('You are going to disable comments to') + ` ${selectedCount} ` + translateString('media, are you sure?'),
confirmMessage:
translateString('You are going to disable comments to') +
` ${selectedCount} ` +
translateString('media, are you sure?'),
});
} else if (action === 'enable-download') {
this.setState({
showConfirmModal: true,
pendingAction: action,
confirmMessage: translateString('You are going to enable download for') + ` ${selectedCount} ` + translateString('media, are you sure?'),
confirmMessage:
translateString('You are going to enable download for') +
` ${selectedCount} ` +
translateString('media, are you sure?'),
});
} else if (action === 'disable-download') {
this.setState({
showConfirmModal: true,
pendingAction: action,
confirmMessage: translateString('You are going to disable download for') + ` ${selectedCount} ` + translateString('media, are you sure?'),
confirmMessage:
translateString('You are going to disable download for') +
` ${selectedCount} ` +
translateString('media, are you sure?'),
});
} else if (action === 'copy-media') {
this.setState({
showConfirmModal: true,
pendingAction: action,
confirmMessage: translateString('You are going to copy') + ` ${selectedCount} ` + translateString('media, are you sure?'),
confirmMessage:
translateString('You are going to copy') +
` ${selectedCount} ` +
translateString('media, are you sure?'),
});
} else if (action === 'add-remove-coviewers') {
this.setState({
@@ -337,7 +367,8 @@ export class ProfileMediaPage extends Page {
return response.json();
})
.then((data) => {
const message = selectedCount === 1
const message =
selectedCount === 1
? translateString('The media was deleted successfully.')
: translateString('Successfully deleted') + ` ${selectedCount} ` + translateString('media.');
this.showNotification(message);
@@ -590,10 +621,18 @@ export class ProfileMediaPage extends Page {
this.setState({ selectedTag: tag }, () => {
// Apply tag filter
this.onFiltersUpdate({
media_type: this.state.filterArgs.includes('media_type') ? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1] : null,
upload_date: this.state.filterArgs.includes('upload_date') ? this.state.filterArgs.match(/upload_date=([^&]*)/)?.[1] : null,
duration: this.state.filterArgs.includes('duration') ? this.state.filterArgs.match(/duration=([^&]*)/)?.[1] : null,
publish_state: this.state.filterArgs.includes('publish_state') ? this.state.filterArgs.match(/publish_state=([^&]*)/)?.[1] : null,
media_type: this.state.filterArgs.includes('media_type')
? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1]
: null,
upload_date: this.state.filterArgs.includes('upload_date')
? this.state.filterArgs.match(/upload_date=([^&]*)/)?.[1]
: null,
duration: this.state.filterArgs.includes('duration')
? this.state.filterArgs.match(/duration=([^&]*)/)?.[1]
: null,
publish_state: this.state.filterArgs.includes('publish_state')
? this.state.filterArgs.match(/publish_state=([^&]*)/)?.[1]
: null,
sort_by: this.state.selectedSort,
tag: tag,
});
@@ -604,10 +643,18 @@ export class ProfileMediaPage extends Page {
this.setState({ selectedSort: sortOption }, () => {
// Apply sort filter
this.onFiltersUpdate({
media_type: this.state.filterArgs.includes('media_type') ? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1] : null,
upload_date: this.state.filterArgs.includes('upload_date') ? this.state.filterArgs.match(/upload_date=([^&]*)/)?.[1] : null,
duration: this.state.filterArgs.includes('duration') ? this.state.filterArgs.match(/duration=([^&]*)/)?.[1] : null,
publish_state: this.state.filterArgs.includes('publish_state') ? this.state.filterArgs.match(/publish_state=([^&]*)/)?.[1] : null,
media_type: this.state.filterArgs.includes('media_type')
? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1]
: null,
upload_date: this.state.filterArgs.includes('upload_date')
? this.state.filterArgs.match(/upload_date=([^&]*)/)?.[1]
: null,
duration: this.state.filterArgs.includes('duration')
? this.state.filterArgs.match(/duration=([^&]*)/)?.[1]
: null,
publish_state: this.state.filterArgs.includes('publish_state')
? this.state.filterArgs.match(/publish_state=([^&]*)/)?.[1]
: null,
sort_by: sortOption,
tag: this.state.selectedTag,
});
@@ -707,9 +754,16 @@ export class ProfileMediaPage extends Page {
let requestUrl;
if (this.state.query) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&q=' +
encodeURIComponent(this.state.query) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + this.state.filterArgs;
}
this.setState({
@@ -851,7 +905,10 @@ export class ProfileMediaPage extends Page {
onResponseDataLoaded(responseData) {
// Extract tags from response
if (responseData && responseData.tags) {
const tags = responseData.tags.split(',').map((tag) => tag.trim()).filter((tag) => tag);
const tags = responseData.tags
.split(',')
.map((tag) => tag.trim())
.filter((tag) => tag);
this.setState({ availableTags: tags });
}
}
@@ -862,12 +919,12 @@ export class ProfileMediaPage extends Page {
const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
// Check if any filters are active (excluding default sort and tags)
const hasActiveFilters = this.state.filterArgs && (
this.state.filterArgs.includes('media_type=') ||
const hasActiveFilters =
this.state.filterArgs &&
(this.state.filterArgs.includes('media_type=') ||
this.state.filterArgs.includes('upload_date=') ||
this.state.filterArgs.includes('duration=') ||
this.state.filterArgs.includes('publish_state=')
);
this.state.filterArgs.includes('publish_state='));
const hasActiveTags = this.state.selectedTag && this.state.selectedTag !== 'all';
const hasActiveSort = this.state.selectedSort && this.state.selectedSort !== 'date_added_desc';
@@ -885,6 +942,7 @@ export class ProfileMediaPage extends Page {
hasActiveFilters={hasActiveFilters}
hasActiveTags={hasActiveTags}
hasActiveSort={hasActiveSort}
hideChannelBanner={inEmbeddedApp()}
/>
) : null,
this.state.author ? (
@@ -900,8 +958,18 @@ export class ProfileMediaPage extends Page {
onDeselectAll={this.handleDeselectAll}
showAddMediaButton={isMediaAuthor}
>
<ProfileMediaFilters hidden={this.state.hiddenFilters} tags={this.state.availableTags} onFiltersUpdate={this.onFiltersUpdate} selectedTag={this.state.selectedTag} selectedSort={this.state.selectedSort} />
<ProfileMediaTags hidden={this.state.hiddenTags} tags={this.state.availableTags} onTagSelect={this.onTagSelect} />
<ProfileMediaFilters
hidden={this.state.hiddenFilters}
tags={this.state.availableTags}
onFiltersUpdate={this.onFiltersUpdate}
selectedTag={this.state.selectedTag}
selectedSort={this.state.selectedSort}
/>
<ProfileMediaTags
hidden={this.state.hiddenTags}
tags={this.state.availableTags}
onTagSelect={this.onTagSelect}
/>
<ProfileMediaSorting hidden={this.state.hiddenSorting} onSortSelect={this.onSortSelect} />
<LazyLoadItemListAsync
key={`${this.state.requestUrl}-${this.state.listKey}`}

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { ApiUrlConsumer } from '../utils/contexts/';
import { PageStore } from '../utils/stores/';
import { inEmbeddedApp } from '../utils/helpers/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
@@ -30,7 +31,7 @@ export class ProfilePlaylistsPage extends ProfileMediaPage {
pageContent() {
return [
this.state.author ? (
<ProfilePagesHeader key="ProfilePagesHeader" author={this.state.author} type="playlists" />
<ProfilePagesHeader key="ProfilePagesHeader" author={this.state.author} type="playlists" hideChannelBanner={inEmbeddedApp()} />
) : null,
this.state.author ? (
<ProfilePagesContent key="ProfilePagesContent">

View File

@@ -11,7 +11,7 @@ import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFi
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
import { BulkActionsModals } from '../components/BulkActionsModals';
import { translateString } from '../utils/helpers';
import { inEmbeddedApp, translateString } from '../utils/helpers';
import { withBulkActions } from '../utils/hoc/withBulkActions';
import { Page } from './_Page';
@@ -24,9 +24,7 @@ function EmptySharedByMe(props) {
{(links) => (
<div className="empty-media empty-channel-media">
<div className="welcome-title">No shared media</div>
<div className="start-uploading">
Media that you have shared with others will show up here.
</div>
<div className="start-uploading">Media that you have shared with others will show up here.</div>
</div>
)}
</LinksConsumer>
@@ -81,9 +79,20 @@ class ProfileSharedByMePage extends Page {
if (author) {
if (this.state.query) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&show=shared_by_me&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
author.id +
'&show=shared_by_me&q=' +
encodeURIComponent(this.state.query) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&show=shared_by_me' + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
author.id +
'&show=shared_by_me' +
this.state.filterArgs;
}
}
@@ -132,9 +141,20 @@ class ProfileSharedByMePage extends Page {
let requestUrl;
if (newQuery) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_by_me&q=' + encodeURIComponent(newQuery) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&show=shared_by_me&q=' +
encodeURIComponent(newQuery) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_by_me' + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&show=shared_by_me' +
this.state.filterArgs;
}
let title = this.state.title;
@@ -290,9 +310,20 @@ class ProfileSharedByMePage extends Page {
let requestUrl;
if (this.state.query) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_by_me&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&show=shared_by_me&q=' +
encodeURIComponent(this.state.query) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_by_me' + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&show=shared_by_me' +
this.state.filterArgs;
}
this.setState({
@@ -304,7 +335,10 @@ class ProfileSharedByMePage extends Page {
onResponseDataLoaded(responseData) {
if (responseData && responseData.tags) {
const tags = responseData.tags.split(',').map((tag) => tag.trim()).filter((tag) => tag);
const tags = responseData.tags
.split(',')
.map((tag) => tag.trim())
.filter((tag) => tag);
this.setState({ availableTags: tags });
}
}
@@ -315,12 +349,12 @@ class ProfileSharedByMePage extends Page {
const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
// Check if any filters are active
const hasActiveFilters = this.state.filterArgs && (
this.state.filterArgs.includes('media_type=') ||
const hasActiveFilters =
this.state.filterArgs &&
(this.state.filterArgs.includes('media_type=') ||
this.state.filterArgs.includes('upload_date=') ||
this.state.filterArgs.includes('duration=') ||
this.state.filterArgs.includes('publish_state=')
);
this.state.filterArgs.includes('publish_state='));
return [
this.state.author ? (
@@ -335,6 +369,7 @@ class ProfileSharedByMePage extends Page {
hasActiveFilters={hasActiveFilters}
hasActiveTags={this.state.selectedTag !== 'all'}
hasActiveSort={this.state.selectedSort !== 'date_added_desc'}
hideChannelBanner={inEmbeddedApp()}
/>
) : null,
this.state.author ? (
@@ -349,8 +384,16 @@ class ProfileSharedByMePage extends Page {
onSelectAll={this.props.bulkActions.handleSelectAll}
onDeselectAll={this.props.bulkActions.handleDeselectAll}
>
<ProfileMediaFilters hidden={this.state.hiddenFilters} tags={this.state.availableTags} onFiltersUpdate={this.onFiltersUpdate} />
<ProfileMediaTags hidden={this.state.hiddenTags} tags={this.state.availableTags} onTagSelect={this.onTagSelect} />
<ProfileMediaFilters
hidden={this.state.hiddenFilters}
tags={this.state.availableTags}
onFiltersUpdate={this.onFiltersUpdate}
/>
<ProfileMediaTags
hidden={this.state.hiddenTags}
tags={this.state.availableTags}
onTagSelect={this.onTagSelect}
/>
<ProfileMediaSorting hidden={this.state.hiddenSorting} onSortSelect={this.onSortSelect} />
<LazyLoadItemListAsync
key={`${this.state.requestUrl}-${this.props.bulkActions.listKey}`}

View File

@@ -10,7 +10,7 @@ import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListA
import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFilters';
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
import { translateString } from '../utils/helpers';
import { inEmbeddedApp, translateString } from '../utils/helpers';
import { Page } from './_Page';
@@ -22,9 +22,7 @@ function EmptySharedWithMe(props) {
{(links) => (
<div className="empty-media empty-channel-media">
<div className="welcome-title">No shared media</div>
<div className="start-uploading">
Media that others have shared with you will show up here.
</div>
<div className="start-uploading">Media that others have shared with you will show up here.</div>
</div>
)}
</LinksConsumer>
@@ -79,9 +77,20 @@ export class ProfileSharedWithMePage extends Page {
if (author) {
if (this.state.query) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&show=shared_with_me&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
author.id +
'&show=shared_with_me&q=' +
encodeURIComponent(this.state.query) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&show=shared_with_me' + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
author.id +
'&show=shared_with_me' +
this.state.filterArgs;
}
}
@@ -130,9 +139,20 @@ export class ProfileSharedWithMePage extends Page {
let requestUrl;
if (newQuery) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_with_me&q=' + encodeURIComponent(newQuery) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&show=shared_with_me&q=' +
encodeURIComponent(newQuery) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_with_me' + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&show=shared_with_me' +
this.state.filterArgs;
}
let title = this.state.title;
@@ -288,9 +308,20 @@ export class ProfileSharedWithMePage extends Page {
let requestUrl;
if (this.state.query) {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_with_me&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&show=shared_with_me&q=' +
encodeURIComponent(this.state.query) +
this.state.filterArgs;
} else {
requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_with_me' + this.state.filterArgs;
requestUrl =
ApiUrlContext._currentValue.media +
'?author=' +
this.state.author.id +
'&show=shared_with_me' +
this.state.filterArgs;
}
this.setState({
@@ -302,7 +333,10 @@ export class ProfileSharedWithMePage extends Page {
onResponseDataLoaded(responseData) {
if (responseData && responseData.tags) {
const tags = responseData.tags.split(',').map((tag) => tag.trim()).filter((tag) => tag);
const tags = responseData.tags
.split(',')
.map((tag) => tag.trim())
.filter((tag) => tag);
this.setState({ availableTags: tags });
}
}
@@ -313,12 +347,12 @@ export class ProfileSharedWithMePage extends Page {
const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
// Check if any filters are active
const hasActiveFilters = this.state.filterArgs && (
this.state.filterArgs.includes('media_type=') ||
const hasActiveFilters =
this.state.filterArgs &&
(this.state.filterArgs.includes('media_type=') ||
this.state.filterArgs.includes('upload_date=') ||
this.state.filterArgs.includes('duration=') ||
this.state.filterArgs.includes('publish_state=')
);
this.state.filterArgs.includes('publish_state='));
return [
this.state.author ? (
@@ -333,16 +367,22 @@ export class ProfileSharedWithMePage extends Page {
hasActiveFilters={hasActiveFilters}
hasActiveTags={this.state.selectedTag !== 'all'}
hasActiveSort={this.state.selectedSort !== 'date_added_desc'}
hideChannelBanner={inEmbeddedApp()}
/>
) : null,
this.state.author ? (
<ProfilePagesContent key="ProfilePagesContent">
<MediaListWrapper
title={this.state.title}
className="items-list-ver"
>
<ProfileMediaFilters hidden={this.state.hiddenFilters} tags={this.state.availableTags} onFiltersUpdate={this.onFiltersUpdate} />
<ProfileMediaTags hidden={this.state.hiddenTags} tags={this.state.availableTags} onTagSelect={this.onTagSelect} />
<MediaListWrapper title={this.state.title} className="items-list-ver">
<ProfileMediaFilters
hidden={this.state.hiddenFilters}
tags={this.state.availableTags}
onFiltersUpdate={this.onFiltersUpdate}
/>
<ProfileMediaTags
hidden={this.state.hiddenTags}
tags={this.state.availableTags}
onTagSelect={this.onTagSelect}
/>
<ProfileMediaSorting hidden={this.state.hiddenSorting} onSortSelect={this.onSortSelect} />
<LazyLoadItemListAsync
key={this.state.requestUrl}

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { PageStore, MediaPageStore } from '../utils/stores/';
import { MediaPageActions } from '../utils/actions/';
import { inEmbeddedApp } from '../utils/helpers/';
import ViewerError from '../components/media-page/ViewerError';
import ViewerInfo from '../components/media-page/ViewerInfo';
import ViewerSidebar from '../components/media-page/ViewerSidebar';
@@ -86,7 +87,7 @@ export class _MediaPage extends Page {
{!this.state.infoAndSidebarViewType
? [
<ViewerInfo key="viewer-info" />,
this.state.pagePlaylistLoaded ? (
!inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
<ViewerSidebar
key="viewer-sidebar"
mediaId={MediaPageStore.get('media-id')}
@@ -95,7 +96,7 @@ export class _MediaPage extends Page {
) : null,
]
: [
this.state.pagePlaylistLoaded ? (
!inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
<ViewerSidebar
key="viewer-sidebar"
mediaId={MediaPageStore.get('media-id')}

View File

@@ -2,6 +2,7 @@ import React from 'react';
// FIXME: 'VideoViewerStore' is used only in case of video media, but is included in every media page code.
import { PageStore, MediaPageStore, VideoViewerStore } from '../utils/stores/';
import { MediaPageActions } from '../utils/actions/';
import { inEmbeddedApp } from '../utils/helpers/';
import ViewerInfoVideo from '../components/media-page/ViewerInfoVideo';
import ViewerError from '../components/media-page/ViewerError';
import ViewerSidebar from '../components/media-page/ViewerSidebar';
@@ -54,7 +55,8 @@ export class _VideoMediaPage extends Page {
}
onMediaLoad() {
const isVideoMedia = 'video' === MediaPageStore.get('media-type') || 'audio' === MediaPageStore.get('media-type');
const isVideoMedia =
'video' === MediaPageStore.get('media-type') || 'audio' === MediaPageStore.get('media-type');
if (isVideoMedia) {
this.onViewerModeChange = this.onViewerModeChange.bind(this);
@@ -102,7 +104,7 @@ export class _VideoMediaPage extends Page {
{!this.state.wideLayout || (this.state.isVideoMedia && this.state.theaterMode)
? [
<ViewerInfoVideo key="viewer-info" />,
this.state.pagePlaylistLoaded ? (
!inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
<ViewerSidebar
key="viewer-sidebar"
mediaId={MediaPageStore.get('media-id')}
@@ -111,7 +113,7 @@ export class _VideoMediaPage extends Page {
) : null,
]
: [
this.state.pagePlaylistLoaded ? (
!inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
<ViewerSidebar
key="viewer-sidebar"
mediaId={MediaPageStore.get('media-id')}

View File

@@ -1,7 +1,7 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { BrowserCache } from '../classes/';
import { PageStore } from '../stores/';
import { addClassname, removeClassname } from '../helpers/';
import { addClassname, removeClassname, inEmbeddedApp } from '../helpers/';
import SiteContext from './SiteContext';
let slidingSidebarTimeout;
@@ -45,7 +45,10 @@ export const LayoutProvider = ({ children }) => {
const site = useContext(SiteContext);
const cache = new BrowserCache('MediaCMS[' + site.id + '][layout]', 86400);
const enabledSidebar = !!(document.getElementById('app-sidebar') || document.querySelector('.page-sidebar'));
const isMediaPage = useMemo(() => PageStore.get('current-page') === 'media', []);
const isEmbeddedApp = useMemo(() => inEmbeddedApp(), []);
const enabledSidebar = Boolean(document.getElementById('app-sidebar') || document.querySelector('.page-sidebar'));
const [visibleSidebar, setVisibleSidebar] = useState(cache.get('visible-sidebar'));
const [visibleMobileSearch, setVisibleMobileSearch] = useState(false);
@@ -61,28 +64,27 @@ export const LayoutProvider = ({ children }) => {
};
useEffect(() => {
if (visibleSidebar) {
if (!isEmbeddedApp && visibleSidebar) {
addClassname(document.body, 'visible-sidebar');
} else {
removeClassname(document.body, 'visible-sidebar');
}
if ('media' !== PageStore.get('current-page') && 1023 < window.innerWidth) {
if (!isEmbeddedApp && !isMediaPage && 1023 < window.innerWidth) {
cache.set('visible-sidebar', visibleSidebar);
}
}, [visibleSidebar]);
}, [isEmbeddedApp, isMediaPage, visibleSidebar]);
useEffect(() => {
PageStore.once('page_init', () => {
if ('media' === PageStore.get('current-page')) {
if (isEmbeddedApp || isMediaPage) {
setVisibleSidebar(false);
removeClassname(document.body, 'visible-sidebar');
}
});
setVisibleSidebar(
'media' !== PageStore.get('current-page') &&
1023 < window.innerWidth &&
(null === visibleSidebar || visibleSidebar)
!isEmbeddedApp && !isMediaPage && 1023 < window.innerWidth && (null === visibleSidebar || visibleSidebar)
);
}, []);

View File

@@ -0,0 +1,20 @@
export function inEmbeddedApp() {
try {
const params = new URL(globalThis.location.href).searchParams;
const mode = params.get('mode');
if (mode === 'embed_mode') {
sessionStorage.setItem('media_cms_embed_mode', 'true');
return true;
}
if (mode === 'standard') {
sessionStorage.removeItem('media_cms_embed_mode');
return false;
}
return sessionStorage.getItem('media_cms_embed_mode') === 'true';
} catch (e) {
return false;
}
}

View File

@@ -14,3 +14,4 @@ export * from './quickSort';
export * from './requests';
export { translateString } from './translate';
export { replaceString } from './replacementStrings';
export * from './embeddedApp';

View File

@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
import { ThemeProvider } from './contexts/ThemeContext';
import { LayoutProvider } from './contexts/LayoutContext';
import { UserProvider } from './contexts/UserContext';
import { inEmbeddedApp } from './helpers';
const AppProviders = ({ children }) => (
<LayoutProvider>
@@ -15,9 +16,27 @@ const AppProviders = ({ children }) => (
import { PageHeader, PageSidebar } from '../components/page-layout';
export function renderPage(idSelector, PageComponent) {
if (inEmbeddedApp()) {
globalThis.document.body.classList.add('embedded-app');
globalThis.document.body.classList.remove('visible-sidebar');
const appContent = idSelector ? document.getElementById(idSelector) : undefined;
if (appContent && PageComponent) {
ReactDOM.render(
<AppProviders>
<PageComponent />
</AppProviders>,
appContent
);
}
return;
}
const appContent = idSelector ? document.getElementById(idSelector) : undefined;
const appHeader = document.getElementById('app-header');
const appSidebar = document.getElementById('app-sidebar');
const appContent = idSelector ? document.getElementById(idSelector) : undefined;
if (appContent && PageComponent) {
ReactDOM.render(

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
!function(){"use strict";var n,e={4256:function(n,e,r){(0,r(2985).C)()}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}t.m=e,n=[],t.O=function(e,r,o,i){if(!r){var u=1/0;for(l=0;l<n.length;l++){r=n[l][0],o=n[l][1],i=n[l][2];for(var f=!0,c=0;c<r.length;c++)(!1&i||u>=i)&&Object.keys(t.O).every(function(n){return t.O[n](r[c])})?r.splice(c--,1):(f=!1,i<u&&(u=i));if(f){n.splice(l--,1);var a=o();void 0!==a&&(e=a)}}return e}i=i||0;for(var l=n.length;l>0&&n[l-1][2]>i;l--)n[l]=n[l-1];n[l]=[r,o,i]},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,{a:e}),e},t.d=function(n,e){for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.j=594,function(){var n={594:0};t.O.j=function(e){return 0===n[e]};var e=function(e,r){var o,i,u=r[0],f=r[1],c=r[2],a=0;if(u.some(function(e){return 0!==n[e]})){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(c)var l=c(t)}for(e&&e(r);a<u.length;a++)i=u[a],t.o(n,i)&&n[i]&&n[i][0](),n[i]=0;return t.O(l)},r=self.webpackChunkmediacms_frontend=self.webpackChunkmediacms_frontend||[];r.forEach(e.bind(null,0)),r.push=e.bind(null,r.push.bind(r))}();var o=t.O(void 0,[276],function(){return t(4256)});o=t.O(o)}();
!function(){"use strict";var n,e={4256:function(n,e,r){(0,r(2985).C)()}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}t.m=e,n=[],t.O=function(e,r,o,i){if(!r){var u=1/0;for(l=0;l<n.length;l++){r=n[l][0],o=n[l][1],i=n[l][2];for(var f=!0,c=0;c<r.length;c++)(!1&i||u>=i)&&Object.keys(t.O).every((function(n){return t.O[n](r[c])}))?r.splice(c--,1):(f=!1,i<u&&(u=i));if(f){n.splice(l--,1);var a=o();void 0!==a&&(e=a)}}return e}i=i||0;for(var l=n.length;l>0&&n[l-1][2]>i;l--)n[l]=n[l-1];n[l]=[r,o,i]},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,{a:e}),e},t.d=function(n,e){for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.j=594,function(){var n={594:0};t.O.j=function(e){return 0===n[e]};var e=function(e,r){var o,i,u=r[0],f=r[1],c=r[2],a=0;if(u.some((function(e){return 0!==n[e]}))){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(c)var l=c(t)}for(e&&e(r);a<u.length;a++)i=u[a],t.o(n,i)&&n[i]&&n[i][0](),n[i]=0;return t.O(l)},r=self.webpackChunkmediacms_frontend=self.webpackChunkmediacms_frontend||[];r.forEach(e.bind(null,0)),r.push=e.bind(null,r.push.bind(r))}();var o=t.O(void 0,[276],(function(){return t(4256)}));o=t.O(o)}();

View File

@@ -1 +1 @@
!function(){"use strict";var n,e={5879:function(n,e,r){(0,r(2985).C)()}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}t.m=e,n=[],t.O=function(e,r,o,i){if(!r){var u=1/0;for(l=0;l<n.length;l++){r=n[l][0],o=n[l][1],i=n[l][2];for(var f=!0,c=0;c<r.length;c++)(!1&i||u>=i)&&Object.keys(t.O).every(function(n){return t.O[n](r[c])})?r.splice(c--,1):(f=!1,i<u&&(u=i));if(f){n.splice(l--,1);var a=o();void 0!==a&&(e=a)}}return e}i=i||0;for(var l=n.length;l>0&&n[l-1][2]>i;l--)n[l]=n[l-1];n[l]=[r,o,i]},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,{a:e}),e},t.d=function(n,e){for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.j=543,function(){var n={543:0};t.O.j=function(e){return 0===n[e]};var e=function(e,r){var o,i,u=r[0],f=r[1],c=r[2],a=0;if(u.some(function(e){return 0!==n[e]})){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(c)var l=c(t)}for(e&&e(r);a<u.length;a++)i=u[a],t.o(n,i)&&n[i]&&n[i][0](),n[i]=0;return t.O(l)},r=self.webpackChunkmediacms_frontend=self.webpackChunkmediacms_frontend||[];r.forEach(e.bind(null,0)),r.push=e.bind(null,r.push.bind(r))}();var o=t.O(void 0,[276],function(){return t(5879)});o=t.O(o)}();
!function(){"use strict";var n,e={5879:function(n,e,r){(0,r(2985).C)()}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}t.m=e,n=[],t.O=function(e,r,o,i){if(!r){var u=1/0;for(l=0;l<n.length;l++){r=n[l][0],o=n[l][1],i=n[l][2];for(var f=!0,c=0;c<r.length;c++)(!1&i||u>=i)&&Object.keys(t.O).every((function(n){return t.O[n](r[c])}))?r.splice(c--,1):(f=!1,i<u&&(u=i));if(f){n.splice(l--,1);var a=o();void 0!==a&&(e=a)}}return e}i=i||0;for(var l=n.length;l>0&&n[l-1][2]>i;l--)n[l]=n[l-1];n[l]=[r,o,i]},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,{a:e}),e},t.d=function(n,e){for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.j=543,function(){var n={543:0};t.O.j=function(e){return 0===n[e]};var e=function(e,r){var o,i,u=r[0],f=r[1],c=r[2],a=0;if(u.some((function(e){return 0!==n[e]}))){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(c)var l=c(t)}for(e&&e(r);a<u.length;a++)i=u[a],t.o(n,i)&&n[i]&&n[i][0](),n[i]=0;return t.O(l)},r=self.webpackChunkmediacms_frontend=self.webpackChunkmediacms_frontend||[];r.forEach(e.bind(null,0)),r.push=e.bind(null,r.push.bind(r))}();var o=t.O(void 0,[276],(function(){return t(5879)}));o=t.O(o)}();

View File

@@ -1 +1 @@
!function(){"use strict";var n,e={1684:function(n,e,r){(0,r(2985).C)()}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}t.m=e,n=[],t.O=function(e,r,o,i){if(!r){var u=1/0;for(l=0;l<n.length;l++){r=n[l][0],o=n[l][1],i=n[l][2];for(var f=!0,c=0;c<r.length;c++)(!1&i||u>=i)&&Object.keys(t.O).every(function(n){return t.O[n](r[c])})?r.splice(c--,1):(f=!1,i<u&&(u=i));if(f){n.splice(l--,1);var a=o();void 0!==a&&(e=a)}}return e}i=i||0;for(var l=n.length;l>0&&n[l-1][2]>i;l--)n[l]=n[l-1];n[l]=[r,o,i]},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,{a:e}),e},t.d=function(n,e){for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.j=152,function(){var n={152:0};t.O.j=function(e){return 0===n[e]};var e=function(e,r){var o,i,u=r[0],f=r[1],c=r[2],a=0;if(u.some(function(e){return 0!==n[e]})){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(c)var l=c(t)}for(e&&e(r);a<u.length;a++)i=u[a],t.o(n,i)&&n[i]&&n[i][0](),n[i]=0;return t.O(l)},r=self.webpackChunkmediacms_frontend=self.webpackChunkmediacms_frontend||[];r.forEach(e.bind(null,0)),r.push=e.bind(null,r.push.bind(r))}();var o=t.O(void 0,[276],function(){return t(1684)});o=t.O(o)}();
!function(){"use strict";var n,e={1684:function(n,e,r){(0,r(2985).C)()}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}t.m=e,n=[],t.O=function(e,r,o,i){if(!r){var u=1/0;for(l=0;l<n.length;l++){r=n[l][0],o=n[l][1],i=n[l][2];for(var f=!0,c=0;c<r.length;c++)(!1&i||u>=i)&&Object.keys(t.O).every((function(n){return t.O[n](r[c])}))?r.splice(c--,1):(f=!1,i<u&&(u=i));if(f){n.splice(l--,1);var a=o();void 0!==a&&(e=a)}}return e}i=i||0;for(var l=n.length;l>0&&n[l-1][2]>i;l--)n[l]=n[l-1];n[l]=[r,o,i]},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,{a:e}),e},t.d=function(n,e){for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.j=152,function(){var n={152:0};t.O.j=function(e){return 0===n[e]};var e=function(e,r){var o,i,u=r[0],f=r[1],c=r[2],a=0;if(u.some((function(e){return 0!==n[e]}))){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(c)var l=c(t)}for(e&&e(r);a<u.length;a++)i=u[a],t.o(n,i)&&n[i]&&n[i][0](),n[i]=0;return t.O(l)},r=self.webpackChunkmediacms_frontend=self.webpackChunkmediacms_frontend||[];r.forEach(e.bind(null,0)),r.push=e.bind(null,r.push.bind(r))}();var o=t.O(void 0,[276],(function(){return t(1684)}));o=t.O(o)}();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long