mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-03-28 08:15:55 +00:00
added labels
This commit is contained in:
parent
4260c148fb
commit
16222b845a
@ -149,7 +149,7 @@ const defaultValues: MyContextInterface = {
|
|||||||
message: "",
|
message: "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export let isMobile = false;
|
export let isMobile = true;
|
||||||
|
|
||||||
const isMobileDevice = () => {
|
const isMobileDevice = () => {
|
||||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
||||||
|
@ -5,7 +5,7 @@ export const sortablePinnedAppsAtom = atom({
|
|||||||
key: 'sortablePinnedAppsFromAtom',
|
key: 'sortablePinnedAppsFromAtom',
|
||||||
default: [{
|
default: [{
|
||||||
name: 'Q-Tube',
|
name: 'Q-Tube',
|
||||||
servic: 'APP'
|
service: 'APP'
|
||||||
}, {
|
}, {
|
||||||
name: 'Q-Mail',
|
name: 'Q-Mail',
|
||||||
service: 'APP'
|
service: 'APP'
|
||||||
|
@ -28,9 +28,17 @@ import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
|||||||
import { Spacer } from "../../common/Spacer";
|
import { Spacer } from "../../common/Spacer";
|
||||||
import { executeEvent } from "../../utils/events";
|
import { executeEvent } from "../../utils/events";
|
||||||
import { AppRating } from "./AppRating";
|
import { AppRating } from "./AppRating";
|
||||||
|
import { settingsLocalLastUpdatedAtom, sortablePinnedAppsAtom } from "../../atoms/global";
|
||||||
|
import { saveToLocalStorage } from "./AppsNavBar";
|
||||||
|
import { useRecoilState, useSetRecoilState } from "recoil";
|
||||||
|
|
||||||
export const AppInfo = ({ app, myName }) => {
|
export const AppInfo = ({ app, myName }) => {
|
||||||
const isInstalled = app?.status?.status === "READY";
|
const isInstalled = app?.status?.status === "READY";
|
||||||
|
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
||||||
|
|
||||||
|
const isSelectedAppPinned = !!sortablePinnedApps?.find((item)=> item?.name === app?.name && item?.service === app?.service)
|
||||||
|
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppsLibraryContainer
|
<AppsLibraryContainer
|
||||||
sx={{
|
sx={{
|
||||||
@ -104,6 +112,56 @@ export const AppInfo = ({ app, myName }) => {
|
|||||||
<AppInfoSnippetRight></AppInfoSnippetRight>
|
<AppInfoSnippetRight></AppInfoSnippetRight>
|
||||||
</AppInfoSnippetContainer>
|
</AppInfoSnippetContainer>
|
||||||
<Spacer height="11px" />
|
<Spacer height="11px" />
|
||||||
|
<Box sx={{
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '20px'
|
||||||
|
}}>
|
||||||
|
<AppDownloadButton
|
||||||
|
onClick={() => {
|
||||||
|
setSortablePinnedApps((prev) => {
|
||||||
|
let updatedApps;
|
||||||
|
|
||||||
|
if (isSelectedAppPinned) {
|
||||||
|
// Remove the selected app if it is pinned
|
||||||
|
updatedApps = prev.filter(
|
||||||
|
(item) => !(item?.name === app?.name && item?.service === app?.service)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Add the selected app if it is not pinned
|
||||||
|
updatedApps = [...prev, {
|
||||||
|
name: app?.name,
|
||||||
|
service: app?.service,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
saveToLocalStorage('ext_saved_settings', 'sortablePinnedApps', updatedApps)
|
||||||
|
return updatedApps;
|
||||||
|
});
|
||||||
|
setSettingsLocalLastUpdated(Date.now())
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#359ff7ff",
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: "320px",
|
||||||
|
height: "29px",
|
||||||
|
opacity: isSelectedAppPinned ? 0.6 : 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AppDownloadButtonText>
|
||||||
|
{!isMobile ? (
|
||||||
|
<>
|
||||||
|
{isSelectedAppPinned ? 'Unpin from dashboard' : 'Pin to dashboard'}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{isSelectedAppPinned ? 'Unpin' : 'Pin'}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</AppDownloadButtonText>
|
||||||
|
</AppDownloadButton>
|
||||||
<AppDownloadButton
|
<AppDownloadButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
executeEvent("addTab", {
|
executeEvent("addTab", {
|
||||||
@ -121,6 +179,8 @@ export const AppInfo = ({ app, myName }) => {
|
|||||||
{isInstalled ? "Open" : "Download"}
|
{isInstalled ? "Open" : "Download"}
|
||||||
</AppDownloadButtonText>
|
</AppDownloadButtonText>
|
||||||
</AppDownloadButton>
|
</AppDownloadButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
</AppsWidthLimiter>
|
</AppsWidthLimiter>
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
<AppsWidthLimiter>
|
<AppsWidthLimiter>
|
||||||
|
@ -12,16 +12,23 @@ import {
|
|||||||
AppInfoUserName,
|
AppInfoUserName,
|
||||||
} from "./Apps-styles";
|
} from "./Apps-styles";
|
||||||
import { Avatar, ButtonBase } from "@mui/material";
|
import { Avatar, ButtonBase } from "@mui/material";
|
||||||
import { getBaseApiReact } from "../../App";
|
import { getBaseApiReact, isMobile } from "../../App";
|
||||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||||
|
|
||||||
import { Spacer } from "../../common/Spacer";
|
import { Spacer } from "../../common/Spacer";
|
||||||
import { executeEvent } from "../../utils/events";
|
import { executeEvent } from "../../utils/events";
|
||||||
import { AppRating } from "./AppRating";
|
import { AppRating } from "./AppRating";
|
||||||
|
import { useRecoilState, useSetRecoilState } from "recoil";
|
||||||
|
import { settingsLocalLastUpdatedAtom, sortablePinnedAppsAtom } from "../../atoms/global";
|
||||||
|
import { saveToLocalStorage } from "./AppsNavBar";
|
||||||
|
|
||||||
export const AppInfoSnippet = ({ app, myName, isFromCategory }) => {
|
export const AppInfoSnippet = ({ app, myName, isFromCategory }) => {
|
||||||
|
|
||||||
const isInstalled = app?.status?.status === 'READY'
|
const isInstalled = app?.status?.status === 'READY'
|
||||||
|
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
||||||
|
|
||||||
|
const isSelectedAppPinned = !!sortablePinnedApps?.find((item)=> item?.name === app?.name && item?.service === app?.service)
|
||||||
|
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
|
||||||
return (
|
return (
|
||||||
<AppInfoSnippetContainer>
|
<AppInfoSnippetContainer>
|
||||||
<AppInfoSnippetLeft>
|
<AppInfoSnippetLeft>
|
||||||
@ -74,6 +81,7 @@ export const AppInfoSnippet = ({ app, myName, isFromCategory }) => {
|
|||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
<AppInfoSnippetMiddle>
|
<AppInfoSnippetMiddle>
|
||||||
|
|
||||||
<ButtonBase onClick={()=> {
|
<ButtonBase onClick={()=> {
|
||||||
if(isFromCategory){
|
if(isFromCategory){
|
||||||
executeEvent("selectedAppInfoCategory", {
|
executeEvent("selectedAppInfoCategory", {
|
||||||
@ -97,7 +105,41 @@ export const AppInfoSnippet = ({ app, myName, isFromCategory }) => {
|
|||||||
<AppRating app={app} myName={myName} />
|
<AppRating app={app} myName={myName} />
|
||||||
</AppInfoSnippetMiddle>
|
</AppInfoSnippetMiddle>
|
||||||
</AppInfoSnippetLeft>
|
</AppInfoSnippetLeft>
|
||||||
<AppInfoSnippetRight>
|
<AppInfoSnippetRight sx={{
|
||||||
|
gap: '10px'
|
||||||
|
}}>
|
||||||
|
{!isMobile && (
|
||||||
|
<AppDownloadButton onClick={()=> {
|
||||||
|
|
||||||
|
setSortablePinnedApps((prev) => {
|
||||||
|
let updatedApps;
|
||||||
|
|
||||||
|
if (isSelectedAppPinned) {
|
||||||
|
// Remove the selected app if it is pinned
|
||||||
|
updatedApps = prev.filter(
|
||||||
|
(item) => !(item?.name === app?.name && item?.service === app?.service)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Add the selected app if it is not pinned
|
||||||
|
updatedApps = [...prev, {
|
||||||
|
name: app?.name,
|
||||||
|
service: app?.service,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
saveToLocalStorage('ext_saved_settings', 'sortablePinnedApps', updatedApps)
|
||||||
|
return updatedApps;
|
||||||
|
});
|
||||||
|
setSettingsLocalLastUpdated(Date.now())
|
||||||
|
}} sx={{
|
||||||
|
backgroundColor: '#359ff7ff',
|
||||||
|
opacity: isSelectedAppPinned ? 0.6 : 1
|
||||||
|
|
||||||
|
}}>
|
||||||
|
<AppDownloadButtonText> {isSelectedAppPinned ? 'Unpin' : 'Pin'}</AppDownloadButtonText>
|
||||||
|
</AppDownloadButton>
|
||||||
|
)}
|
||||||
|
|
||||||
<AppDownloadButton onClick={()=> {
|
<AppDownloadButton onClick={()=> {
|
||||||
|
|
||||||
executeEvent("addTab", {
|
executeEvent("addTab", {
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
AppCircle,
|
AppCircle,
|
||||||
AppCircleContainer,
|
AppCircleContainer,
|
||||||
AppCircleLabel,
|
AppCircleLabel,
|
||||||
|
AppLibrarySubTitle,
|
||||||
AppsContainer,
|
AppsContainer,
|
||||||
AppsParent,
|
AppsParent,
|
||||||
} from "./Apps-styles";
|
} from "./Apps-styles";
|
||||||
@ -12,9 +13,26 @@ import { getBaseApiReact } from "../../App";
|
|||||||
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 { SortablePinnedApps } from "./SortablePinnedApps";
|
import { SortablePinnedApps } from "./SortablePinnedApps";
|
||||||
|
import { Spacer } from "../../common/Spacer";
|
||||||
|
|
||||||
export const AppsHome = ({ setMode, myApp, myWebsite, availableQapps }) => {
|
export const AppsHome = ({ setMode, myApp, myWebsite, availableQapps }) => {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<AppsContainer
|
||||||
|
sx={{
|
||||||
|
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AppLibrarySubTitle
|
||||||
|
|
||||||
|
>
|
||||||
|
Apps Dashboard
|
||||||
|
|
||||||
|
</AppLibrarySubTitle>
|
||||||
|
</AppsContainer>
|
||||||
|
<Spacer height="20px" />
|
||||||
|
|
||||||
<AppsContainer>
|
<AppsContainer>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -32,5 +50,6 @@ export const AppsHome = ({ setMode, myApp, myWebsite, availableQapps }) => {
|
|||||||
<SortablePinnedApps availableQapps={availableQapps} myWebsite={myWebsite} myApp={myApp} />
|
<SortablePinnedApps availableQapps={availableQapps} myWebsite={myWebsite} myApp={myApp} />
|
||||||
|
|
||||||
</AppsContainer>
|
</AppsContainer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
AppCircle,
|
AppCircle,
|
||||||
AppCircleContainer,
|
AppCircleContainer,
|
||||||
AppCircleLabel,
|
AppCircleLabel,
|
||||||
|
AppLibrarySubTitle,
|
||||||
AppsContainer,
|
AppsContainer,
|
||||||
AppsParent,
|
AppsParent,
|
||||||
} from "./Apps-styles";
|
} from "./Apps-styles";
|
||||||
@ -12,30 +13,61 @@ import { getBaseApiReact, isMobile } from "../../App";
|
|||||||
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 { SortablePinnedApps } from "./SortablePinnedApps";
|
import { SortablePinnedApps } from "./SortablePinnedApps";
|
||||||
|
import { Spacer } from "../../common/Spacer";
|
||||||
|
|
||||||
export const AppsHomeDesktop = ({ setMode, myApp, myWebsite, availableQapps }) => {
|
export const AppsHomeDesktop = ({
|
||||||
|
setMode,
|
||||||
|
myApp,
|
||||||
|
myWebsite,
|
||||||
|
availableQapps,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<AppsContainer sx={{
|
<>
|
||||||
gap: '75px',
|
<AppsContainer
|
||||||
justifyContent: 'flex-start'
|
sx={{
|
||||||
}}>
|
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AppLibrarySubTitle
|
||||||
|
sx={{
|
||||||
|
fontSize: "30px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Apps Dashboard
|
||||||
|
</AppLibrarySubTitle>
|
||||||
|
</AppsContainer>
|
||||||
|
<Spacer height="45px" />
|
||||||
|
<AppsContainer
|
||||||
|
sx={{
|
||||||
|
gap: "75px",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setMode("library");
|
setMode("library");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppCircleContainer sx={{
|
<AppCircleContainer
|
||||||
gap: !isMobile ? '10px': '5px'
|
sx={{
|
||||||
}}>
|
gap: !isMobile ? "10px" : "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<AppCircle>
|
<AppCircle>
|
||||||
<Add>+</Add>
|
<Add>+</Add>
|
||||||
</AppCircle>
|
</AppCircle>
|
||||||
<AppCircleLabel>Library</AppCircleLabel>
|
<AppCircleLabel>Library</AppCircleLabel>
|
||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<SortablePinnedApps isDesktop={true} availableQapps={availableQapps} myWebsite={myWebsite} myApp={myApp} />
|
<SortablePinnedApps
|
||||||
|
isDesktop={true}
|
||||||
|
availableQapps={availableQapps}
|
||||||
|
myWebsite={myWebsite}
|
||||||
|
myApp={myApp}
|
||||||
|
/>
|
||||||
</AppsContainer>
|
</AppsContainer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -25,11 +25,13 @@ import IconSearch from "../../assets/svgs/Search.svg";
|
|||||||
import IconClearInput from "../../assets/svgs/ClearInput.svg";
|
import IconClearInput from "../../assets/svgs/ClearInput.svg";
|
||||||
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
|
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
|
||||||
import qappDots from "../../assets/svgs/qappDots.svg";
|
import qappDots from "../../assets/svgs/qappDots.svg";
|
||||||
|
import ReturnSVG from '../../assets/svgs/Return.svg'
|
||||||
|
|
||||||
import { Spacer } from "../../common/Spacer";
|
import { Spacer } from "../../common/Spacer";
|
||||||
import { AppInfoSnippet } from "./AppInfoSnippet";
|
import { AppInfoSnippet } from "./AppInfoSnippet";
|
||||||
import { Virtuoso } from "react-virtuoso";
|
import { Virtuoso } from "react-virtuoso";
|
||||||
import { executeEvent } from "../../utils/events";
|
import { executeEvent } from "../../utils/events";
|
||||||
|
import { ComposeP, MailIconImg, ShowMessageReturnButton } from "../Group/Forum/Mail-styles";
|
||||||
const officialAppList = [
|
const officialAppList = [
|
||||||
"q-tube",
|
"q-tube",
|
||||||
"q-blog",
|
"q-blog",
|
||||||
@ -160,6 +162,15 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
|||||||
</Box>
|
</Box>
|
||||||
</AppsWidthLimiter>
|
</AppsWidthLimiter>
|
||||||
<Spacer height="25px" />
|
<Spacer height="25px" />
|
||||||
|
<ShowMessageReturnButton sx={{
|
||||||
|
padding: '2px'
|
||||||
|
}} onClick={() => {
|
||||||
|
setMode('home')
|
||||||
|
}}>
|
||||||
|
<MailIconImg src={ReturnSVG} />
|
||||||
|
<ComposeP>Return to Apps Dashboard</ComposeP>
|
||||||
|
</ShowMessageReturnButton>
|
||||||
|
<Spacer height="25px" />
|
||||||
{searchedList?.length > 0 ? (
|
{searchedList?.length > 0 ? (
|
||||||
<AppsWidthLimiter>
|
<AppsWidthLimiter>
|
||||||
<StyledVirtuosoContainer sx={{
|
<StyledVirtuosoContainer sx={{
|
||||||
|
@ -44,6 +44,8 @@ import {
|
|||||||
AppsDesktopLibraryHeader,
|
AppsDesktopLibraryHeader,
|
||||||
} from "./AppsDesktop-styles";
|
} from "./AppsDesktop-styles";
|
||||||
import { AppsNavBarDesktop } from "./AppsNavBarDesktop";
|
import { AppsNavBarDesktop } from "./AppsNavBarDesktop";
|
||||||
|
import ReturnSVG from '../../assets/svgs/Return.svg'
|
||||||
|
import { ComposeP, MailIconImg, ShowMessageReturnButton } from "../Group/Forum/Mail-styles";
|
||||||
const officialAppList = [
|
const officialAppList = [
|
||||||
"q-tube",
|
"q-tube",
|
||||||
"q-blog",
|
"q-blog",
|
||||||
@ -217,7 +219,17 @@ export const AppsLibraryDesktop = ({
|
|||||||
width: "90%",
|
width: "90%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Spacer height="90px" />
|
|
||||||
|
<Spacer height="70px" />
|
||||||
|
<ShowMessageReturnButton sx={{
|
||||||
|
padding: '2px'
|
||||||
|
}} onClick={() => {
|
||||||
|
setMode('home')
|
||||||
|
}}>
|
||||||
|
<MailIconImg src={ReturnSVG} />
|
||||||
|
<ComposeP>Return to Apps Dashboard</ComposeP>
|
||||||
|
</ShowMessageReturnButton>
|
||||||
|
<Spacer height="20px" />
|
||||||
{searchedList?.length > 0 ? (
|
{searchedList?.length > 0 ? (
|
||||||
<AppsWidthLimiter>
|
<AppsWidthLimiter>
|
||||||
<StyledVirtuosoContainer
|
<StyledVirtuosoContainer
|
||||||
|
@ -7,13 +7,28 @@ import {
|
|||||||
import NavBack from "../../assets/svgs/NavBack.svg";
|
import NavBack from "../../assets/svgs/NavBack.svg";
|
||||||
import NavAdd from "../../assets/svgs/NavAdd.svg";
|
import NavAdd from "../../assets/svgs/NavAdd.svg";
|
||||||
import NavMoreMenu from "../../assets/svgs/NavMoreMenu.svg";
|
import NavMoreMenu from "../../assets/svgs/NavMoreMenu.svg";
|
||||||
import { ButtonBase, ListItemIcon, ListItemText, Menu, MenuItem, Tab, Tabs } from "@mui/material";
|
import {
|
||||||
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
|
ButtonBase,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemText,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
Tab,
|
||||||
|
Tabs,
|
||||||
|
} from "@mui/material";
|
||||||
|
import {
|
||||||
|
executeEvent,
|
||||||
|
subscribeToEvent,
|
||||||
|
unsubscribeFromEvent,
|
||||||
|
} 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 { settingsLocalLastUpdatedAtom, sortablePinnedAppsAtom } from "../../atoms/global";
|
import {
|
||||||
|
settingsLocalLastUpdatedAtom,
|
||||||
|
sortablePinnedAppsAtom,
|
||||||
|
} from "../../atoms/global";
|
||||||
|
|
||||||
export function saveToLocalStorage(key, subKey, newValue) {
|
export function saveToLocalStorage(key, subKey, newValue) {
|
||||||
try {
|
try {
|
||||||
@ -28,13 +43,13 @@ export function saveToLocalStorage(key, subKey, newValue) {
|
|||||||
combinedData = {
|
combinedData = {
|
||||||
...parsedData,
|
...parsedData,
|
||||||
timestamp: Date.now(), // Update the root timestamp
|
timestamp: Date.now(), // Update the root timestamp
|
||||||
[subKey]: newValue // Assuming the data is an array
|
[subKey]: newValue, // Assuming the data is an array
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// If no existing data, just use the new data under the subKey
|
// If no existing data, just use the new data under the subKey
|
||||||
combinedData = {
|
combinedData = {
|
||||||
timestamp: Date.now(), // Set the initial root timestamp
|
timestamp: Date.now(), // Set the initial root timestamp
|
||||||
[subKey]: newValue
|
[subKey]: newValue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,22 +57,24 @@ 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 AppsNavBar = () => {
|
export const AppsNavBar = () => {
|
||||||
const [tabs, setTabs] = useState([])
|
const [tabs, setTabs] = useState([]);
|
||||||
const [selectedTab, setSelectedTab] = useState(null)
|
const [selectedTab, setSelectedTab] = useState(null);
|
||||||
const [isNewTabWindow, setIsNewTabWindow] = useState(false)
|
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
||||||
const tabsRef = useRef(null);
|
const tabsRef = useRef(null);
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(
|
||||||
|
sortablePinnedAppsAtom
|
||||||
|
);
|
||||||
|
|
||||||
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
|
const setSettingsLocalLastUpdated = useSetRecoilState(
|
||||||
|
settingsLocalLastUpdatedAtom
|
||||||
|
);
|
||||||
|
|
||||||
const handleClick = (event) => {
|
const handleClick = (event) => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
@ -70,20 +87,24 @@ export const AppsNavBar = () => {
|
|||||||
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({ behavior: 'smooth', block: 'nearest', inline: 'end' });
|
lastTab.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "nearest",
|
||||||
|
inline: "end",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [tabs.length]); // Dependency on the number of tabs
|
}, [tabs.length]); // Dependency on the number of tabs
|
||||||
|
|
||||||
const setTabsToNav = (e) => {
|
const setTabsToNav = (e) => {
|
||||||
const {tabs, selectedTab, isNewTabWindow} = e.detail?.data;
|
const { tabs, selectedTab, isNewTabWindow } = e.detail?.data;
|
||||||
|
|
||||||
setTabs([...tabs])
|
setTabs([...tabs]);
|
||||||
setSelectedTab(!selectedTab ? nulll : {...selectedTab})
|
setSelectedTab(!selectedTab ? nulll : { ...selectedTab });
|
||||||
setIsNewTabWindow(isNewTabWindow)
|
setIsNewTabWindow(isNewTabWindow);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -94,70 +115,94 @@ export const AppsNavBar = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const isSelectedAppPinned = !!sortablePinnedApps?.find(
|
||||||
const isSelectedAppPinned = !!sortablePinnedApps?.find((item)=> item?.name === selectedTab?.name && item?.service === selectedTab?.service)
|
(item) =>
|
||||||
|
item?.name === selectedTab?.name && item?.service === selectedTab?.service
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<AppsNavBarParent>
|
<AppsNavBarParent>
|
||||||
<AppsNavBarLeft>
|
<AppsNavBarLeft>
|
||||||
<ButtonBase onClick={()=> {
|
<ButtonBase
|
||||||
executeEvent("navigateBack", {
|
onClick={() => {
|
||||||
});
|
executeEvent("navigateBack", {});
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<img src={NavBack} />
|
<img src={NavBack} />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
<Tabs
|
<Tabs
|
||||||
ref={tabsRef}
|
ref={tabsRef}
|
||||||
aria-label="basic tabs example"
|
aria-label="basic tabs example"
|
||||||
variant="scrollable" // Make tabs scrollable
|
variant="scrollable" // Make tabs scrollable
|
||||||
scrollButtons={false}
|
scrollButtons={false}
|
||||||
sx={{
|
|
||||||
"& .MuiTabs-indicator": {
|
|
||||||
backgroundColor: "white",
|
|
||||||
},
|
|
||||||
maxWidth: `calc(100vw - 150px)`, // Ensure the tabs container fits within the available space
|
|
||||||
overflow: 'hidden', // Prevents overflow on small screens
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{tabs?.map((tab) => (
|
|
||||||
<Tab
|
|
||||||
key={tab.tabId}
|
|
||||||
label={<TabComponent isSelected={tab?.tabId === selectedTab?.tabId && !isNewTabWindow} app={tab} />} // Pass custom component
|
|
||||||
sx={{
|
sx={{
|
||||||
"&.Mui-selected": {
|
"& .MuiTabs-indicator": {
|
||||||
color: "white",
|
backgroundColor: "white",
|
||||||
},
|
},
|
||||||
padding: '0px',
|
maxWidth: `calc(100vw - 150px)`, // Ensure the tabs container fits within the available space
|
||||||
margin: '0px',
|
overflow: "hidden", // Prevents overflow on small screens
|
||||||
minWidth: '0px',
|
|
||||||
width: '50px'
|
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
))}
|
{tabs?.map((tab) => (
|
||||||
</Tabs>
|
<Tab
|
||||||
|
key={tab.tabId}
|
||||||
|
label={
|
||||||
|
<TabComponent
|
||||||
|
isSelected={
|
||||||
|
tab?.tabId === selectedTab?.tabId && !isNewTabWindow
|
||||||
|
}
|
||||||
|
app={tab}
|
||||||
|
/>
|
||||||
|
} // Pass custom component
|
||||||
|
sx={{
|
||||||
|
"&.Mui-selected": {
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
padding: "0px",
|
||||||
|
margin: "0px",
|
||||||
|
minWidth: "0px",
|
||||||
|
width: "50px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
</AppsNavBarLeft>
|
</AppsNavBarLeft>
|
||||||
<AppsNavBarRight sx={{
|
{selectedTab && (
|
||||||
gap: '10px'
|
<AppsNavBarRight
|
||||||
}}>
|
sx={{
|
||||||
<ButtonBase onClick={()=> {
|
gap: "10px",
|
||||||
setSelectedTab(null)
|
}}
|
||||||
executeEvent("newTabWindow", {
|
>
|
||||||
});
|
<ButtonBase
|
||||||
}}>
|
onClick={() => {
|
||||||
<img style={{
|
setSelectedTab(null);
|
||||||
height: '40px',
|
executeEvent("newTabWindow", {});
|
||||||
width: '40px'
|
}}
|
||||||
}} src={NavAdd} />
|
>
|
||||||
</ButtonBase>
|
<img
|
||||||
<ButtonBase onClick={(e)=> {
|
style={{
|
||||||
if(!selectedTab) return
|
height: "40px",
|
||||||
handleClick(e)
|
width: "40px",
|
||||||
}}>
|
}}
|
||||||
<img style={{
|
src={NavAdd}
|
||||||
height: '34px',
|
/>
|
||||||
width: '34px'
|
</ButtonBase>
|
||||||
}} src={NavMoreMenu} />
|
<ButtonBase
|
||||||
</ButtonBase>
|
onClick={(e) => {
|
||||||
</AppsNavBarRight>
|
if (!selectedTab) return;
|
||||||
|
handleClick(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{
|
||||||
|
height: "34px",
|
||||||
|
width: "34px",
|
||||||
|
}}
|
||||||
|
src={NavMoreMenu}
|
||||||
|
/>
|
||||||
|
</ButtonBase>
|
||||||
|
</AppsNavBarRight>
|
||||||
|
)}
|
||||||
|
|
||||||
<Menu
|
<Menu
|
||||||
id="navbar-more-mobile"
|
id="navbar-more-mobile"
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
@ -167,102 +212,123 @@ export const AppsNavBar = () => {
|
|||||||
"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: 'var(--bg-primary)',
|
color: "#fff",
|
||||||
color: '#fff',
|
width: "148px",
|
||||||
width: '148px',
|
borderRadius: "5px",
|
||||||
borderRadius: '5px'
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
marginTop: '10px'
|
marginTop: "10px",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
>
|
>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!selectedTab) return;
|
if (!selectedTab) return;
|
||||||
|
|
||||||
setSortablePinnedApps((prev) => {
|
|
||||||
let updatedApps;
|
|
||||||
|
|
||||||
if (isSelectedAppPinned) {
|
|
||||||
// Remove the selected app if it is pinned
|
|
||||||
updatedApps = prev.filter(
|
|
||||||
(item) => !(item?.name === selectedTab?.name && item?.service === selectedTab?.service)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Add the selected app if it is not pinned
|
|
||||||
updatedApps = [...prev, {
|
|
||||||
name: selectedTab?.name,
|
|
||||||
service: selectedTab?.service,
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
saveToLocalStorage('ext_saved_settings', 'sortablePinnedApps', updatedApps)
|
|
||||||
return updatedApps;
|
|
||||||
});
|
|
||||||
setSettingsLocalLastUpdated(Date.now())
|
|
||||||
|
|
||||||
handleClose();
|
setSortablePinnedApps((prev) => {
|
||||||
}}
|
let updatedApps;
|
||||||
>
|
|
||||||
<ListItemIcon sx={{
|
if (isSelectedAppPinned) {
|
||||||
|
// Remove the selected app if it is pinned
|
||||||
minWidth: '24px !important',
|
updatedApps = prev.filter(
|
||||||
marginRight: '5px'
|
(item) =>
|
||||||
}}>
|
!(
|
||||||
<PushPinIcon height={20} sx={{
|
item?.name === selectedTab?.name &&
|
||||||
color: isSelectedAppPinned ? 'red' : "rgba(250, 250, 250, 0.5)",
|
item?.service === selectedTab?.service
|
||||||
|
)
|
||||||
}} />
|
);
|
||||||
</ListItemIcon>
|
} else {
|
||||||
<ListItemText sx={{
|
// Add the selected app if it is not pinned
|
||||||
"& .MuiTypography-root": {
|
updatedApps = [
|
||||||
fontSize: "12px",
|
...prev,
|
||||||
fontWeight: 600,
|
{
|
||||||
color: isSelectedAppPinned ? 'red' : "rgba(250, 250, 250, 0.5)"
|
name: selectedTab?.name,
|
||||||
|
service: selectedTab?.service,
|
||||||
},
|
},
|
||||||
}} primary={`${isSelectedAppPinned ? 'Unpin app' : 'Pin app'}`} />
|
];
|
||||||
</MenuItem>
|
}
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
saveToLocalStorage(
|
||||||
executeEvent('refreshApp', {
|
"ext_saved_settings",
|
||||||
tabId: selectedTab?.tabId
|
"sortablePinnedApps",
|
||||||
})
|
updatedApps
|
||||||
|
);
|
||||||
|
return updatedApps;
|
||||||
|
});
|
||||||
|
setSettingsLocalLastUpdated(Date.now());
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemIcon sx={{
|
<ListItemIcon
|
||||||
|
sx={{
|
||||||
minWidth: '24px !important',
|
minWidth: "24px !important",
|
||||||
marginRight: '5px'
|
marginRight: "5px",
|
||||||
}}>
|
}}
|
||||||
<RefreshIcon height={20} sx={{
|
>
|
||||||
color:"rgba(250, 250, 250, 0.5)"
|
<PushPinIcon
|
||||||
}} />
|
height={20}
|
||||||
|
sx={{
|
||||||
|
color: isSelectedAppPinned ? "red" : "rgba(250, 250, 250, 0.5)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText sx={{
|
<ListItemText
|
||||||
"& .MuiTypography-root": {
|
sx={{
|
||||||
fontSize: "12px",
|
"& .MuiTypography-root": {
|
||||||
fontWeight: 600,
|
fontSize: "12px",
|
||||||
color:"rgba(250, 250, 250, 0.5)"
|
fontWeight: 600,
|
||||||
},
|
color: isSelectedAppPinned ? "red" : "rgba(250, 250, 250, 0.5)",
|
||||||
}} primary="Refresh" />
|
},
|
||||||
|
}}
|
||||||
|
primary={`${isSelectedAppPinned ? "Unpin app" : "Pin app"}`}
|
||||||
|
/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Menu>
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
executeEvent("refreshApp", {
|
||||||
|
tabId: selectedTab?.tabId,
|
||||||
|
});
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemIcon
|
||||||
|
sx={{
|
||||||
|
minWidth: "24px !important",
|
||||||
|
marginRight: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RefreshIcon
|
||||||
|
height={20}
|
||||||
|
sx={{
|
||||||
|
color: "rgba(250, 250, 250, 0.5)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
sx={{
|
||||||
|
"& .MuiTypography-root": {
|
||||||
|
fontSize: "12px",
|
||||||
|
fontWeight: 600,
|
||||||
|
color: "rgba(250, 250, 250, 0.5)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
primary="Refresh"
|
||||||
|
/>
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
</AppsNavBarParent>
|
</AppsNavBarParent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user