diff --git a/resources/scripts/assets/css/GlobalStylesheet.ts b/resources/scripts/assets/css/GlobalStylesheet.ts
new file mode 100644
index 000000000..72d80f583
--- /dev/null
+++ b/resources/scripts/assets/css/GlobalStylesheet.ts
@@ -0,0 +1,20 @@
+import tw from 'twin.macro';
+import { createGlobalStyle } from 'styled-components/macro';
+
+export default createGlobalStyle`
+ @import url('//fonts.googleapis.com/css?family=Rubik:300,400,500&display=swap');
+ @import url('//fonts.googleapis.com/css?family=IBM+Plex+Mono|IBM+Plex+Sans:500&display=swap');
+
+ body {
+ ${tw`font-sans bg-neutral-800 text-neutral-200`};
+ letter-spacing: 0.015em;
+ }
+
+ h1, h2, h3, h4, h5, h6 {
+ ${tw`font-medium tracking-normal font-header`};
+ }
+
+ p {
+ ${tw`text-neutral-200 leading-snug font-sans`};
+ }
+`;
diff --git a/resources/scripts/components/App.tsx b/resources/scripts/components/App.tsx
index a90786ae0..dac7fd102 100644
--- a/resources/scripts/components/App.tsx
+++ b/resources/scripts/components/App.tsx
@@ -11,6 +11,7 @@ import { SiteSettings } from '@/state/settings';
import ProgressBar from '@/components/elements/ProgressBar';
import NotFound from '@/components/screens/NotFound';
import tw from 'twin.macro';
+import GlobalStylesheet from '@/assets/css/GlobalStylesheet';
interface ExtendedWindow extends Window {
SiteConfiguration?: SiteSettings;
@@ -48,21 +49,24 @@ const App = () => {
}
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
);
};
diff --git a/resources/scripts/components/NavigationBar.tsx b/resources/scripts/components/NavigationBar.tsx
index 7ff60bef0..f8213a34b 100644
--- a/resources/scripts/components/NavigationBar.tsx
+++ b/resources/scripts/components/NavigationBar.tsx
@@ -1,51 +1,76 @@
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';
-import { faCogs } from '@fortawesome/free-solid-svg-icons/faCogs';
+import { faCogs, faLayerGroup, faSignOutAlt, faUserCircle } from '@fortawesome/free-solid-svg-icons';
import { useStoreState } from 'easy-peasy';
import { ApplicationStore } from '@/state';
-import { faSearch } from '@fortawesome/free-solid-svg-icons/faSearch';
import SearchContainer from '@/components/dashboard/search/SearchContainer';
+import tw from 'twin.macro';
+import styled from 'styled-components/macro';
+import * as config from '@/../../tailwind.config.js';
+
+const Navigation = styled.div`
+ ${tw`w-full bg-neutral-900 shadow-md`};
+
+ & > div {
+ ${tw`mx-auto w-full flex items-center`};
+ }
+
+ & #logo {
+ ${tw`flex-1`};
+
+ & > a {
+ ${tw`text-2xl font-header px-4 no-underline text-neutral-200 hover:text-neutral-100 transition-colors duration-150`};
+ }
+ }
+`;
+
+const RightNavigation = styled.div`
+ ${tw`flex h-full items-center justify-center`};
+
+ & > a, & > .navigation-link {
+ ${tw`flex items-center h-full no-underline text-neutral-300 px-6 cursor-pointer transition-all duration-150`};
+
+ &:active, &:hover {
+ ${tw`text-neutral-100 bg-black`};
+ }
+
+ &:active, &:hover, &.active {
+ box-shadow: inset 0 -2px ${config.theme.colors.cyan['700']};
+ }
+ }
+`;
export default () => {
const user = useStoreState((state: ApplicationStore) => state.user.data!);
const name = useStoreState((state: ApplicationStore) => state.settings.data!.name);
return (
-
-
+
+
{name}
-
+
-
+
{user.rootAdmin &&
-
+
}
- {process.env.NODE_ENV !== 'production' &&
-
-
-
- }
-
+
-
+
);
};
diff --git a/resources/scripts/components/dashboard/DashboardContainer.tsx b/resources/scripts/components/dashboard/DashboardContainer.tsx
index ad8f30d6f..6daf78f0d 100644
--- a/resources/scripts/components/dashboard/DashboardContainer.tsx
+++ b/resources/scripts/components/dashboard/DashboardContainer.tsx
@@ -10,6 +10,7 @@ import FlashMessageRender from '@/components/FlashMessageRender';
import { useStoreState } from 'easy-peasy';
import { usePersistedState } from '@/plugins/usePersistedState';
import Switch from '@/components/elements/Switch';
+import tw from 'twin.macro';
export default () => {
const { addError, clearFlashes } = useFlash();
@@ -37,10 +38,10 @@ export default () => {
return (
-
+
{rootAdmin &&
-
-
+
+
{showAdmin ? 'Showing all servers' : 'Showing your servers'}
{
}
{loading ?
-
+
:
servers.length > 0 ?
- servers.map(server => (
-
+ servers.map((server, index) => (
+ 0 ? tw`mt-2` : undefined}>
+
+
))
:
-
+
There are no servers associated with your account.
}
diff --git a/resources/scripts/components/dashboard/DesignElementsContainer.tsx b/resources/scripts/components/dashboard/DesignElementsContainer.tsx
deleted file mode 100644
index 1e9747868..000000000
--- a/resources/scripts/components/dashboard/DesignElementsContainer.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-import * as React from 'react';
-import { Link } from 'react-router-dom';
-import ContentBox from '@/components/elements/ContentBox';
-
-export default class DesignElementsContainer extends React.PureComponent {
- render () {
- return (
-
-
-
-
-
- Your demands have been received: Dark Mode will be default in Pterodactyl 0.8!
-
- Back
-
-
-
Form Elements
-
-
-
-
- This is some descriptive helper text to explain how things work.
-
-
-
-
-
- This field has an error.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
diff --git a/resources/scripts/components/dashboard/ServerRow.tsx b/resources/scripts/components/dashboard/ServerRow.tsx
index a212bce0c..89233728a 100644
--- a/resources/scripts/components/dashboard/ServerRow.tsx
+++ b/resources/scripts/components/dashboard/ServerRow.tsx
@@ -11,6 +11,8 @@ import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import getServerResourceUsage, { ServerStats } from '@/api/server/getServerResourceUsage';
import { bytesToHuman } from '@/helpers';
import classNames from 'classnames';
+import tw from 'twin.macro';
+import GreyRowBox from '@/components/elements/GreyRowBox';
// Determines if the current value is in an alarm threshold so we can show it in red rather
// than the more faded default style.
@@ -20,7 +22,7 @@ const isAlarmState = (current: number, limit: number): boolean => {
return current / limitInBytes >= 0.90;
};
-export default ({ server, className }: { server: Server; className: string | undefined }) => {
+export default ({ server }: { server: Server }) => {
const interval = useRef
(null);
const [ stats, setStats ] = useState(null);
const [ statsError, setStatsError ] = useState(false);
@@ -37,7 +39,6 @@ export default ({ server, className }: { server: Server; className: string | und
useEffect(() => {
getStats().then(() => {
- // @ts-ignore
interval.current = setInterval(() => getStats(), 20000);
});
@@ -52,21 +53,21 @@ export default ({ server, className }: { server: Server; className: string | und
alarms.memory = isAlarmState(stats.memoryUsageInBytes, server.limits.memory);
alarms.disk = server.limits.disk === 0 ? false : isAlarmState(stats.diskUsageInBytes, server.limits.disk);
}
- const disklimit = server.limits.disk != 0 ? bytesToHuman(server.limits.disk * 1000 * 1000) : "Unlimited";
- const memorylimit = server.limits.memory != 0 ? bytesToHuman(server.limits.memory * 1000 * 1000) : "Unlimited";
+ const disklimit = server.limits.disk !== 0 ? bytesToHuman(server.limits.disk * 1000 * 1000) : 'Unlimited';
+ const memorylimit = server.limits.memory !== 0 ? bytesToHuman(server.limits.memory * 1000 * 1000) : 'Unlimited';
return (
-
+
-
-
{server.name}
+
-
-
-
-
+
+
+
+
{
server.allocations.filter(alloc => alloc.default).map(allocation => (
{allocation.alias || allocation.ip}:{allocation.port}
@@ -75,85 +76,88 @@ export default ({ server, className }: { server: Server; className: string | und
-
+
{!stats ?
!statsError ?
:
server.isInstalling ?
-
-
+
+
Installing
:
-
-
+
+
{server.isSuspended ? 'Suspended' : 'Connection Error'}
:
-
+
{stats.cpuUsagePercent} %
-
-
+
+
{bytesToHuman(stats.memoryUsageInBytes)}
-
of {memorylimit}
+
of {memorylimit}
-
-
+
+
{bytesToHuman(stats.diskUsageInBytes)}
-
of {disklimit}
+
of {disklimit}
}
-
+
);
};
diff --git a/resources/scripts/components/elements/GreyRowBox.tsx b/resources/scripts/components/elements/GreyRowBox.tsx
new file mode 100644
index 000000000..e33dae6ca
--- /dev/null
+++ b/resources/scripts/components/elements/GreyRowBox.tsx
@@ -0,0 +1,14 @@
+import styled from 'styled-components/macro';
+import tw from 'twin.macro';
+
+export default styled.div`
+ ${tw`flex rounded no-underline text-neutral-200 items-center bg-neutral-700 p-4 border border-transparent transition-colors duration-150`};
+
+ &:not(.no-hover):hover {
+ ${tw`border-neutral-500`};
+ }
+
+ & > div.icon {
+ ${tw`rounded-full bg-neutral-500 p-3`};
+ }
+`;
diff --git a/resources/scripts/components/elements/PageContentBlock.tsx b/resources/scripts/components/elements/PageContentBlock.tsx
index 87d9d3d34..656facf95 100644
--- a/resources/scripts/components/elements/PageContentBlock.tsx
+++ b/resources/scripts/components/elements/PageContentBlock.tsx
@@ -1,26 +1,22 @@
import React from 'react';
import ContentContainer from '@/components/elements/ContentContainer';
import { CSSTransition } from 'react-transition-group';
+import tw from 'twin.macro';
-interface Props {
- children: React.ReactNode;
- className?: string;
-}
-
-export default ({ className, children }: Props) => (
-
+export default ({ children }): React.FC => (
+
<>
-
+
{children}
-
-
+
+
© 2015 - 2020
Pterodactyl Software
diff --git a/resources/scripts/routers/DashboardRouter.tsx b/resources/scripts/routers/DashboardRouter.tsx
index 1e1de404d..f0a78a183 100644
--- a/resources/scripts/routers/DashboardRouter.tsx
+++ b/resources/scripts/routers/DashboardRouter.tsx
@@ -1,6 +1,5 @@
import * as React from 'react';
import { NavLink, Route, RouteComponentProps, Switch } 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';
@@ -9,13 +8,13 @@ import AccountApiContainer from '@/components/dashboard/AccountApiContainer';
import NotFound from '@/components/screens/NotFound';
export default ({ location }: RouteComponentProps) => (
-
+ <>
{location.pathname.startsWith('/account') &&
- Settings
- API Credentials
+ Settings
+ API Credentials
}
@@ -24,9 +23,8 @@ export default ({ location }: RouteComponentProps) => (
-
-
+ >
);