Add theme

This commit is contained in:
Nicola Benaglia 2025-04-20 09:29:10 +02:00
parent e5c2e73876
commit acfc641663
2 changed files with 176 additions and 165 deletions

View File

@ -1,12 +1,12 @@
import React, { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from 'react';
import { import {
AppsNavBarLeft, AppsNavBarLeft,
AppsNavBarParent, AppsNavBarParent,
AppsNavBarRight, AppsNavBarRight,
} from "./Apps-styles"; } from './Apps-styles';
import NavBack from "../../assets/svgs/NavBack.svg"; import { NavBack } from '../../assets/svgs/NavBack.tsx';
import NavAdd from "../../assets/svgs/NavAdd.svg"; import { NavAdd } from '../../assets/svgs/NavAdd.tsx';
import NavMoreMenu from "../../assets/svgs/NavMoreMenu.svg"; import { NavMoreMenu } from '../../assets/svgs/NavMoreMenu.tsx';
import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import { import {
ButtonBase, ButtonBase,
@ -16,21 +16,22 @@ import {
MenuItem, MenuItem,
Tab, Tab,
Tabs, Tabs,
} from "@mui/material"; useTheme,
} from '@mui/material';
import { import {
executeEvent, executeEvent,
subscribeToEvent, subscribeToEvent,
unsubscribeFromEvent, unsubscribeFromEvent,
} from "../../utils/events"; } from '../../utils/events';
import TabComponent from "./TabComponent"; import TabComponent from './TabComponent';
import PushPinIcon from "@mui/icons-material/PushPin"; import PushPinIcon from '@mui/icons-material/PushPin';
import RefreshIcon from "@mui/icons-material/Refresh"; import RefreshIcon from '@mui/icons-material/Refresh';
import { useRecoilState, useSetRecoilState } from "recoil"; import { useRecoilState, useSetRecoilState } from 'recoil';
import { import {
navigationControllerAtom, navigationControllerAtom,
settingsLocalLastUpdatedAtom, settingsLocalLastUpdatedAtom,
sortablePinnedAppsAtom, sortablePinnedAppsAtom,
} from "../../atoms/global"; } from '../../atoms/global';
export function saveToLocalStorage(key, subKey, newValue) { export function saveToLocalStorage(key, subKey, newValue) {
try { try {
@ -59,14 +60,17 @@ export function saveToLocalStorage(key, subKey, newValue) {
const serializedValue = JSON.stringify(combinedData); const serializedValue = JSON.stringify(combinedData);
localStorage.setItem(key, serializedValue); localStorage.setItem(key, serializedValue);
} catch (error) { } catch (error) {
console.error("Error saving to localStorage:", error); console.error('Error saving to localStorage:', error);
} }
} }
export const AppsNavBarDesktop = ({disableBack}) => { export const AppsNavBarDesktop = ({ disableBack }) => {
const [tabs, setTabs] = useState([]); const [tabs, setTabs] = useState([]);
const [selectedTab, setSelectedTab] = useState(null); const [selectedTab, setSelectedTab] = useState(null);
const [navigationController, setNavigationController] = useRecoilState(navigationControllerAtom) const [navigationController, setNavigationController] = useRecoilState(
navigationControllerAtom
);
const theme = useTheme();
const [isNewTabWindow, setIsNewTabWindow] = useState(false); const [isNewTabWindow, setIsNewTabWindow] = useState(false);
const tabsRef = useRef(null); const tabsRef = useRef(null);
@ -76,7 +80,6 @@ export const AppsNavBarDesktop = ({disableBack}) => {
sortablePinnedAppsAtom sortablePinnedAppsAtom
); );
const setSettingsLocalLastUpdated = useSetRecoilState( const setSettingsLocalLastUpdated = useSetRecoilState(
settingsLocalLastUpdatedAtom settingsLocalLastUpdatedAtom
); );
@ -92,29 +95,26 @@ export const AppsNavBarDesktop = ({disableBack}) => {
useEffect(() => { useEffect(() => {
// Scroll to the last tab whenever the tabs array changes (e.g., when a new tab is added) // Scroll to the last tab whenever the tabs array changes (e.g., when a new tab is added)
if (tabsRef.current) { if (tabsRef.current) {
const tabElements = tabsRef.current.querySelectorAll(".MuiTab-root"); const tabElements = tabsRef.current.querySelectorAll('.MuiTab-root');
if (tabElements.length > 0) { if (tabElements.length > 0) {
const lastTab = tabElements[tabElements.length - 1]; const lastTab = tabElements[tabElements.length - 1];
lastTab.scrollIntoView({ lastTab.scrollIntoView({
behavior: "smooth", behavior: 'smooth',
block: "nearest", block: 'nearest',
inline: "end", inline: 'end',
}); });
} }
} }
}, [tabs.length]); // Dependency on the number of tabs }, [tabs.length]); // Dependency on the number of tabs
const isDisableBackButton = useMemo(() => {
if (disableBack) return true;
const isDisableBackButton = useMemo(()=> { if (selectedTab && navigationController[selectedTab?.tabId]?.hasBack)
if(disableBack) return true return false;
if(selectedTab && navigationController[selectedTab?.tabId]?.hasBack) return false if (selectedTab && !navigationController[selectedTab?.tabId]?.hasBack)
if(selectedTab && !navigationController[selectedTab?.tabId]?.hasBack) return true return true;
return false return false;
}, [navigationController, selectedTab, disableBack]) }, [navigationController, selectedTab, disableBack]);
const setTabsToNav = (e) => { const setTabsToNav = (e) => {
const { tabs, selectedTab, isNewTabWindow } = e.detail?.data; const { tabs, selectedTab, isNewTabWindow } = e.detail?.data;
@ -124,57 +124,61 @@ export const AppsNavBarDesktop = ({disableBack}) => {
}; };
useEffect(() => { useEffect(() => {
subscribeToEvent("setTabsToNav", setTabsToNav); subscribeToEvent('setTabsToNav', setTabsToNav);
return () => { return () => {
unsubscribeFromEvent("setTabsToNav", setTabsToNav); unsubscribeFromEvent('setTabsToNav', setTabsToNav);
}; };
}, []); }, []);
const isSelectedAppPinned = useMemo(() => {
if (selectedTab?.isPrivate) {
const isSelectedAppPinned = useMemo(()=> {
if(selectedTab?.isPrivate){
return !!sortablePinnedApps?.find( return !!sortablePinnedApps?.find(
(item) => (item) =>
item?.privateAppProperties?.name === selectedTab?.privateAppProperties?.name && item?.privateAppProperties?.service === selectedTab?.privateAppProperties?.service && item?.privateAppProperties?.identifier === selectedTab?.privateAppProperties?.identifier item?.privateAppProperties?.name ===
selectedTab?.privateAppProperties?.name &&
item?.privateAppProperties?.service ===
selectedTab?.privateAppProperties?.service &&
item?.privateAppProperties?.identifier ===
selectedTab?.privateAppProperties?.identifier
); );
} else { } else {
return !!sortablePinnedApps?.find( return !!sortablePinnedApps?.find(
(item) => (item) =>
item?.name === selectedTab?.name && item?.service === selectedTab?.service item?.name === selectedTab?.name &&
item?.service === selectedTab?.service
); );
} }
}, [selectedTab,sortablePinnedApps]) }, [selectedTab, sortablePinnedApps]);
return ( return (
<AppsNavBarParent <AppsNavBarParent
sx={{ sx={{
position: "relative", borderRadius: '0px 30px 30px 0px',
flexDirection: "column", flexDirection: 'column',
width: "60px", height: 'unset',
height: "unset", maxHeight: '70vh',
maxHeight: "70vh", padding: '10px',
borderRadius: "0px 30px 30px 0px", position: 'relative',
padding: "10px", width: '60px',
}} }}
> >
<AppsNavBarLeft <AppsNavBarLeft
sx={{ sx={{
flexDirection: "column", flexDirection: 'column',
}} }}
> >
<ButtonBase <ButtonBase
onClick={() => { onClick={() => {
executeEvent("navigateBack", selectedTab?.tabId); executeEvent('navigateBack', selectedTab?.tabId);
}} }}
disabled={isDisableBackButton} disabled={isDisableBackButton}
sx={{ sx={{
opacity: !isDisableBackButton ? 1 : 0.1, opacity: !isDisableBackButton ? 1 : 0.1,
cursor: !isDisableBackButton ? 'pointer': 'default' cursor: !isDisableBackButton ? 'pointer' : 'default',
}} }}
> >
<img src={NavBack} /> <NavBack />
</ButtonBase> </ButtonBase>
<Tabs <Tabs
orientation="vertical" orientation="vertical"
@ -183,11 +187,11 @@ export const AppsNavBarDesktop = ({disableBack}) => {
variant="scrollable" // Make tabs scrollable variant="scrollable" // Make tabs scrollable
scrollButtons={true} scrollButtons={true}
sx={{ sx={{
"& .MuiTabs-indicator": { '& .MuiTabs-indicator': {
backgroundColor: "white", backgroundColor: theme.palette.background.default,
}, },
maxHeight: `320px`, // Ensure the tabs container fits within the available space maxHeight: `320px`, // Ensure the tabs container fits within the available space
overflow: "hidden", // Prevents overflow on small screens overflow: 'hidden', // Prevents overflow on small screens
}} }}
> >
{tabs?.map((tab) => ( {tabs?.map((tab) => (
@ -202,84 +206,83 @@ export const AppsNavBarDesktop = ({disableBack}) => {
/> />
} // Pass custom component } // Pass custom component
sx={{ sx={{
"&.Mui-selected": { '&.Mui-selected': {
color: "white", color: theme.palette.text.primary,
}, },
padding: "0px", padding: '0px',
margin: "0px", margin: '0px',
minWidth: "0px", minWidth: '0px',
width: "50px", width: '50px',
}} }}
/> />
))} ))}
</Tabs> </Tabs>
</AppsNavBarLeft> </AppsNavBarLeft>
{selectedTab && ( {selectedTab && (
<AppsNavBarRight <AppsNavBarRight
sx={{ sx={{
gap: "10px", gap: '10px',
flexDirection: "column", flexDirection: 'column',
}}
>
<ButtonBase
onClick={() => {
setSelectedTab(null);
executeEvent("newTabWindow", {});
}} }}
> >
<img <ButtonBase
style={{ onClick={() => {
height: "40px", setSelectedTab(null);
width: "40px", executeEvent('newTabWindow', {});
}} }}
src={NavAdd} >
/> <NavAdd
</ButtonBase> style={{
<ButtonBase height: '40px',
onClick={(e) => { width: '40px',
if (!selectedTab) return; }}
handleClick(e); />
}} </ButtonBase>
> <ButtonBase
<img onClick={(e) => {
style={{ if (!selectedTab) return;
height: "34px", handleClick(e);
width: "34px",
}} }}
src={NavMoreMenu} >
/> <NavMoreMenu
</ButtonBase> style={{
</AppsNavBarRight> height: '34px',
width: '34px',
}}
/>
</ButtonBase>
</AppsNavBarRight>
)} )}
<Menu <Menu
id="navbar-more-mobile" id="navbar-more-mobile"
anchorEl={anchorEl} anchorEl={anchorEl}
open={open} open={open}
onClose={handleClose} onClose={handleClose}
MenuListProps={{ MenuListProps={{
"aria-labelledby": "basic-button", 'aria-labelledby': 'basic-button',
}} }}
anchorOrigin={{ anchorOrigin={{
vertical: "bottom", vertical: 'bottom',
horizontal: "center", horizontal: 'center',
}} }}
transformOrigin={{ transformOrigin={{
vertical: "top", vertical: 'top',
horizontal: "center", horizontal: 'center',
}} }}
slotProps={{ slotProps={{
paper: { paper: {
sx: { sx: {
backgroundColor: "var(--bg-primary)", backgroundColor: theme.palette.background.default,
color: "#fff", color: theme.palette.text.primary,
width: "148px", width: '148px',
borderRadius: "5px", borderRadius: '5px',
}, },
}, },
}} }}
sx={{ sx={{
marginTop: "10px", marginTop: '10px',
}} }}
> >
<MenuItem <MenuItem
@ -291,13 +294,16 @@ export const AppsNavBarDesktop = ({disableBack}) => {
if (isSelectedAppPinned) { if (isSelectedAppPinned) {
// Remove the selected app if it is pinned // Remove the selected app if it is pinned
if(selectedTab?.isPrivate){ if (selectedTab?.isPrivate) {
updatedApps = prev.filter( updatedApps = prev.filter(
(item) => (item) =>
!( !(
item?.privateAppProperties?.name === selectedTab?.privateAppProperties?.name && item?.privateAppProperties?.name ===
item?.privateAppProperties?.service === selectedTab?.privateAppProperties?.service && selectedTab?.privateAppProperties?.name &&
item?.privateAppProperties?.identifier === selectedTab?.privateAppProperties?.identifier item?.privateAppProperties?.service ===
selectedTab?.privateAppProperties?.service &&
item?.privateAppProperties?.identifier ===
selectedTab?.privateAppProperties?.identifier
) )
); );
} else { } else {
@ -309,21 +315,19 @@ export const AppsNavBarDesktop = ({disableBack}) => {
) )
); );
} }
} else { } else {
// Add the selected app if it is not pinned // Add the selected app if it is not pinned
if(selectedTab?.isPrivate){ if (selectedTab?.isPrivate) {
updatedApps = [ updatedApps = [
...prev, ...prev,
{ {
isPreview: true, isPreview: true,
isPrivate: true, isPrivate: true,
privateAppProperties: { privateAppProperties: {
...(selectedTab?.privateAppProperties || {}) ...(selectedTab?.privateAppProperties || {}),
} },
},
}, ];
];
} else { } else {
updatedApps = [ updatedApps = [
...prev, ...prev,
@ -333,12 +337,11 @@ export const AppsNavBarDesktop = ({disableBack}) => {
}, },
]; ];
} }
} }
saveToLocalStorage( saveToLocalStorage(
"ext_saved_settings", 'ext_saved_settings',
"sortablePinnedApps", 'sortablePinnedApps',
updatedApps updatedApps
); );
return updatedApps; return updatedApps;
@ -350,70 +353,74 @@ export const AppsNavBarDesktop = ({disableBack}) => {
> >
<ListItemIcon <ListItemIcon
sx={{ sx={{
minWidth: "24px !important", minWidth: '24px !important',
marginRight: "5px", marginRight: '5px',
}} }}
> >
<PushPinIcon <PushPinIcon
height={20} height={20}
sx={{ sx={{
color: isSelectedAppPinned ? "var(--danger)" : "rgba(250, 250, 250, 0.5)", color: isSelectedAppPinned
? 'var(--danger)'
: theme.palette.text.primary,
}} }}
/> />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
sx={{ sx={{
"& .MuiTypography-root": { '& .MuiTypography-root': {
fontSize: "12px", fontSize: '12px',
fontWeight: 600, fontWeight: 600,
color: isSelectedAppPinned ? "var(--danger)" : "rgba(250, 250, 250, 0.5)", color: isSelectedAppPinned
? 'var(--danger)'
: theme.palette.text.primary,
}, },
}} }}
primary={`${isSelectedAppPinned ? "Unpin app" : "Pin app"}`} primary={`${isSelectedAppPinned ? 'Unpin app' : 'Pin app'}`}
/> />
</MenuItem> </MenuItem>
<MenuItem <MenuItem
onClick={() => { onClick={() => {
if (selectedTab?.refreshFunc) { if (selectedTab?.refreshFunc) {
selectedTab.refreshFunc(selectedTab?.tabId); selectedTab.refreshFunc(selectedTab?.tabId);
} else { } else {
executeEvent("refreshApp", { executeEvent('refreshApp', {
tabId: selectedTab?.tabId, tabId: selectedTab?.tabId,
}); });
} }
handleClose(); handleClose();
}} }}
> >
<ListItemIcon <ListItemIcon
sx={{ sx={{
minWidth: "24px !important", minWidth: '24px !important',
marginRight: "5px", marginRight: '5px',
}} }}
> >
<RefreshIcon <RefreshIcon
height={20} height={20}
sx={{ sx={{
color: "rgba(250, 250, 250, 0.5)", color: theme.palette.text.primary,
}} }}
/> />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
sx={{ sx={{
"& .MuiTypography-root": { '& .MuiTypography-root': {
fontSize: "12px", fontSize: '12px',
fontWeight: 600, fontWeight: 600,
color: "rgba(250, 250, 250, 0.5)", color: theme.palette.text.primary,
}, },
}} }}
primary="Refresh" primary="Refresh"
/> />
</MenuItem> </MenuItem>
{!selectedTab?.isPrivate && ( {!selectedTab?.isPrivate && (
<MenuItem <MenuItem
onClick={() => { onClick={() => {
executeEvent("copyLink", { executeEvent('copyLink', {
tabId: selectedTab?.tabId, tabId: selectedTab?.tabId,
}); });
handleClose(); handleClose();
@ -421,23 +428,24 @@ export const AppsNavBarDesktop = ({disableBack}) => {
> >
<ListItemIcon <ListItemIcon
sx={{ sx={{
minWidth: "24px !important", minWidth: '24px !important',
marginRight: "5px", marginRight: '5px',
}} }}
> >
<ContentCopyIcon <ContentCopyIcon
height={20} height={20}
sx={{ sx={{
color: "rgba(250, 250, 250, 0.5)", color: theme.palette.text.primary,
}} }}
/> />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
sx={{ sx={{
"& .MuiTypography-root": { '& .MuiTypography-root': {
fontSize: "12px", fontSize: '12px',
fontWeight: 600, fontWeight: 600,
color: "rgba(250, 250, 250, 0.5)", color: theme.palette.text.primary,
}, },
}} }}
primary="Copy link" primary="Copy link"

View File

@ -1,54 +1,57 @@
import { TabParent } from "./Apps-styles"; import { TabParent } from './Apps-styles';
import NavCloseTab from "../../assets/svgs/NavCloseTab.svg"; import { NavCloseTab } from '../../assets/svgs/NavCloseTab.tsx';
import { getBaseApiReact } from "../../App"; import { getBaseApiReact } from '../../App';
import { Avatar, ButtonBase } from "@mui/material"; import { Avatar, ButtonBase, useTheme } from '@mui/material';
import LogoSelected from "../../assets/svgs/LogoSelected.svg"; import LogoSelected from '../../assets/svgs/LogoSelected.svg';
import { executeEvent } from "../../utils/events"; import { executeEvent } from '../../utils/events';
import LockIcon from "@mui/icons-material/Lock"; import LockIcon from '@mui/icons-material/Lock';
const TabComponent = ({ isSelected, app }) => { const TabComponent = ({ isSelected, app }) => {
const theme = useTheme();
return ( return (
<ButtonBase <ButtonBase
onClick={() => { onClick={() => {
if (isSelected) { if (isSelected) {
executeEvent("removeTab", { executeEvent('removeTab', {
data: app, data: app,
}); });
return; return;
} }
executeEvent("setSelectedTab", { executeEvent('setSelectedTab', {
data: app, data: app,
}); });
}} }}
> >
<TabParent <TabParent
sx={{ sx={{
border: isSelected && "1px solid #FFFFFF", borderStyle: isSelected && 'solid',
borderWidth: isSelected && '1px',
borderColor: isSelected && theme.palette.text.primary,
}} }}
> >
{isSelected && ( {isSelected && (
<img <NavCloseTab
style={{ style={{
position: "absolute", position: 'absolute',
top: "-5px", top: '-5px',
right: "-5px", right: '-5px',
zIndex: 1, zIndex: 1,
}} }}
src={NavCloseTab}
/> />
)} )}
{app?.isPrivate && !app?.privateAppProperties?.logo ? ( {app?.isPrivate && !app?.privateAppProperties?.logo ? (
<LockIcon <LockIcon
sx={{ sx={{
height: "28px", height: '28px',
width: "28px", width: '28px',
}} }}
/> />
) : ( ) : (
<Avatar <Avatar
sx={{ sx={{
height: "28px", height: '28px',
width: "28px", width: '28px',
}} }}
alt={app?.name} alt={app?.name}
src={ src={
@ -61,8 +64,8 @@ const TabComponent = ({ isSelected, app }) => {
> >
<img <img
style={{ style={{
width: "28px", width: '28px',
height: "auto", height: 'auto',
}} }}
src={LogoSelected} src={LogoSelected}
alt="center-icon" alt="center-icon"