/******************************************************************************** * Copyright (c) 2020 TypeFox and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. * * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ import { FunctionComponent, PropsWithChildren, useContext, useRef, useState } from 'react'; import { Avatar, Button, IconButton, Link, Menu, MenuItem, Typography } from '@mui/material'; import { useLocation, useNavigate, Link as RouteLink } from 'react-router'; import { UserAvatar } from '../pages/user/avatar'; import { UserSettingsRoutes } from '../pages/user/user-settings-routes'; import { alpha, styled, Theme } from '@mui/material/styles'; import { MainContext } from '../context'; import { KbdKey } from '../components/kbd-key'; import { useShortcut } from '../hooks/use-shortcut'; import { focusOutline } from '../components/page-primitives'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import GitHubIcon from '@mui/icons-material/GitHub'; import SettingsIcon from '@mui/icons-material/Settings'; import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; import LogoutIcon from '@mui/icons-material/Logout'; import AccountBoxIcon from '@mui/icons-material/AccountBox'; import PublishIcon from '@mui/icons-material/Publish'; import MenuBookIcon from '@mui/icons-material/MenuBook'; import InfoIcon from '@mui/icons-material/Info'; import { AdminDashboardRoutes } from '../pages/admin-dashboard/admin-dashboard-routes'; import { LogoutForm } from '../pages/user/logout'; import { LoginComponent } from './login'; // Shared destinations so a menu item's link, its keyboard shortcut, and its hint // can't drift apart. External docs open in the same tab, matching the link click. const DOCS_URL = 'https://github.com/eclipse/openvsx/wiki'; //-------------------- Mobile View --------------------// // eslint-disable-next-line react-refresh/only-export-components export const itemIcon = { mr: 1, width: '16px', height: '16px' }; export const MenuItemText: FunctionComponent = ({ children }) => { return ( {children} ); }; export const MobileUserAvatar: FunctionComponent = () => { const { user } = useContext(MainContext); const logoutFormRef = useRef(null); const anchorRef = useRef(null); const [open, setOpen] = useState(false); const close = () => setOpen(false); if (!user) { return null; } return ( <> setOpen(true)} aria-haspopup='menu' aria-expanded={open}> {user.loginName} {user.loginName} Settings {user.role === 'admin' ? ( Admin Dashboard ) : null} logoutFormRef.current?.submit()}> Log Out ); }; export const MobileMenuContent: FunctionComponent = () => { const location = useLocation(); const { user, loginProviders } = useContext(MainContext); return ( <> {loginProviders && (user ? ( ) : ( ( Log In )} /> ))} {loginProviders && !location.pathname.startsWith(UserSettingsRoutes.ROOT) && ( Publish Extension )} Source Code Documentation About This Service ); }; //-------------------- Default View --------------------// // eslint-disable-next-line react-refresh/only-export-components export const headerItem = ({ theme }: { theme: Theme }) => ({ margin: theme.spacing(0, 0.5), padding: theme.spacing(1, 1.5), // Inherited color so the items follow the nav's content color over page // bands; opacity stands in for the secondary/primary text pair. color: 'inherit', opacity: 0.78, textDecoration: 'none', fontSize: '0.875rem', fontFamily: theme.typography.fontFamily, fontWeight: 500, letterSpacing: 0, borderRadius: `${theme.shape.borderRadius}px`, transition: 'background 0.14s, opacity 0.14s', '&:hover': { opacity: 1, backgroundColor: 'color-mix(in srgb, currentcolor 8%, transparent)', textDecoration: 'none' }, ...focusOutline(theme) }); // eslint-disable-next-line react-refresh/only-export-components export const MenuLink = styled(Link)(headerItem); // eslint-disable-next-line react-refresh/only-export-components export const MenuRouteLink = styled(RouteLink)(headerItem); export const DefaultMenuContent: FunctionComponent = () => { const { user, loginProviders } = useContext(MainContext); const navigate = useNavigate(); // Register each shortcut next to the control it drives, sharing the same // destination so the hint, the click, and the keypress stay in sync. useShortcut({ key: 'd', label: 'Documentation', order: 2, callback: () => window.location.assign(DOCS_URL) }); useShortcut({ key: 'p', label: 'Publish', order: 3, callback: () => navigate(UserSettingsRoutes.EXTENSIONS), enabled: !!loginProviders }); return ( <> Documentation d About {loginProviders && ( <> {user ? ( ) : ( { // Inherited color + opacity (not a palette gray) so the dimming // follows the nav's content color over tinted chromes, like headerItem. const loginButtonSx = { opacity: 0.78, transition: 'opacity 0.14s', '&:hover': { opacity: 1 } }; if (href) { return ( ); } else { return ( ); } }} /> )} )} ); };