This commit is contained in:
Markos Gogoulos
2026-02-01 13:38:48 +02:00
parent 27828d798e
commit f28ce5990b
18 changed files with 118 additions and 64 deletions

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { translateString, inEmbeddedApp } from '../utils/helpers/';
import { translateString, inSelectMediaEmbedMode } from '../utils/helpers/';
interface MediaListHeaderProps {
title?: string;
@@ -11,12 +11,12 @@ interface MediaListHeaderProps {
export const MediaListHeader: React.FC<MediaListHeaderProps> = (props) => {
const viewAllText = props.viewAllText || translateString('VIEW ALL');
const isEmbedMode = inEmbeddedApp();
const isSelectMediaMode = inSelectMediaEmbedMode();
return (
<div className={(props.className ? props.className + ' ' : '') + 'media-list-header'} style={props.style}>
<h2>{props.title}</h2>
{!isEmbedMode && props.viewAllLink ? (
{!isSelectMediaMode && props.viewAllLink ? (
<h3>
{' '}
<a href={props.viewAllLink} title={viewAllText}>

View File

@@ -1,13 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useMediaItem } from '../../utils/hooks/';
import { PositiveInteger, PositiveIntegerOrZero, inEmbeddedApp } from '../../utils/helpers/';
import { PositiveInteger, PositiveIntegerOrZero, inSelectMediaEmbedMode } from '../../utils/helpers/';
import { MediaItemThumbnailLink, itemClassname } from './includes/items/';
import { Item } from './Item';
export function MediaItem(props) {
const type = props.type;
const isEmbedMode = inEmbeddedApp();
const isSelectMediaMode = inSelectMediaEmbedMode();
const [titleComponentOrig, descriptionComponent, thumbnailUrl, UnderThumbWrapperOrig, editMediaComponent, metaComponents, viewMediaComponent] =
useMediaItem({ ...props, type });
@@ -21,14 +21,14 @@ export function MediaItem(props) {
const ItemMain = ({ children }) => <div className="item-main">{children}</div>;
const titleComponent = isEmbedMode
const titleComponent = isSelectMediaMode
? () => <ItemTitle title={props.title} />
: titleComponentOrig;
const UnderThumbWrapper = isEmbedMode ? ItemMain : UnderThumbWrapperOrig;
const UnderThumbWrapper = isSelectMediaMode ? ItemMain : UnderThumbWrapperOrig;
function thumbnailComponent() {
if (isEmbedMode) {
if (isSelectMediaMode) {
// In embed mode, render thumbnail without link
const thumbStyle = thumbnailUrl ? { backgroundImage: "url('" + thumbnailUrl + "')" } : null;
return (
@@ -57,13 +57,13 @@ export function MediaItem(props) {
const finalClassname = containerClassname +
(props.showSelection ? ' with-selection' : '') +
(props.isSelected ? ' selected' : '') +
(props.hasAnySelection || isEmbedMode ? ' has-any-selection' : '');
(props.hasAnySelection || isSelectMediaMode ? ' has-any-selection' : '');
const handleItemClick = (e) => {
const isEmbedMode = inEmbeddedApp();
const isSelectMediaMode = inSelectMediaEmbedMode();
// In embed mode or if there's any selection active, clicking the item should toggle selection
if ((isEmbedMode || props.hasAnySelection) && props.onCheckboxChange) {
// In select media mode or if there's any selection active, clicking the item should toggle selection
if ((isSelectMediaMode || props.hasAnySelection) && props.onCheckboxChange) {
// Check if clicking on the checkbox itself, edit icon, or view icon
if (e.target.closest('.item-selection-checkbox') ||
e.target.closest('.item-edit-icon') ||
@@ -93,12 +93,12 @@ export function MediaItem(props) {
</div>
)}
{!isEmbedMode && editMediaComponent()}
{!isEmbedMode && viewMediaComponent()}
{!isSelectMediaMode && editMediaComponent()}
{!isSelectMediaMode && viewMediaComponent()}
{thumbnailComponent()}
{isEmbedMode ? (
{isSelectMediaMode ? (
<UnderThumbWrapper>
{titleComponent()}
{metaComponents()}

View File

@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useMediaItem } from '../../utils/hooks/';
import { PositiveIntegerOrZero, inEmbeddedApp } from '../../utils/helpers/';
import { PositiveIntegerOrZero, inSelectMediaEmbedMode } from '../../utils/helpers/';
import { MediaDurationInfo } from '../../utils/classes/';
import { MediaPlaylistOptions } from '../media-playlist-options/MediaPlaylistOptions';
import { MediaItemDuration, MediaItemPlaylistIndex, itemClassname } from './includes/items/';
@@ -9,7 +9,7 @@ import { MediaItem } from './MediaItem';
export function MediaItemAudio(props) {
const type = props.type;
const isEmbedMode = inEmbeddedApp();
const isSelectMediaMode = inSelectMediaEmbedMode();
const [titleComponentOrig, descriptionComponent, thumbnailUrl, UnderThumbWrapperOrig, editMediaComponent, metaComponents, viewMediaComponent] =
useMediaItem({ ...props, type });
@@ -23,11 +23,11 @@ export function MediaItemAudio(props) {
const ItemMain = ({ children }) => <div className="item-main">{children}</div>;
const titleComponent = isEmbedMode
const titleComponent = isSelectMediaMode
? () => <ItemTitle title={props.title} />
: titleComponentOrig;
const UnderThumbWrapper = isEmbedMode ? ItemMain : UnderThumbWrapperOrig;
const UnderThumbWrapper = isSelectMediaMode ? ItemMain : UnderThumbWrapperOrig;
const _MediaDurationInfo = new MediaDurationInfo();
@@ -38,7 +38,7 @@ export function MediaItemAudio(props) {
const durationISO8601 = _MediaDurationInfo.ISO8601();
function thumbnailComponent() {
if (isEmbedMode) {
if (isSelectMediaMode) {
// In embed mode, render thumbnail without link
return (
<div
@@ -99,11 +99,11 @@ export function MediaItemAudio(props) {
const finalClassname = containerClassname +
(props.showSelection ? ' with-selection' : '') +
(props.isSelected ? ' selected' : '') +
(props.hasAnySelection || isEmbedMode ? ' has-any-selection' : '');
(props.hasAnySelection || isSelectMediaMode ? ' has-any-selection' : '');
const handleItemClick = (e) => {
// In embed mode or if there's any selection active, clicking the item should toggle selection
if ((isEmbedMode || props.hasAnySelection) && props.onCheckboxChange) {
if ((isSelectMediaMode || props.hasAnySelection) && props.onCheckboxChange) {
// Check if clicking on the checkbox itself, edit icon, or view icon
if (e.target.closest('.item-selection-checkbox') ||
e.target.closest('.item-edit-icon') ||
@@ -135,12 +135,12 @@ export function MediaItemAudio(props) {
</div>
)}
{!isEmbedMode && editMediaComponent()}
{!isEmbedMode && viewMediaComponent()}
{!isSelectMediaMode && editMediaComponent()}
{!isSelectMediaMode && viewMediaComponent()}
{thumbnailComponent()}
{isEmbedMode ? (
{isSelectMediaMode ? (
<UnderThumbWrapper>
{titleComponent()}
{metaComponents()}

View File

@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useMediaItem } from '../../utils/hooks/';
import { PositiveIntegerOrZero, inEmbeddedApp } from '../../utils/helpers/';
import { PositiveIntegerOrZero, inSelectMediaEmbedMode } from '../../utils/helpers/';
import { MediaDurationInfo } from '../../utils/classes/';
import { MediaPlaylistOptions } from '../media-playlist-options/MediaPlaylistOptions.jsx';
import { MediaItemVideoPlayer, MediaItemDuration, MediaItemVideoPreviewer, MediaItemPlaylistIndex, itemClassname } from './includes/items/';
@@ -9,7 +9,7 @@ import { MediaItem } from './MediaItem';
export function MediaItemVideo(props) {
const type = props.type;
const isEmbedMode = inEmbeddedApp();
const isSelectMediaMode = inSelectMediaEmbedMode();
const [titleComponentOrig, descriptionComponent, thumbnailUrl, UnderThumbWrapperOrig, editMediaComponent, metaComponents, viewMediaComponent] =
useMediaItem({ ...props, type });
@@ -23,11 +23,11 @@ export function MediaItemVideo(props) {
const ItemMain = ({ children }) => <div className="item-main">{children}</div>;
const titleComponent = isEmbedMode
const titleComponent = isSelectMediaMode
? () => <ItemTitle title={props.title} />
: titleComponentOrig;
const UnderThumbWrapper = isEmbedMode ? ItemMain : UnderThumbWrapperOrig;
const UnderThumbWrapper = isSelectMediaMode ? ItemMain : UnderThumbWrapperOrig;
const _MediaDurationInfo = new MediaDurationInfo();
@@ -42,8 +42,8 @@ export function MediaItemVideo(props) {
}
function thumbnailComponent() {
if (isEmbedMode) {
// In embed mode, render thumbnail without link
if (isSelectMediaMode) {
// In select media mode, render thumbnail without link
return (
<div
key="item-thumb"
@@ -109,11 +109,11 @@ export function MediaItemVideo(props) {
const finalClassname = containerClassname +
(props.showSelection ? ' with-selection' : '') +
(props.isSelected ? ' selected' : '') +
(props.hasAnySelection || isEmbedMode ? ' has-any-selection' : '');
(props.hasAnySelection || isSelectMediaMode ? ' has-any-selection' : '');
const handleItemClick = (e) => {
// In embed mode or if there's any selection active, clicking the item should toggle selection
if ((isEmbedMode || props.hasAnySelection) && props.onCheckboxChange) {
// In select media mode or if there's any selection active, clicking the item should toggle selection
if ((isSelectMediaMode || props.hasAnySelection) && props.onCheckboxChange) {
// Check if clicking on the checkbox itself, edit icon, or view icon
if (e.target.closest('.item-selection-checkbox') ||
e.target.closest('.item-edit-icon') ||
@@ -145,12 +145,12 @@ export function MediaItemVideo(props) {
</div>
)}
{!isEmbedMode && editMediaComponent()}
{!isEmbedMode && viewMediaComponent()}
{!isSelectMediaMode && editMediaComponent()}
{!isSelectMediaMode && viewMediaComponent()}
{props.hasMediaViewer ? videoViewerComponent() : thumbnailComponent()}
{isEmbedMode ? (
{isSelectMediaMode ? (
<UnderThumbWrapper>
{titleComponent()}
{metaComponents()}

View File

@@ -5,7 +5,7 @@ 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 { translateString, inEmbeddedApp } from '../../utils/helpers/';
import { translateString, inEmbeddedApp, inSelectMediaEmbedMode } from '../../utils/helpers/';
class ProfileSearchBar extends React.PureComponent {
constructor(props) {
@@ -372,7 +372,7 @@ class NavMenuInlineTabs extends React.PureComponent {
}
render() {
const isEmbedMode = inEmbeddedApp();
const isSelectMediaMode = inSelectMediaEmbedMode();
return (
<nav ref="tabsNav" className="profile-nav items-list-outer list-inline list-slider">
@@ -380,7 +380,7 @@ class NavMenuInlineTabs extends React.PureComponent {
{this.state.displayPrev ? this.previousBtn : null}
<ul className="items-list-wrap" ref="itemsListWrap">
{!isEmbedMode ? (
{!isSelectMediaMode ? (
<InlineTab
id="about"
isActive={'about' === this.props.type}
@@ -411,7 +411,7 @@ class NavMenuInlineTabs extends React.PureComponent {
/>
) : null}
{!isEmbedMode && MemberContext._currentValue.can.saveMedia ? (
{!isSelectMediaMode && MemberContext._currentValue.can.saveMedia ? (
<InlineTab
id="playlists"
isActive={'playlists' === this.props.type}
@@ -772,7 +772,7 @@ export default function ProfilePagesHeader(props) {
)}
<div className="profile-info-nav-wrap">
{inEmbeddedApp() ? (
{inSelectMediaEmbedMode() ? (
<div className="profile-info">
<div className="profile-info-inner">
<div>

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 { inEmbeddedApp, translateString } from '../utils/helpers/';
import { inEmbeddedApp, inSelectMediaEmbedMode, translateString } from '../utils/helpers/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
@@ -202,13 +202,13 @@ export class ProfileMediaPage extends Page {
}
handleMediaSelection(mediaId, isSelected) {
const isEmbedMode = inEmbeddedApp();
const isSelectMediaMode = inSelectMediaEmbedMode();
this.setState((prevState) => {
const newSelectedMedia = new Set();
// In embed mode, only allow single selection
if (isEmbedMode) {
// In select media mode, only allow single selection
if (isSelectMediaMode) {
if (isSelected) {
newSelectedMedia.add(mediaId);
console.log('Selected media item:', mediaId);
@@ -933,7 +933,7 @@ export class ProfileMediaPage extends Page {
const authorData = ProfilePageStore.get('author-data');
const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
const isEmbedMode = inEmbeddedApp();
const isSelectMediaMode = inSelectMediaEmbedMode();
// Check if any filters are active (excluding default sort and tags)
const hasActiveFilters =
@@ -965,16 +965,16 @@ export class ProfileMediaPage extends Page {
this.state.author ? (
<ProfilePagesContent key="ProfilePagesContent">
<MediaListWrapper
title={isEmbedMode ? undefined : this.state.title}
title={isSelectMediaMode ? undefined : this.state.title}
className="items-list-ver"
style={isEmbedMode ? { marginTop: '24px' } : undefined}
showBulkActions={!isEmbedMode && isMediaAuthor}
style={isSelectMediaMode ? { marginTop: '24px' } : undefined}
showBulkActions={!isSelectMediaMode && isMediaAuthor}
selectedCount={this.state.selectedMedia.size}
totalCount={this.state.availableMediaIds.length}
onBulkAction={this.handleBulkAction}
onSelectAll={this.handleSelectAll}
onDeselectAll={this.handleDeselectAll}
showAddMediaButton={!isEmbedMode && isMediaAuthor}
showAddMediaButton={!isSelectMediaMode && isMediaAuthor}
>
<ProfileMediaFilters
hidden={this.state.hiddenFilters}
@@ -997,7 +997,7 @@ export class ProfileMediaPage extends Page {
hideViews={!PageStore.get('config-media-item').displayViews}
hideDate={!PageStore.get('config-media-item').displayPublishDate}
canEdit={isMediaAuthor}
showSelection={isMediaAuthor || isEmbedMode}
showSelection={isMediaAuthor || isSelectMediaMode}
hasAnySelection={this.state.selectedMedia.size > 0}
selectedMedia={this.state.selectedMedia}
onMediaSelection={this.handleMediaSelection}

View File

@@ -7,7 +7,7 @@ export function inEmbeddedApp() {
sessionStorage.setItem('media_cms_embed_mode', 'true');
return true;
}
if (mode === 'standard') {
sessionStorage.removeItem('media_cms_embed_mode');
return false;
@@ -18,3 +18,29 @@ export function inEmbeddedApp() {
return false;
}
}
export function isSelectMediaMode() {
try {
const params = new URL(globalThis.location.href).searchParams;
const action = params.get('action');
if (action === 'select_media') {
sessionStorage.setItem('media_cms_select_media', 'true');
return true;
}
// Clear if action is explicitly something else
if (action && action !== 'select_media') {
sessionStorage.removeItem('media_cms_select_media');
return false;
}
return sessionStorage.getItem('media_cms_select_media') === 'true';
} catch (e) {
return false;
}
}
export function inSelectMediaEmbedMode() {
return inEmbeddedApp() && isSelectMediaMode();
}