Add basic navigation bar
This commit is contained in:
parent
c7355975ad
commit
9cb8020dbe
12 changed files with 121 additions and 161 deletions
|
@ -1,6 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "pterodactyl-panel",
|
"name": "pterodactyl-panel",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^1.2.19",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
||||||
|
"@fortawesome/react-fontawesome": "^0.1.4",
|
||||||
"@hot-loader/react-dom": "^16.8.6",
|
"@hot-loader/react-dom": "^16.8.6",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"brace": "^0.11.1",
|
"brace": "^0.11.1",
|
||||||
|
|
|
@ -1,117 +1,38 @@
|
||||||
.nav {
|
#navigation {
|
||||||
@apply .bg-primary-600 .border-b .border-t .border-primary-700;
|
@apply .w-full .bg-neutral-900 .shadow-md;
|
||||||
height: 56px;
|
|
||||||
|
|
||||||
& .logo {
|
& > div {
|
||||||
@apply .mr-8 .font-sans .font-thin .text-3xl .text-white .inline-block;
|
@apply .mx-auto .w-full .flex .items-center;
|
||||||
|
|
||||||
& a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@screen xsx {
|
|
||||||
@apply .hidden;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& .search-box {
|
& #logo {
|
||||||
@apply .mr-2;
|
@apply .flex-1;
|
||||||
|
|
||||||
& > .search-input {
|
|
||||||
@apply .text-sm .p-2 .ml-8 .rounded .border .border-primary-600 .bg-white .text-neutral-900 .w-96;
|
|
||||||
transition: border 150ms ease-in;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
@apply .border-primary-700;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.has-search-results {
|
|
||||||
@apply .border-b-0 .rounded-b-none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .search-results {
|
|
||||||
@apply .absolute .bg-white .border .border-primary-700 .border-t-0 .rounded .rounded-t-none .p-2 .ml-8 .z-50 .w-96;
|
|
||||||
|
|
||||||
& a {
|
|
||||||
@apply .block .no-underline .p-2 .rounded;
|
|
||||||
|
|
||||||
&:not(.no-hover):hover {
|
|
||||||
@apply .bg-neutral-50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .menu {
|
|
||||||
@apply .flex .h-full .items-center;
|
|
||||||
|
|
||||||
& > a {
|
& > a {
|
||||||
transition: background-color 150ms linear;
|
@apply .text-2xl .font-header .px-4 .no-underline .text-neutral-200;
|
||||||
@apply .block .flex .self-stretch .items-center .no-underline .text-white .font-light .text-sm .px-5;
|
transition: color 150ms linear;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@apply .bg-primary-700;
|
@apply .text-neutral-100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .right-navigation {
|
||||||
|
@apply .flex .h-full .items-center .justify-center;
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
@apply .flex .items-center .h-full .no-underline .text-neutral-300 .px-6;
|
||||||
|
transition: background-color 150ms linear, color 150ms linear, box-shadow 150ms ease-in;
|
||||||
|
|
||||||
|
&.active, &:hover {
|
||||||
|
@apply .text-neutral-100 .bg-black;
|
||||||
|
box-shadow: inset 0 -2px config('colors.cyan-700');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
box-shadow: inset 0 -2px config('colors.cyan-500');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidenav {
|
|
||||||
ul {
|
|
||||||
@apply .list-reset;
|
|
||||||
|
|
||||||
& li {
|
|
||||||
@apply .block;
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
transition: border-left-color 250ms linear, color 250ms linear;
|
|
||||||
@apply .block .px-4 .py-3 .border-l-3 .border-neutral-100 .no-underline .text-neutral-400 .font-medium;
|
|
||||||
|
|
||||||
&:hover, &.router-link-exact-active, &.router-link-active {
|
|
||||||
@apply .text-neutral-800;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.router-link-exact-active, &.router-link-active {
|
|
||||||
@apply .border-primary-500 .cursor-default;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner {
|
|
||||||
@apply .border-none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Because of how the router works the first sidebar link is always active
|
|
||||||
* since that is the container for all of the server things. Override the
|
|
||||||
* style for active links if its the first one and not an exact route match.
|
|
||||||
*/
|
|
||||||
&:first-of-type > a {
|
|
||||||
&.router-link-active:not(.router-link-exact-active) {
|
|
||||||
@apply .border-neutral-100 .text-neutral-400 .cursor-pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
.sidenav {
|
|
||||||
@apply .py-2;
|
|
||||||
|
|
||||||
a {
|
|
||||||
@apply .block .py-3 .px-6 .text-neutral-900 .no-underline .border .border-transparent;
|
|
||||||
|
|
||||||
&:hover, &.router-link-exact-active {
|
|
||||||
@apply .border-neutral-400 .bg-neutral-50;
|
|
||||||
|
|
||||||
border-left: 1px solid transparent;
|
|
||||||
border-right: 1px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.router-link-exact-active + a:hover {
|
|
||||||
border-top: 1px solid transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
@ -2,11 +2,11 @@ import * as React from 'react';
|
||||||
import { hot } from 'react-hot-loader/root';
|
import { hot } from 'react-hot-loader/root';
|
||||||
import { BrowserRouter as Router, Route } from 'react-router-dom';
|
import { BrowserRouter as Router, Route } from 'react-router-dom';
|
||||||
import AuthenticationRouter from '@/routers/AuthenticationRouter';
|
import AuthenticationRouter from '@/routers/AuthenticationRouter';
|
||||||
import AccountRouter from '@/routers/AccountRouter';
|
|
||||||
import ServerOverviewContainer from '@/components/ServerOverviewContainer';
|
import ServerOverviewContainer from '@/components/ServerOverviewContainer';
|
||||||
import { StoreProvider } from 'easy-peasy';
|
import { StoreProvider } from 'easy-peasy';
|
||||||
import { store } from '@/state';
|
import { store } from '@/state';
|
||||||
import TransitionRouter from '@/TransitionRouter';
|
import TransitionRouter from '@/TransitionRouter';
|
||||||
|
import DashboardRouter from '@/routers/DashboardRouter';
|
||||||
|
|
||||||
interface WindowWithUser extends Window {
|
interface WindowWithUser extends Window {
|
||||||
PterodactylUser?: {
|
PterodactylUser?: {
|
||||||
|
@ -41,9 +41,8 @@ const App = () => {
|
||||||
<Router basename={'/'}>
|
<Router basename={'/'}>
|
||||||
<div className={'mx-auto w-auto'}>
|
<div className={'mx-auto w-auto'}>
|
||||||
<TransitionRouter basename={'/'}>
|
<TransitionRouter basename={'/'}>
|
||||||
<Route exact path="/" component={ServerOverviewContainer}/>
|
<Route path="/" component={DashboardRouter}/>
|
||||||
<Route path="/auth" component={AuthenticationRouter}/>
|
<Route path="/auth" component={AuthenticationRouter}/>
|
||||||
<Route path="/account" component={AccountRouter}/>
|
|
||||||
</TransitionRouter>
|
</TransitionRouter>
|
||||||
</div>
|
</div>
|
||||||
</Router>
|
</Router>
|
||||||
|
|
35
resources/scripts/components/NavigationBar.tsx
Normal file
35
resources/scripts/components/NavigationBar.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Link, NavLink } from 'react-router-dom';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { faLayerGroup } from '@fortawesome/free-solid-svg-icons/faLayerGroup';
|
||||||
|
import { faUserCircle } from '@fortawesome/free-solid-svg-icons/faUserCircle';
|
||||||
|
import { faSignOutAlt } from '@fortawesome/free-solid-svg-icons/faSignOutAlt';
|
||||||
|
import { faSwatchbook } from '@fortawesome/free-solid-svg-icons/faSwatchbook';
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div id={'navigation'}>
|
||||||
|
<div className={'mx-auto w-full flex items-center'} style={{ maxWidth: '1200px', height: '3.5rem' }}>
|
||||||
|
<div id={'logo'}>
|
||||||
|
<Link to={'/'}>
|
||||||
|
Pterodactyl
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className={'right-navigation'}>
|
||||||
|
<NavLink to={'/'} exact={true}>
|
||||||
|
<FontAwesomeIcon icon={faLayerGroup}/>
|
||||||
|
</NavLink>
|
||||||
|
<NavLink to={'/account'}>
|
||||||
|
<FontAwesomeIcon icon={faUserCircle}/>
|
||||||
|
</NavLink>
|
||||||
|
{process.env.NODE_ENV !== 'production' &&
|
||||||
|
<NavLink to={'/design'}>
|
||||||
|
<FontAwesomeIcon icon={faSwatchbook}/>
|
||||||
|
</NavLink>
|
||||||
|
}
|
||||||
|
<NavLink to={'/auth/logout'}>
|
||||||
|
<FontAwesomeIcon icon={faSignOutAlt}/>
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import ContentBox from '@/components/elements/ContentBox';
|
import ContentBox from '@/components/elements/ContentBox';
|
||||||
import UpdatePasswordForm from '@/components/account/forms/UpdatePasswordForm';
|
import UpdatePasswordForm from '@/components/dashboard/forms/UpdatePasswordForm';
|
||||||
import UpdateEmailAddressForm from '@/components/account/forms/UpdateEmailAddressForm';
|
import UpdateEmailAddressForm from '@/components/dashboard/forms/UpdateEmailAddressForm';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return (
|
return (
|
|
@ -0,0 +1,7 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<p>Dashboard</p>
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -1,49 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { Link, NavLink, Route, RouteComponentProps } from 'react-router-dom';
|
|
||||||
import DesignElementsContainer from '@/components/account/DesignElementsContainer';
|
|
||||||
import AccountOverviewContainer from '@/components/account/AccountOverviewContainer';
|
|
||||||
|
|
||||||
export default ({ match }: RouteComponentProps) => (
|
|
||||||
<div>
|
|
||||||
<div className={'w-full bg-neutral-900 shadow-md'}>
|
|
||||||
<div className={'mx-auto w-full flex items-center'} style={{ maxWidth: '1200px', height: '3.5rem' }}>
|
|
||||||
<div className={'flex-1'}>
|
|
||||||
<Link
|
|
||||||
to={'/'}
|
|
||||||
className={'text-2xl font-header px-4 no-underline text-neutral-200 hover:text-neutral-100'}
|
|
||||||
style={{
|
|
||||||
transition: 'color 150ms linear',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Pterodactyl
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div className={'flex h-full items-center justify-center'}>
|
|
||||||
<NavLink
|
|
||||||
to={'/'}
|
|
||||||
exact={true}
|
|
||||||
className={'flex items-center h-full no-underline text-neutral-300 hover:text-neutral-100 hover:bg-black px-4'}
|
|
||||||
style={{
|
|
||||||
transition: 'background-color 150ms linear, color 150ms linear',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Dashboard
|
|
||||||
</NavLink>
|
|
||||||
<NavLink
|
|
||||||
to={'/account'}
|
|
||||||
className={'flex items-center h-full no-underline text-neutral-300 hover:text-neutral-100 hover:bg-black px-4'}
|
|
||||||
style={{
|
|
||||||
transition: 'background-color 150ms linear, color 150ms linear',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Account
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={'w-full mx-auto'} style={{ maxWidth: '1200px' }}>
|
|
||||||
<Route path={`${match.path}/`} component={AccountOverviewContainer} exact/>
|
|
||||||
<Route path={`${match.path}/design`} component={DesignElementsContainer} exact/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
17
resources/scripts/routers/DashboardRouter.tsx
Normal file
17
resources/scripts/routers/DashboardRouter.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Route, RouteComponentProps } from 'react-router-dom';
|
||||||
|
import DesignElementsContainer from '@/components/dashboard/DesignElementsContainer';
|
||||||
|
import AccountOverviewContainer from '@/components/dashboard/AccountOverviewContainer';
|
||||||
|
import NavigationBar from '@/components/NavigationBar';
|
||||||
|
import DashboardContainer from '@/components/dashboard/DashboardContainer';
|
||||||
|
|
||||||
|
export default ({ match }: RouteComponentProps) => (
|
||||||
|
<div>
|
||||||
|
<NavigationBar/>
|
||||||
|
<div className={'w-full mx-auto'} style={{ maxWidth: '1200px' }}>
|
||||||
|
<Route path={'/'} component={DashboardContainer} exact/>
|
||||||
|
<Route path={'/account'} component={AccountOverviewContainer}/>
|
||||||
|
<Route path={'/design'} component={DesignElementsContainer}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
29
yarn.lock
29
yarn.lock
|
@ -726,6 +726,29 @@
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@csstools/sass-import-resolve/-/sass-import-resolve-1.0.0.tgz#32c3cdb2f7af3cd8f0dca357b592e7271f3831b5"
|
resolved "https://registry.yarnpkg.com/@csstools/sass-import-resolve/-/sass-import-resolve-1.0.0.tgz#32c3cdb2f7af3cd8f0dca357b592e7271f3831b5"
|
||||||
|
|
||||||
|
"@fortawesome/fontawesome-common-types@^0.2.19":
|
||||||
|
version "0.2.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.19.tgz#754a0f85e1290858152e1c05700ab502b11197f1"
|
||||||
|
|
||||||
|
"@fortawesome/fontawesome-svg-core@^1.2.19":
|
||||||
|
version "1.2.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.19.tgz#0eca1ce9285c3d99e6e340633ee8f615f9d1a2e0"
|
||||||
|
dependencies:
|
||||||
|
"@fortawesome/fontawesome-common-types" "^0.2.19"
|
||||||
|
|
||||||
|
"@fortawesome/free-solid-svg-icons@^5.9.0":
|
||||||
|
version "5.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.9.0.tgz#1c73e7bac17417d23f934d83f7fff5b100a7fda9"
|
||||||
|
dependencies:
|
||||||
|
"@fortawesome/fontawesome-common-types" "^0.2.19"
|
||||||
|
|
||||||
|
"@fortawesome/react-fontawesome@^0.1.4":
|
||||||
|
version "0.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.4.tgz#18d61d9b583ca289a61aa7dccc05bd164d6bc9ad"
|
||||||
|
dependencies:
|
||||||
|
humps "^2.0.1"
|
||||||
|
prop-types "^15.5.10"
|
||||||
|
|
||||||
"@hot-loader/react-dom@^16.8.6":
|
"@hot-loader/react-dom@^16.8.6":
|
||||||
version "16.8.6"
|
version "16.8.6"
|
||||||
resolved "https://registry.yarnpkg.com/@hot-loader/react-dom/-/react-dom-16.8.6.tgz#7923ba27db1563a7cc48d4e0b2879a140df461ea"
|
resolved "https://registry.yarnpkg.com/@hot-loader/react-dom/-/react-dom-16.8.6.tgz#7923ba27db1563a7cc48d4e0b2879a140df461ea"
|
||||||
|
@ -3772,6 +3795,10 @@ https-browserify@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||||
|
|
||||||
|
humps@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.1.tgz#dd02ea6081bd0568dc5d073184463957ba9ef9aa"
|
||||||
|
|
||||||
iconv-lite@0.4.23, iconv-lite@^0.4.22, iconv-lite@^0.4.4:
|
iconv-lite@0.4.23, iconv-lite@^0.4.22, iconv-lite@^0.4.4:
|
||||||
version "0.4.23"
|
version "0.4.23"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
||||||
|
@ -6059,7 +6086,7 @@ promise@^7.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
asap "~2.0.3"
|
asap "~2.0.3"
|
||||||
|
|
||||||
prop-types@^15.6.1, prop-types@^15.6.2:
|
prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2:
|
||||||
version "15.7.2"
|
version "15.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
Loading…
Reference in a new issue