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.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) => ( - - + );