Fix sidebar styling and remove hacky fixed positioning
This commit is contained in:
parent
b070efce98
commit
1405c881a8
7 changed files with 194 additions and 210 deletions
|
@ -43,6 +43,7 @@
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.15.4",
|
"@fortawesome/free-regular-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.15",
|
"@fortawesome/react-fontawesome": "^0.1.15",
|
||||||
|
"@heroicons/react": "^1.0.4",
|
||||||
"@hot-loader/react-dom": "^16.14.0",
|
"@hot-loader/react-dom": "^16.14.0",
|
||||||
"axios": "^0.21.4",
|
"axios": "^0.21.4",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
|
@ -169,8 +170,8 @@
|
||||||
},
|
},
|
||||||
"styledComponents": {
|
"styledComponents": {
|
||||||
"pure": true,
|
"pure": true,
|
||||||
"displayName": false,
|
"displayName": true,
|
||||||
"fileName": false
|
"fileName": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@3.0.2"
|
"packageManager": "yarn@3.0.2"
|
||||||
|
|
80
resources/scripts/components/admin/Sidebar.tsx
Normal file
80
resources/scripts/components/admin/Sidebar.tsx
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import tw, { css } from 'twin.macro';
|
||||||
|
import styled from 'styled-components/macro';
|
||||||
|
import { withSubComponents } from '@/components/helpers';
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
${tw`w-full flex flex-col px-4`};
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
${tw`h-10 w-full flex flex-row items-center text-neutral-300 cursor-pointer select-none px-4`};
|
||||||
|
${tw`hover:text-neutral-50`};
|
||||||
|
|
||||||
|
& > svg {
|
||||||
|
${tw`h-6 w-6 flex flex-shrink-0`};
|
||||||
|
}
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
${tw`font-header font-medium text-lg whitespace-nowrap leading-none ml-3`};
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active, &.active {
|
||||||
|
${tw`text-neutral-50 bg-neutral-800 rounded`};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Section = styled.div`
|
||||||
|
${tw`h-[18px] font-header font-medium text-xs text-neutral-300 whitespace-nowrap uppercase ml-4 mb-1 select-none`};
|
||||||
|
|
||||||
|
&:not(:first-of-type) {
|
||||||
|
${tw`mt-4`};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const User = styled.div`
|
||||||
|
${tw`h-16 w-full flex items-center bg-neutral-700 justify-center`};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Sidebar = styled.div<{ $collapsed?: boolean }>`
|
||||||
|
${tw`h-screen hidden md:flex flex-col items-center flex-shrink-0 bg-neutral-900 overflow-x-hidden ease-linear`};
|
||||||
|
${tw`transition-[width] duration-150 ease-in`};
|
||||||
|
${tw`w-[17.5rem]`};
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
${tw`h-10 w-full flex flex-row items-center text-neutral-300 cursor-pointer select-none px-8`};
|
||||||
|
${tw`hover:text-neutral-50`};
|
||||||
|
|
||||||
|
& > svg {
|
||||||
|
${tw`transition-none h-6 w-6 flex flex-shrink-0`};
|
||||||
|
}
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
${tw`font-header font-medium text-lg whitespace-nowrap leading-none ml-3`};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${props => props.$collapsed && css`
|
||||||
|
${tw`w-20`};
|
||||||
|
|
||||||
|
${Section} {
|
||||||
|
${tw`invisible`};
|
||||||
|
}
|
||||||
|
|
||||||
|
${Wrapper} > a {
|
||||||
|
${tw`justify-center px-0`};
|
||||||
|
}
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
${tw`justify-center px-4`};
|
||||||
|
}
|
||||||
|
|
||||||
|
& > a > span,
|
||||||
|
${User} > div,
|
||||||
|
${User} > a,
|
||||||
|
${Wrapper} > a > span {
|
||||||
|
${tw`hidden`};
|
||||||
|
}
|
||||||
|
`};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default withSubComponents(Sidebar, { Section, Wrapper, User });
|
9
resources/scripts/components/helpers.ts
Normal file
9
resources/scripts/components/helpers.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { StyledComponent } from 'styled-components/macro';
|
||||||
|
|
||||||
|
export const withSubComponents = <C extends StyledComponent<any, any>, P extends Record<string, any>> (component: C, properties: P): C & P => {
|
||||||
|
Object.keys(properties).forEach((key: keyof P) => {
|
||||||
|
(component as any)[key] = properties[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
return component as C & P;
|
||||||
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||||
|
|
||||||
export function usePersistedState<S = undefined> (key: string, defaultValue: S): [ S | undefined, Dispatch<SetStateAction<S | undefined>> ] {
|
export function usePersistedState<S extends any = undefined> (key: string, defaultValue: S): [ S, Dispatch<SetStateAction<S>> ] {
|
||||||
const [ state, setState ] = useState(
|
const [ state, setState ] = useState(
|
||||||
() => {
|
() => {
|
||||||
try {
|
try {
|
||||||
|
|
9
resources/scripts/plugins/useUserPersistedState.ts
Normal file
9
resources/scripts/plugins/useUserPersistedState.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { useStoreState } from 'easy-peasy';
|
||||||
|
import { usePersistedState } from '@/plugins/usePersistedState';
|
||||||
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
|
|
||||||
|
export default <S extends any = undefined>(key: string, defaultValue: S): [ S, Dispatch<SetStateAction<S>> ] => {
|
||||||
|
const uuid = useStoreState(state => state.user.data!.uuid);
|
||||||
|
|
||||||
|
return usePersistedState(`${uuid}:${key}`, defaultValue);
|
||||||
|
};
|
|
@ -1,7 +1,7 @@
|
||||||
import { State, useStoreState } from 'easy-peasy';
|
import { State, useStoreState } from 'easy-peasy';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom';
|
import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom';
|
||||||
import tw, { styled } from 'twin.macro';
|
import tw from 'twin.macro';
|
||||||
import OverviewContainer from '@/components/admin/overview/OverviewContainer';
|
import OverviewContainer from '@/components/admin/overview/OverviewContainer';
|
||||||
import SettingsContainer from '@/components/admin/settings/SettingsContainer';
|
import SettingsContainer from '@/components/admin/settings/SettingsContainer';
|
||||||
import DatabasesContainer from '@/components/admin/databases/DatabasesContainer';
|
import DatabasesContainer from '@/components/admin/databases/DatabasesContainer';
|
||||||
|
@ -28,249 +28,124 @@ import MountsContainer from '@/components/admin/mounts/MountsContainer';
|
||||||
import NewMountContainer from '@/components/admin/mounts/NewMountContainer';
|
import NewMountContainer from '@/components/admin/mounts/NewMountContainer';
|
||||||
import MountEditContainer from '@/components/admin/mounts/MountEditContainer';
|
import MountEditContainer from '@/components/admin/mounts/MountEditContainer';
|
||||||
import { NotFound } from '@/components/elements/ScreenBlock';
|
import { NotFound } from '@/components/elements/ScreenBlock';
|
||||||
import { usePersistedState } from '@/plugins/usePersistedState';
|
|
||||||
import { ApplicationStore } from '@/state';
|
import { ApplicationStore } from '@/state';
|
||||||
import { AdminContext } from '@/state/admin';
|
import { AdminContext } from '@/state/admin';
|
||||||
import { breakpoint } from '@/theme';
|
import {
|
||||||
|
CogIcon,
|
||||||
const Sidebar = styled.div<{ collapsed?: boolean }>`
|
DatabaseIcon,
|
||||||
${tw`fixed h-screen hidden md:flex flex-col items-center flex-shrink-0 bg-neutral-900 overflow-x-hidden transition-all duration-250 ease-linear`};
|
FolderAddIcon,
|
||||||
${props => props.collapsed ? 'width: 70px' : 'width: 287px'};
|
GlobeIcon,
|
||||||
|
OfficeBuildingIcon,
|
||||||
& > div.header {
|
ReplyIcon,
|
||||||
${tw`h-16 w-full flex flex-col items-center justify-center mt-1 mb-3 select-none cursor-pointer`};
|
ServerIcon,
|
||||||
}
|
TerminalIcon,
|
||||||
|
UserGroupIcon,
|
||||||
& > div.wrapper {
|
UsersIcon,
|
||||||
${tw`w-full flex flex-col px-4`};
|
ViewGridIcon,
|
||||||
|
} from '@heroicons/react/outline';
|
||||||
& > span {
|
import CollapsedIcon from '@/assets/images/pterodactyl.svg';
|
||||||
height: 18px;
|
import Sidebar from '@/components/admin/Sidebar';
|
||||||
${tw`font-header font-medium text-xs text-neutral-300 whitespace-nowrap uppercase ml-4 mb-1 select-none`};
|
import useUserPersistedState from '@/plugins/useUserPersistedState';
|
||||||
${props => props.collapsed && tw`opacity-0`};
|
|
||||||
|
|
||||||
&:not(:first-of-type) {
|
|
||||||
${tw`mt-4`};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
${tw`h-10 w-full flex flex-row items-center text-neutral-300 cursor-pointer select-none`};
|
|
||||||
${props => props.collapsed ? tw`justify-center` : tw`px-4`};
|
|
||||||
|
|
||||||
& > svg {
|
|
||||||
${tw`h-6 w-6 flex flex-shrink-0`};
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
${props => props.collapsed ? tw`hidden` : tw`font-header font-medium text-lg whitespace-nowrap leading-none ml-3`};
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
${tw`text-neutral-50`};
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active, &.active {
|
|
||||||
${tw`text-neutral-50 bg-neutral-800 rounded`};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
${tw`h-10 w-full flex flex-row items-center text-neutral-300 cursor-pointer select-none`};
|
|
||||||
${props => props.collapsed ? tw`justify-center px-4` : tw`px-8`};
|
|
||||||
|
|
||||||
& > svg {
|
|
||||||
${tw`h-6 w-6 flex flex-shrink-0`};
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
${props => props.collapsed ? tw`hidden` : tw`font-header font-medium text-lg whitespace-nowrap leading-none ml-3`};
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
${tw`text-neutral-50`};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > div.user {
|
|
||||||
${tw`h-16 w-full flex items-center bg-neutral-700 justify-center`};
|
|
||||||
|
|
||||||
& > div, a {
|
|
||||||
${props => props.collapsed && tw`hidden`};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Container = styled.div<{ collapsed?: boolean }>`
|
|
||||||
${tw`w-full flex flex-col items-center transition-all duration-250 ease-linear`};
|
|
||||||
${props => props.collapsed ?
|
|
||||||
breakpoint('md')`padding-left: 70px`
|
|
||||||
:
|
|
||||||
breakpoint('md')`padding-left: 287px`};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const AdminRouter = ({ location, match }: RouteComponentProps) => {
|
const AdminRouter = ({ location, match }: RouteComponentProps) => {
|
||||||
const user = useStoreState((state: State<ApplicationStore>) => state.user.data);
|
const email = useStoreState((state: State<ApplicationStore>) => state.user.data!.email);
|
||||||
|
const roleName = useStoreState((state: State<ApplicationStore>) => state.user.data!.roleName);
|
||||||
|
const avatarURL = useStoreState((state: State<ApplicationStore>) => state.user.data!.avatarURL);
|
||||||
const applicationName = useStoreState((state: ApplicationStore) => state.settings.data!.name);
|
const applicationName = useStoreState((state: ApplicationStore) => state.settings.data!.name);
|
||||||
|
|
||||||
const uuid = useStoreState(state => state.user.data!.uuid);
|
const [ collapsed, setCollapsed ] = useUserPersistedState('admin_sidebar_collapsed', false);
|
||||||
const [ collapsed, setCollapsed ] = usePersistedState<boolean>(`${uuid}:admin_sidebar_collapsed`, false);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div css={tw`h-screen w-screen overflow-x-hidden flex flex-col md:flex-row`}>
|
<div css={tw`h-screen flex`}>
|
||||||
<Sidebar collapsed={collapsed}>
|
<Sidebar css={tw`flex-none`} $collapsed={collapsed}>
|
||||||
<div className={'header'} onClick={ () => { setCollapsed(!collapsed); } }>
|
<div
|
||||||
{ !collapsed ?
|
css={tw`h-16 w-full flex flex-col items-center justify-center mt-1 mb-3 select-none cursor-pointer`}
|
||||||
|
onClick={() => setCollapsed(!collapsed)}
|
||||||
|
>
|
||||||
|
{!collapsed ?
|
||||||
<h1 css={tw`text-2xl text-neutral-50 whitespace-nowrap font-medium`}>{applicationName}</h1>
|
<h1 css={tw`text-2xl text-neutral-50 whitespace-nowrap font-medium`}>{applicationName}</h1>
|
||||||
:
|
:
|
||||||
<img src={'/favicons/android-icon-48x48.png'} alt={'Pterodactyl Icon'} />
|
<img src={CollapsedIcon} css={tw`mt-4 w-20`} alt={'Pterodactyl Icon'}/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
<Sidebar.Wrapper>
|
||||||
<div className={'wrapper'}>
|
<Sidebar.Section>Administration</Sidebar.Section>
|
||||||
<span>Administration</span>
|
|
||||||
|
|
||||||
<NavLink to={`${match.url}`} exact>
|
<NavLink to={`${match.url}`} exact>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" /></svg>
|
<OfficeBuildingIcon/><span>Overview</span>
|
||||||
<span>Overview</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink to={`${match.url}/settings`}>
|
<NavLink to={`${match.url}/settings`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" /><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
|
<CogIcon/><span>Settings</span>
|
||||||
<span>Settings</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
<Sidebar.Section>Management</Sidebar.Section>
|
||||||
<span>Management</span>
|
|
||||||
|
|
||||||
<NavLink to={`${match.url}/databases`}>
|
<NavLink to={`${match.url}/databases`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" /></svg>
|
<DatabaseIcon/><span>Databases</span>
|
||||||
<span>Databases</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink to={`${match.url}/locations`}>
|
<NavLink to={`${match.url}/locations`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
<GlobeIcon/><span>Locations</span>
|
||||||
<span>Locations</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink to={`${match.url}/nodes`}>
|
<NavLink to={`${match.url}/nodes`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" /></svg>
|
<ServerIcon/><span>Nodes</span>
|
||||||
<span>Nodes</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink to={`${match.url}/servers`}>
|
<NavLink to={`${match.url}/servers`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" /></svg>
|
<TerminalIcon/><span>Servers</span>
|
||||||
<span>Servers</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink to={`${match.url}/users`}>
|
<NavLink to={`${match.url}/users`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" /></svg>
|
<UsersIcon/><span>Users</span>
|
||||||
<span>Users</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink to={`${match.url}/roles`}>
|
<NavLink to={`${match.url}/roles`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>
|
<UserGroupIcon/><span>Roles</span>
|
||||||
<span>Roles</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
<Sidebar.Section>Service Management</Sidebar.Section>
|
||||||
<span>Service Management</span>
|
|
||||||
|
|
||||||
<NavLink to={`${match.url}/nests`}>
|
<NavLink to={`${match.url}/nests`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" /></svg>
|
<ViewGridIcon/><span>Nests</span>
|
||||||
<span>Nests</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink to={`${match.url}/mounts`}>
|
<NavLink to={`${match.url}/mounts`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" /></svg>
|
<FolderAddIcon/><span>Mounts</span>
|
||||||
<span>Mounts</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</Sidebar.Wrapper>
|
||||||
|
|
||||||
<NavLink to={'/'} css={tw`mt-auto mb-3`}>
|
<NavLink to={'/'} css={tw`mt-auto mb-3`}>
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" css={tw`h-6 w-6`}>
|
<ReplyIcon/><span>Return</span>
|
||||||
<path strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6"/>
|
|
||||||
</svg>
|
|
||||||
<span>Return</span>
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
<Sidebar.User>
|
||||||
<div className={'user'}>
|
{avatarURL &&
|
||||||
<img src={user !== undefined ? user.avatarURL + '?s=64' : ''} alt="Profile Picture" css={tw`h-10 w-10 rounded-full select-none`} />
|
<img src={`${avatarURL}?s=64`} alt="Profile Picture" css={tw`h-10 w-10 rounded-full select-none`}/>
|
||||||
|
}
|
||||||
<div css={tw`flex flex-col ml-3`}>
|
<div css={tw`flex flex-col ml-3`}>
|
||||||
<span css={tw`font-sans font-normal text-sm text-neutral-50 whitespace-nowrap leading-tight select-none`}>{user?.email}</span>
|
<span css={tw`font-sans font-normal text-sm text-neutral-50 whitespace-nowrap leading-tight select-none`}>{email}</span>
|
||||||
<span css={tw`font-header font-normal text-xs text-neutral-300 whitespace-nowrap leading-tight select-none`}>{user?.roleName}</span>
|
<span css={tw`font-header font-normal text-xs text-neutral-300 whitespace-nowrap leading-tight select-none`}>{roleName}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Sidebar.User>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
<div css={tw`flex-1 overflow-x-hidden px-6 pt-6 lg:px-10 lg:pt-8 xl:px-16 xl:pt-12`}>
|
||||||
<Container collapsed={collapsed}>
|
<Switch location={location}>
|
||||||
<div css={tw`md:min-h-screen w-full flex flex-col px-6 md:px-16 pt-6 md:pt-12`} style={{ maxWidth: '86rem' }}>
|
<Route path={`${match.path}`} component={OverviewContainer} exact/>
|
||||||
{/* <TransitionRouter> */}
|
<Route path={`${match.path}/settings`} component={SettingsContainer} exact/>
|
||||||
<Switch location={location}>
|
<Route path={`${match.path}/databases`} component={DatabasesContainer} exact/>
|
||||||
<Route path={`${match.path}`} component={OverviewContainer} exact/>
|
<Route path={`${match.path}/databases/new`} component={NewDatabaseContainer} exact/>
|
||||||
<Route path={`${match.path}/settings`} component={SettingsContainer} exact/>
|
<Route path={`${match.path}/databases/:id`} component={DatabaseEditContainer} exact/>
|
||||||
|
<Route path={`${match.path}/locations`} component={LocationsContainer} exact/>
|
||||||
<Route path={`${match.path}/databases`} component={DatabasesContainer} exact/>
|
<Route path={`${match.path}/locations/:id`} component={LocationEditContainer} exact/>
|
||||||
<Route path={`${match.path}/databases/new`} component={NewDatabaseContainer} exact/>
|
<Route path={`${match.path}/nodes`} component={NodesContainer} exact/>
|
||||||
<Route
|
<Route path={`${match.path}/nodes/new`} component={NewNodeContainer} exact/>
|
||||||
path={`${match.path}/databases/:id`}
|
<Route path={`${match.path}/nodes/:id`} component={NodeRouter}/>
|
||||||
component={DatabaseEditContainer}
|
<Route path={`${match.path}/servers`} component={ServersContainer} exact/>
|
||||||
exact
|
<Route path={`${match.path}/servers/new`} component={NewServerContainer} exact/>
|
||||||
/>
|
<Route path={`${match.path}/servers/:id`} component={ServerRouter}/>
|
||||||
|
<Route path={`${match.path}/users`} component={UsersContainer} exact/>
|
||||||
<Route path={`${match.path}/locations`} component={LocationsContainer} exact/>
|
<Route path={`${match.path}/users/new`} component={NewUserContainer} exact/>
|
||||||
<Route
|
<Route path={`${match.path}/users/:id`} component={UserRouter}/>
|
||||||
path={`${match.path}/locations/:id`}
|
<Route path={`${match.path}/roles`} component={RolesContainer} exact/>
|
||||||
component={LocationEditContainer}
|
<Route path={`${match.path}/roles/:id`} component={RoleEditContainer} exact/>
|
||||||
exact
|
<Route path={`${match.path}/nests`} component={NestsContainer} exact/>
|
||||||
/>
|
<Route path={`${match.path}/nests/:nestId`} component={NestEditContainer} exact/>
|
||||||
|
<Route path={`${match.path}/nests/:nestId/new`} component={NewEggContainer} exact/>
|
||||||
<Route path={`${match.path}/nodes`} component={NodesContainer} exact/>
|
<Route path={`${match.path}/nests/:nestId/eggs/:id`} component={EggRouter}/>
|
||||||
<Route path={`${match.path}/nodes/new`} component={NewNodeContainer} exact/>
|
<Route path={`${match.path}/mounts`} component={MountsContainer} exact/>
|
||||||
<Route
|
<Route path={`${match.path}/mounts/new`} component={NewMountContainer} exact/>
|
||||||
path={`${match.path}/nodes/:id`}
|
<Route path={`${match.path}/mounts/:id`} component={MountEditContainer} exact/>
|
||||||
component={NodeRouter}
|
<Route path={'*'} component={NotFound}/>
|
||||||
/>
|
</Switch>
|
||||||
|
</div>
|
||||||
<Route path={`${match.path}/servers`} component={ServersContainer} exact/>
|
|
||||||
<Route path={`${match.path}/servers/new`} component={NewServerContainer} exact/>
|
|
||||||
<Route
|
|
||||||
path={`${match.path}/servers/:id`}
|
|
||||||
component={ServerRouter}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route path={`${match.path}/users`} component={UsersContainer} exact/>
|
|
||||||
<Route path={`${match.path}/users/new`} component={NewUserContainer} exact/>
|
|
||||||
<Route
|
|
||||||
path={`${match.path}/users/:id`}
|
|
||||||
component={UserRouter}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route path={`${match.path}/roles`} component={RolesContainer} exact/>
|
|
||||||
<Route
|
|
||||||
path={`${match.path}/roles/:id`}
|
|
||||||
component={RoleEditContainer}
|
|
||||||
exact
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route path={`${match.path}/nests`} component={NestsContainer} exact/>
|
|
||||||
<Route
|
|
||||||
path={`${match.path}/nests/:nestId`}
|
|
||||||
component={NestEditContainer}
|
|
||||||
exact
|
|
||||||
/>
|
|
||||||
<Route path={`${match.path}/nests/:nestId/new`} component={NewEggContainer} exact/>
|
|
||||||
<Route
|
|
||||||
path={`${match.path}/nests/:nestId/eggs/:id`}
|
|
||||||
component={EggRouter}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route path={`${match.path}/mounts`} component={MountsContainer} exact/>
|
|
||||||
<Route path={`${match.path}/mounts/new`} component={NewMountContainer} exact/>
|
|
||||||
<Route
|
|
||||||
path={`${match.path}/mounts/:id`}
|
|
||||||
component={MountEditContainer}
|
|
||||||
exact
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route path={'*'} component={NotFound}/>
|
|
||||||
</Switch>
|
|
||||||
{/* </TransitionRouter> */}
|
|
||||||
</div>
|
|
||||||
</Container>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -2215,6 +2215,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@heroicons/react@npm:^1.0.4":
|
||||||
|
version: 1.0.4
|
||||||
|
resolution: "@heroicons/react@npm:1.0.4"
|
||||||
|
peerDependencies:
|
||||||
|
react: ">= 16"
|
||||||
|
checksum: 08f2853a49e51f274f22e8e1bb4e7d8a49456b7eb770447da66fd06ac05bf821ddf5d93170088d61ec44ae66cfbdc877c287861d5a3d22aad1785659502e3a71
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@hot-loader/react-dom@npm:^16.14.0":
|
"@hot-loader/react-dom@npm:^16.14.0":
|
||||||
version: 16.14.0
|
version: 16.14.0
|
||||||
resolution: "@hot-loader/react-dom@npm:16.14.0"
|
resolution: "@hot-loader/react-dom@npm:16.14.0"
|
||||||
|
@ -9942,6 +9951,7 @@ fsevents@^1.2.7:
|
||||||
"@fortawesome/free-regular-svg-icons": ^5.15.4
|
"@fortawesome/free-regular-svg-icons": ^5.15.4
|
||||||
"@fortawesome/free-solid-svg-icons": ^5.15.4
|
"@fortawesome/free-solid-svg-icons": ^5.15.4
|
||||||
"@fortawesome/react-fontawesome": ^0.1.15
|
"@fortawesome/react-fontawesome": ^0.1.15
|
||||||
|
"@heroicons/react": ^1.0.4
|
||||||
"@hot-loader/react-dom": ^16.14.0
|
"@hot-loader/react-dom": ^16.14.0
|
||||||
"@tailwindcss/forms": ^0.3.3
|
"@tailwindcss/forms": ^0.3.3
|
||||||
"@types/chart.js": ^2.9.34
|
"@types/chart.js": ^2.9.34
|
||||||
|
|
Loading…
Reference in a new issue