mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-03-22 04:33:09 -04:00
refactor(frontend): convert contexts layer to TS and align page integration
This commit is contained in:
@@ -55,7 +55,7 @@ export const HistoryPage: React.FC = () => {
|
||||
const anonymousPage = isAnonymous || !PageStore.get('config-options').pages.profile.includeHistory;
|
||||
|
||||
if (!anonymousPage) {
|
||||
addClassname(document.getElementById('page-history'), 'profile-page-history');
|
||||
addClassname(document.getElementById('page-history')!, 'profile-page-history');
|
||||
window.MediaCMS.profileId = username;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ export const HomePage: React.FC<HomePageProps> = ({
|
||||
<MediaListRow
|
||||
title={featured_title}
|
||||
style={!visibleFeatured ? { display: 'none' } : undefined}
|
||||
viewAllLink={featured_view_all_link ? links.featured : null}
|
||||
viewAllLink={featured_view_all_link ? links.featured : undefined}
|
||||
>
|
||||
<InlineSliderItemListAsync
|
||||
requestUrl={apiUrl.featured}
|
||||
@@ -93,7 +93,7 @@ export const HomePage: React.FC<HomePageProps> = ({
|
||||
<MediaListRow
|
||||
title={recommended_title}
|
||||
style={!visibleRecommended ? { display: 'none' } : undefined}
|
||||
viewAllLink={recommended_view_all_link ? links.recommended : null}
|
||||
viewAllLink={recommended_view_all_link ? links.recommended : undefined}
|
||||
>
|
||||
<InlineSliderItemListAsync
|
||||
requestUrl={apiUrl.recommended}
|
||||
@@ -108,7 +108,7 @@ export const HomePage: React.FC<HomePageProps> = ({
|
||||
<MediaListRow
|
||||
title={latest_title}
|
||||
style={!visibleLatest ? { display: 'none' } : undefined}
|
||||
viewAllLink={latest_view_all_link ? links.latest : null}
|
||||
viewAllLink={latest_view_all_link ? links.latest : undefined}
|
||||
>
|
||||
<ItemListAsync
|
||||
pageItems={30}
|
||||
|
||||
@@ -55,7 +55,7 @@ export const LikedMediaPage: React.FC = () => {
|
||||
const anonymousPage = isAnonymous || !PageStore.get('config-options').pages.profile.includeLikedMedia;
|
||||
|
||||
if (!anonymousPage) {
|
||||
addClassname(document.getElementById('page-liked'), 'profile-page-liked');
|
||||
addClassname(document.getElementById('page-liked')!, 'profile-page-liked');
|
||||
window.MediaCMS.profileId = username;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
|
||||
export const ApiUrlContext = createContext(mediacmsConfig(window.MediaCMS).api);
|
||||
export const ApiUrlConsumer = ApiUrlContext.Consumer;
|
||||
5
frontend/src/static/js/utils/contexts/ApiUrlContext.ts
Normal file
5
frontend/src/static/js/utils/contexts/ApiUrlContext.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
export const ApiUrlContext = createContext(mediacmsConfig(window.MediaCMS).api);
|
||||
export const ApiUrlConsumer = ApiUrlContext.Consumer;
|
||||
@@ -1,130 +0,0 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
import { translateString } from '../../utils/helpers/';
|
||||
|
||||
const config = mediacmsConfig(window.MediaCMS);
|
||||
|
||||
const links = config.url;
|
||||
const theme = config.theme;
|
||||
const user = config.member;
|
||||
|
||||
const hasThemeSwitcher = theme.switch.enabled && 'header' === theme.switch.position;
|
||||
|
||||
function popupTopNavItems() {
|
||||
const items = [];
|
||||
|
||||
if (!user.is.anonymous) {
|
||||
if (user.can.addMedia) {
|
||||
items.push({
|
||||
link: links.user.addMedia,
|
||||
icon: 'video_call',
|
||||
text: translateString('Upload media'),
|
||||
itemAttr: {
|
||||
className: 'visible-only-in-small',
|
||||
},
|
||||
});
|
||||
|
||||
if (user.pages.media) {
|
||||
items.push({
|
||||
link: user.pages.media,
|
||||
icon: 'video_library',
|
||||
text: translateString('My media'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
items.push({
|
||||
link: links.signout,
|
||||
icon: 'exit_to_app',
|
||||
text: translateString('Sign out'),
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function popupMiddleNavItems() {
|
||||
const items = [];
|
||||
|
||||
if (hasThemeSwitcher) {
|
||||
items.push({
|
||||
itemType: 'open-subpage',
|
||||
icon: 'brightness_4',
|
||||
iconPos: 'left',
|
||||
text: 'Switch theme',
|
||||
buttonAttr: {
|
||||
className: 'change-page',
|
||||
'data-page-id': 'switch-theme',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (user.is.anonymous) {
|
||||
if (user.can.login) {
|
||||
items.push({
|
||||
itemType: 'link',
|
||||
icon: 'login',
|
||||
iconPos: 'left',
|
||||
text: translateString('Sign in'),
|
||||
link: links.signin,
|
||||
linkAttr: {
|
||||
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (user.can.register) {
|
||||
items.push({
|
||||
itemType: 'link',
|
||||
icon: 'person_add',
|
||||
iconPos: 'left',
|
||||
text: translateString('Register'),
|
||||
link: links.register,
|
||||
linkAttr: {
|
||||
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
items.push({
|
||||
link: links.user.editProfile,
|
||||
icon: 'brush',
|
||||
text: translateString('Edit profile'),
|
||||
});
|
||||
|
||||
if (user.can.changePassword) {
|
||||
items.push({
|
||||
link: links.changePassword,
|
||||
icon: 'lock',
|
||||
text: translateString('Change password'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function popupBottomNavItems() {
|
||||
const items = [];
|
||||
|
||||
if (user.is.admin) {
|
||||
items.push({
|
||||
link: links.admin,
|
||||
icon: 'admin_panel_settings',
|
||||
text: 'MediaCMS administration',
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
export const HeaderContext = createContext({
|
||||
hasThemeSwitcher,
|
||||
popupNavItems: {
|
||||
top: popupTopNavItems(),
|
||||
middle: popupMiddleNavItems(),
|
||||
bottom: popupBottomNavItems(),
|
||||
},
|
||||
});
|
||||
|
||||
export const HeaderConsumer = HeaderContext.Consumer;
|
||||
130
frontend/src/static/js/utils/contexts/HeaderContext.ts
Normal file
130
frontend/src/static/js/utils/contexts/HeaderContext.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
import { translateString } from '../helpers';
|
||||
|
||||
const config = mediacmsConfig(window.MediaCMS);
|
||||
|
||||
const links = config.url;
|
||||
const theme = config.theme;
|
||||
const user = config.member;
|
||||
|
||||
const hasThemeSwitcher = theme.switch.enabled && 'header' === theme.switch.position;
|
||||
|
||||
function popupTopNavItems() {
|
||||
const items = [];
|
||||
|
||||
if (!user.is.anonymous) {
|
||||
if (user.can.addMedia) {
|
||||
items.push({
|
||||
link: links.user.addMedia,
|
||||
icon: 'video_call',
|
||||
text: translateString('Upload media'),
|
||||
itemAttr: {
|
||||
className: 'visible-only-in-small',
|
||||
},
|
||||
});
|
||||
|
||||
if (user.pages.media) {
|
||||
items.push({
|
||||
link: user.pages.media,
|
||||
icon: 'video_library',
|
||||
text: translateString('My media'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
items.push({
|
||||
link: links.signout,
|
||||
icon: 'exit_to_app',
|
||||
text: translateString('Sign out'),
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function popupMiddleNavItems() {
|
||||
const items = [];
|
||||
|
||||
if (hasThemeSwitcher) {
|
||||
items.push({
|
||||
itemType: 'open-subpage',
|
||||
icon: 'brightness_4',
|
||||
iconPos: 'left',
|
||||
text: 'Switch theme',
|
||||
buttonAttr: {
|
||||
className: 'change-page',
|
||||
'data-page-id': 'switch-theme',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (user.is.anonymous) {
|
||||
if (user.can.login) {
|
||||
items.push({
|
||||
itemType: 'link',
|
||||
icon: 'login',
|
||||
iconPos: 'left',
|
||||
text: translateString('Sign in'),
|
||||
link: links.signin,
|
||||
linkAttr: {
|
||||
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (user.can.register) {
|
||||
items.push({
|
||||
itemType: 'link',
|
||||
icon: 'person_add',
|
||||
iconPos: 'left',
|
||||
text: translateString('Register'),
|
||||
link: links.register,
|
||||
linkAttr: {
|
||||
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
items.push({
|
||||
link: links.user.editProfile,
|
||||
icon: 'brush',
|
||||
text: translateString('Edit profile'),
|
||||
});
|
||||
|
||||
if (user.can.changePassword) {
|
||||
items.push({
|
||||
link: links.changePassword,
|
||||
icon: 'lock',
|
||||
text: translateString('Change password'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function popupBottomNavItems() {
|
||||
const items = [];
|
||||
|
||||
if (user.is.admin) {
|
||||
items.push({
|
||||
link: links.admin,
|
||||
icon: 'admin_panel_settings',
|
||||
text: 'MediaCMS administration',
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
export const HeaderContext = createContext({
|
||||
hasThemeSwitcher,
|
||||
popupNavItems: {
|
||||
top: popupTopNavItems(),
|
||||
middle: popupMiddleNavItems(),
|
||||
bottom: popupBottomNavItems(),
|
||||
},
|
||||
});
|
||||
|
||||
export const HeaderConsumer = HeaderContext.Consumer;
|
||||
@@ -1,13 +1,15 @@
|
||||
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { BrowserCache } from '../classes/';
|
||||
import { PageStore } from '../stores/';
|
||||
import { addClassname, removeClassname, inEmbeddedApp } from '../helpers/';
|
||||
import React, { createContext, ReactNode, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { BrowserCache } from '../classes';
|
||||
import { PageStore } from '../stores';
|
||||
import { addClassname, removeClassname, inEmbeddedApp } from '../helpers';
|
||||
import SiteContext from './SiteContext';
|
||||
|
||||
let slidingSidebarTimeout;
|
||||
let slidingSidebarTimeout: NodeJS.Timeout | null = null;
|
||||
|
||||
function onSidebarVisibilityChange(visibleSidebar) {
|
||||
clearTimeout(slidingSidebarTimeout);
|
||||
function onSidebarVisibilityChange(visibleSidebar: boolean) {
|
||||
if (slidingSidebarTimeout) {
|
||||
clearTimeout(slidingSidebarTimeout);
|
||||
}
|
||||
|
||||
addClassname(document.body, 'sliding-sidebar');
|
||||
|
||||
@@ -39,18 +41,29 @@ function onSidebarVisibilityChange(visibleSidebar) {
|
||||
}, 20);
|
||||
}
|
||||
|
||||
export const LayoutContext = createContext();
|
||||
export const LayoutContext = createContext({
|
||||
enabledSidebar: true,
|
||||
visibleSidebar: true,
|
||||
setVisibleSidebar: (_: boolean) => {},
|
||||
visibleMobileSearch: false,
|
||||
toggleMobileSearch: () => {},
|
||||
toggleSidebar: () => {},
|
||||
});
|
||||
|
||||
export const LayoutProvider = ({ children }) => {
|
||||
export const LayoutProvider = ({ children }: { children: ReactNode }) => {
|
||||
const site = useContext(SiteContext);
|
||||
const cache = new BrowserCache('MediaCMS[' + site.id + '][layout]', 86400);
|
||||
const cache = BrowserCache('MediaCMS[' + site.id + '][layout]', 86400);
|
||||
|
||||
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 [visibleSidebar, setVisibleSidebar] = useState<boolean>(
|
||||
cache instanceof Error
|
||||
? true // @todo: Check this again
|
||||
: cache.get('visible-sidebar')
|
||||
);
|
||||
const [visibleMobileSearch, setVisibleMobileSearch] = useState(false);
|
||||
|
||||
const toggleMobileSearch = () => {
|
||||
@@ -71,7 +84,9 @@ export const LayoutProvider = ({ children }) => {
|
||||
}
|
||||
|
||||
if (!isEmbeddedApp && !isMediaPage && 1023 < window.innerWidth) {
|
||||
cache.set('visible-sidebar', visibleSidebar);
|
||||
if (!(cache instanceof Error)) {
|
||||
cache.set('visible-sidebar', visibleSidebar);
|
||||
}
|
||||
}
|
||||
}, [isEmbeddedApp, isMediaPage, visibleSidebar]);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
export const LinksContext = createContext(mediacmsConfig(window.MediaCMS).url);
|
||||
export const LinksConsumer = LinksContext.Consumer;
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
export const MemberContext = createContext(mediacmsConfig(window.MediaCMS).member);
|
||||
export const MemberConsumer = MemberContext.Consumer;
|
||||
@@ -1,4 +0,0 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
|
||||
export const PlaylistsContext = createContext(mediacmsConfig(window.MediaCMS).playlists);
|
||||
@@ -0,0 +1,4 @@
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
export const PlaylistsContext = createContext(mediacmsConfig(window.MediaCMS).playlists);
|
||||
@@ -1,5 +0,0 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
|
||||
export const ShareOptionsContext = createContext(mediacmsConfig(window.MediaCMS).media.share.options);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
export const ShareOptionsContext = createContext(mediacmsConfig(window.MediaCMS).media.share.options);
|
||||
@@ -1,5 +0,0 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
|
||||
export const SidebarContext = createContext(mediacmsConfig(window.MediaCMS).sidebar);
|
||||
export const SidebarConsumer = SidebarContext.Consumer;
|
||||
5
frontend/src/static/js/utils/contexts/SidebarContext.ts
Normal file
5
frontend/src/static/js/utils/contexts/SidebarContext.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
export const SidebarContext = createContext(mediacmsConfig(window.MediaCMS).sidebar);
|
||||
export const SidebarConsumer = SidebarContext.Consumer;
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
export const SiteContext = createContext(mediacmsConfig(window.MediaCMS).site);
|
||||
export const SiteConsumer = SiteContext.Consumer;
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
import { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
const notifications = mediacmsConfig(window.MediaCMS).notifications.messages;
|
||||
|
||||
const texts = {
|
||||
notifications,
|
||||
notifications,
|
||||
};
|
||||
|
||||
export const TextsContext = createContext(texts);
|
||||
@@ -1,80 +0,0 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
import { BrowserCache } from '../classes/';
|
||||
import { addClassname, removeClassname, supportsSvgAsImg } from '../helpers/';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
import SiteContext from './SiteContext';
|
||||
|
||||
const config = mediacmsConfig(window.MediaCMS);
|
||||
|
||||
function initLogo(logo) {
|
||||
let light = null;
|
||||
let dark = null;
|
||||
|
||||
if (void 0 !== logo.darkMode) {
|
||||
if (supportsSvgAsImg() && void 0 !== logo.darkMode.svg && '' !== logo.darkMode.svg) {
|
||||
dark = logo.darkMode.svg;
|
||||
} else if (void 0 !== logo.darkMode.img && '' !== logo.darkMode.img) {
|
||||
dark = logo.darkMode.img;
|
||||
}
|
||||
}
|
||||
|
||||
if (void 0 !== logo.lightMode) {
|
||||
if (supportsSvgAsImg() && void 0 !== logo.lightMode.svg && '' !== logo.lightMode.svg) {
|
||||
light = logo.lightMode.svg;
|
||||
} else if (void 0 !== logo.lightMode.img && '' !== logo.lightMode.img) {
|
||||
light = logo.lightMode.img;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== light || null !== dark) {
|
||||
if (null === light) {
|
||||
light = dark;
|
||||
} else if (null === dark) {
|
||||
dark = light;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
light,
|
||||
dark,
|
||||
};
|
||||
}
|
||||
|
||||
function initMode(cachedValue, defaultValue) {
|
||||
return 'light' === cachedValue || 'dark' === cachedValue ? cachedValue : defaultValue;
|
||||
}
|
||||
|
||||
export const ThemeContext = createContext();
|
||||
|
||||
export const ThemeProvider = ({ children }) => {
|
||||
const site = useContext(SiteContext);
|
||||
const cache = new BrowserCache('MediaCMS[' + site.id + '][theme]', 86400);
|
||||
const [themeMode, setThemeMode] = useState(initMode(cache.get('mode'), config.theme.mode));
|
||||
const logos = initLogo(config.theme.logo);
|
||||
const [logo, setLogo] = useState(logos[themeMode]);
|
||||
|
||||
const changeMode = () => {
|
||||
setThemeMode('light' === themeMode ? 'dark' : 'light');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if ('dark' === themeMode) {
|
||||
addClassname(document.body, 'dark_theme');
|
||||
} else {
|
||||
removeClassname(document.body, 'dark_theme');
|
||||
}
|
||||
cache.set('mode', themeMode);
|
||||
setLogo(logos[themeMode]);
|
||||
}, [themeMode]);
|
||||
|
||||
const value = {
|
||||
logo,
|
||||
currentThemeMode: themeMode,
|
||||
changeThemeMode: changeMode,
|
||||
themeModeSwitcher: config.theme.switch,
|
||||
};
|
||||
|
||||
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
||||
};
|
||||
|
||||
export const ThemeConsumer = ThemeContext.Consumer;
|
||||
95
frontend/src/static/js/utils/contexts/ThemeContext.tsx
Normal file
95
frontend/src/static/js/utils/contexts/ThemeContext.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import React, { createContext, ReactNode, useContext, useEffect, useState } from 'react';
|
||||
import { GlobalMediaCMS } from '../../types';
|
||||
import { BrowserCache } from '../classes';
|
||||
import { addClassname, removeClassname, supportsSvgAsImg } from '../helpers';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
import SiteContext from './SiteContext';
|
||||
|
||||
const config = mediacmsConfig(window.MediaCMS);
|
||||
|
||||
function initLogo(logo: GlobalMediaCMS['site']['logo']) {
|
||||
let light = null;
|
||||
let dark = null;
|
||||
|
||||
if (void 0 !== logo.darkMode) {
|
||||
if (supportsSvgAsImg() && void 0 !== logo.darkMode.svg && '' !== logo.darkMode.svg) {
|
||||
dark = logo.darkMode.svg;
|
||||
} else if (void 0 !== logo.darkMode.img && '' !== logo.darkMode.img) {
|
||||
dark = logo.darkMode.img;
|
||||
}
|
||||
}
|
||||
|
||||
if (void 0 !== logo.lightMode) {
|
||||
if (supportsSvgAsImg() && void 0 !== logo.lightMode.svg && '' !== logo.lightMode.svg) {
|
||||
light = logo.lightMode.svg;
|
||||
} else if (void 0 !== logo.lightMode.img && '' !== logo.lightMode.img) {
|
||||
light = logo.lightMode.img;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== light || null !== dark) {
|
||||
if (null === light) {
|
||||
light = dark;
|
||||
} else if (null === dark) {
|
||||
dark = light;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
light,
|
||||
dark,
|
||||
};
|
||||
}
|
||||
|
||||
function initMode(cachedValue: string | undefined, defaultValue: GlobalMediaCMS['site']['theme']['mode']) {
|
||||
return 'light' === cachedValue || 'dark' === cachedValue ? cachedValue : defaultValue;
|
||||
}
|
||||
|
||||
export const ThemeContext = createContext({
|
||||
logo: initLogo(config.theme.logo)[config.theme.mode],
|
||||
currentThemeMode: config.theme.mode,
|
||||
changeThemeMode: () => {},
|
||||
themeModeSwitcher: config.theme.switch,
|
||||
});
|
||||
|
||||
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
|
||||
const site = useContext(SiteContext);
|
||||
|
||||
const cache = BrowserCache('MediaCMS[' + site.id + '][theme]', 86400);
|
||||
|
||||
const [themeMode, setThemeMode] = useState(
|
||||
initMode(cache instanceof Error ? undefined : cache.get('mode'), config.theme.mode)
|
||||
);
|
||||
|
||||
const logos = initLogo(config.theme.logo);
|
||||
const [logo, setLogo] = useState(logos[themeMode]);
|
||||
|
||||
const changeMode = () => {
|
||||
setThemeMode('light' === themeMode ? 'dark' : 'light');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if ('dark' === themeMode) {
|
||||
addClassname(document.body, 'dark_theme');
|
||||
} else {
|
||||
removeClassname(document.body, 'dark_theme');
|
||||
}
|
||||
|
||||
if (!(cache instanceof Error)) {
|
||||
cache.set('mode', themeMode);
|
||||
}
|
||||
|
||||
setLogo(logos[themeMode]);
|
||||
}, [themeMode]);
|
||||
|
||||
const value = {
|
||||
logo,
|
||||
currentThemeMode: themeMode,
|
||||
changeThemeMode: changeMode,
|
||||
themeModeSwitcher: config.theme.switch,
|
||||
};
|
||||
|
||||
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
||||
};
|
||||
|
||||
export const ThemeConsumer = ThemeContext.Consumer;
|
||||
@@ -1,22 +0,0 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
|
||||
export const UserContext = createContext();
|
||||
|
||||
const member = mediacmsConfig(window.MediaCMS).member;
|
||||
|
||||
export const UserProvider = ({ children }) => {
|
||||
const value = {
|
||||
isAnonymous: member.is.anonymous,
|
||||
username: member.username,
|
||||
thumbnail: member.thumbnail,
|
||||
userCan: member.can,
|
||||
pages: member.pages,
|
||||
};
|
||||
|
||||
return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
|
||||
};
|
||||
|
||||
export const UserConsumer = UserContext.Consumer;
|
||||
|
||||
export default UserContext;
|
||||
28
frontend/src/static/js/utils/contexts/UserContext.tsx
Normal file
28
frontend/src/static/js/utils/contexts/UserContext.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { createContext, ReactNode } from 'react';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
const member = mediacmsConfig(window.MediaCMS).member;
|
||||
export const UserContext = createContext({
|
||||
isAnonymous: member.is.anonymous,
|
||||
username: member.username,
|
||||
thumbnail: member.thumbnail,
|
||||
userCan: member.can,
|
||||
pages: member.pages,
|
||||
});
|
||||
|
||||
export function UserProvider({ children }: { children: ReactNode }) {
|
||||
const value = {
|
||||
isAnonymous: member.is.anonymous,
|
||||
username: member.username,
|
||||
thumbnail: member.thumbnail,
|
||||
userCan: member.can,
|
||||
pages: member.pages,
|
||||
};
|
||||
|
||||
return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
|
||||
}
|
||||
|
||||
export const UserConsumer = UserContext.Consumer;
|
||||
|
||||
export default UserContext;
|
||||
@@ -1,19 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useBulkActions } from '../hooks/useBulkActions';
|
||||
|
||||
/**
|
||||
* Higher-Order Component that provides bulk actions functionality
|
||||
* to class components via props
|
||||
*/
|
||||
export function withBulkActions(WrappedComponent) {
|
||||
return function WithBulkActionsComponent(props) {
|
||||
const bulkActions = useBulkActions();
|
||||
|
||||
return (
|
||||
<WrappedComponent
|
||||
{...props}
|
||||
bulkActions={bulkActions}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
15
frontend/src/static/js/utils/hoc/withBulkActions.tsx
Normal file
15
frontend/src/static/js/utils/hoc/withBulkActions.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import { useBulkActions } from '../hooks/useBulkActions';
|
||||
|
||||
/**
|
||||
* Higher-Order Component that provides bulk actions functionality
|
||||
* to class components via props
|
||||
*/
|
||||
export function withBulkActions<P extends { bulkActions: ReturnType<typeof useBulkActions> }>(
|
||||
WrappedComponent: React.ComponentType<P>
|
||||
) {
|
||||
return function WithBulkActionsComponent(props: Omit<P, 'bulkActions'>) {
|
||||
const bulkActions = useBulkActions();
|
||||
return <WrappedComponent {...(props as P)} bulkActions={bulkActions} />;
|
||||
};
|
||||
}
|
||||
@@ -18,10 +18,6 @@ jest.mock('../../../src/static/js/utils/classes/', () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/dispatcher.js', () => ({
|
||||
register: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/settings/config', () => ({
|
||||
config: jest.fn(() => jest.requireActual('../../tests-constants').sampleMediaCMSConfig),
|
||||
}));
|
||||
@@ -54,7 +50,7 @@ describe('utils/hooks', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('Returns undefined value when used without a Provider', () => {
|
||||
test('Returns default context value when used without a Provider', () => {
|
||||
let received: any = 'init';
|
||||
|
||||
const Comp: React.FC = () => {
|
||||
@@ -64,7 +60,14 @@ describe('utils/hooks', () => {
|
||||
|
||||
render(<Comp />);
|
||||
|
||||
expect(received).toBe(undefined);
|
||||
expect(received).toStrictEqual({
|
||||
enabledSidebar: true,
|
||||
visibleSidebar: true,
|
||||
visibleMobileSearch: false,
|
||||
setVisibleSidebar: expect.any(Function),
|
||||
toggleMobileSearch: expect.any(Function),
|
||||
toggleSidebar: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
test('Toggle sidebar', () => {
|
||||
|
||||
@@ -12,10 +12,6 @@ jest.mock('../../../src/static/js/utils/classes/', () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/dispatcher.js', () => ({
|
||||
register: jest.fn(),
|
||||
}));
|
||||
|
||||
function getRenderers(ThemeProvider: React.FC<{ children: React.ReactNode }>, useTheme: typeof useThemeHook) {
|
||||
const data: { current: any } = { current: undefined };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user