Skip to content

Commit

Permalink
wip: dynamic title and favicon
Browse files Browse the repository at this point in the history
  • Loading branch information
tabarra committed Nov 23, 2023
1 parent 4b2849f commit c57fd29
Show file tree
Hide file tree
Showing 15 changed files with 246 additions and 55 deletions.
13 changes: 7 additions & 6 deletions docs/dev_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,14 @@ Processo:
- [x][5d] fully responsive layout (show/hide sidebars, login, addMaster, etc)
- [x][2h] merge new shell design into the `txadmin/panel` codebase
- [ ][~3d] implement most shell+status features
- [ ][1d] socket.io connection for default room
- [x][1d] socket.io connection for default room
- [x][2h] warning for outdated tx, visible in all pages
- [ ][1h] zap hosting advertisement
- [ ][1h] dynamic title
- [ ][1h] dynamic favicon
- [x][1h] dynamic title
- [x][1h] dynamic favicon
- [ ][1d] server status
- [ ][4h] update notices via socket.io
- [ ][2h] tooltips on everything
- [ ][1h] zap hosting advertisement
- [ ][1d] toasts API
- [ ] generic toasts
- [ ] markdown toasts
Expand All @@ -89,8 +90,8 @@ Processo:
- [ ] disable menu links based on permissions
- [ ] flow to refresh the permissions on the client side
- [ ] flow to refresh the page if invalidated auth
- [ ][4h] full setup flow (legacy)
- [ ][4h] full deployer flow (legacy)
- [ ][2d] full setup flow (legacy)
- [ ][1d] full deployer flow (legacy)
- [ ][1d] NEW PAGE: Dashboard
- [ ] warning for txadmin updates
- [ ] warning for fxserver update
Expand Down
2 changes: 1 addition & 1 deletion panel/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<!-- {{basePath}} -->
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="./emoji_favicon.png" />
<link rel="icon" type="image/svg" href="./favicon_default.svg" id="favicon"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>txAdmin</title>
<meta name="description" content="{{ogDescripttion}}">
Expand Down
Binary file removed panel/public/emoji_favicon.png
Binary file not shown.
14 changes: 14 additions & 0 deletions panel/public/favicon_default.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions panel/public/favicon_offline.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions panel/public/favicon_online.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions panel/public/favicon_partial.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion panel/public/vite.svg

This file was deleted.

2 changes: 1 addition & 1 deletion panel/src/components/MainPageLink.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useSheets } from "@/hooks/sheets";
import { pageErrorStatusAtom, useContentRefresh } from "@/hooks/mainPageStatus";
import { pageErrorStatusAtom, useContentRefresh } from "@/hooks/pages";
import { useAtomValue } from "jotai";
import { forwardRef } from "react";
import { Link, useRoute } from "wouter";
Expand Down
21 changes: 0 additions & 21 deletions panel/src/hooks/mainPageStatus.ts

This file was deleted.

65 changes: 65 additions & 0 deletions panel/src/hooks/pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { atom, useSetAtom } from 'jotai';
import { atomEffect } from 'jotai-effect'
import faviconDefault from '/favicon_default.svg';
import faviconOnline from '/favicon_online.svg';
import faviconPartial from '/favicon_partial.svg';
import faviconOffline from '/favicon_offline.svg';
import { globalStatusAtom } from './socketio';

/**
* This atom is used to change the key of the main page error boundry, which also resets the router
* as a side effect. This is used to reset the page that errored as well as resetting the current
* page when the user clicks on the active menu link.
*/
export const contentRefreshKeyAtom = atom(0);

//Hook to refresh content
export const useContentRefresh = () => {
const setContentRefreshKey = useSetAtom(contentRefreshKeyAtom);
return () => setContentRefreshKey(Math.random());
};

/**
* This atom describes if the main page is in error state or not.
* When the page is in error, clicking on any menu link will reset the error boundry and router,
* therefore also resetting the page that errored.
*/
export const pageErrorStatusAtom = atom(false);



/**
* Page title management
*/
const faviconEl = document.getElementById('favicon') as HTMLLinkElement;
const pageTitleAtom = atom('txAdmin');

export const useSetPageTitle = () => {
const setPageTitle = useSetAtom(pageTitleAtom);
return (title = 'txAdmin') => setPageTitle(title);
}

export const pageTitleWatcher = atomEffect((get, set) => {
if (!window.txConsts.isWebInterface) return;
const pageTitle = get(pageTitleAtom);
const globalStatus = get(globalStatusAtom);

if (!globalStatus) {
faviconEl.href = faviconDefault;
document.title = 'txAdmin';
} else {
if(globalStatus.server.status === 'ONLINE'){
faviconEl.href = faviconOnline;
}else if(globalStatus.server.status === 'PARTIAL'){
faviconEl.href = faviconPartial;
} else {
faviconEl.href = faviconOffline;
}
document.title = `(${globalStatus.server.players}) ${globalStatus.server.name} · ${pageTitle}`;
}

return () => {
faviconEl.href = faviconDefault;
document.title = 'txAdmin';
}
});
130 changes: 106 additions & 24 deletions panel/src/layout/MainRouter.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,109 @@
import { ErrorBoundary } from "react-error-boundary";
import { Route, Switch, useLocation } from "wouter";
import { Route as WouterRoute, Switch, useLocation } from "wouter";
import { PageErrorFallback } from "../components/ErrorFallback";
import { useAtomValue, useSetAtom } from "jotai";
import { contentRefreshKeyAtom, pageErrorStatusAtom } from "../hooks/mainPageStatus";
import { contentRefreshKeyAtom, pageErrorStatusAtom, useSetPageTitle } from "../hooks/pages";

import Iframe from "../pages/Iframe"
import NotFound from "../pages/NotFound"
import TestingPage from "../pages/testing/TestingPage";


type RouteType = {
path: string;
title: string;
children: JSX.Element;
};

const allRoutes: RouteType[] = [
//Global Routes
{
path: '/players',
title: 'Players',
children: <Iframe legacyUrl="players" />
},
// {
// path: '/history',
// title: 'History',
// children: <>TODO:</>
// },
{
path: '/whitelist',
title: 'Whitelist',
children: <Iframe legacyUrl="whitelist" />
},
{
path: '/admins',
title: 'Admins',
children: <Iframe legacyUrl="adminManager" />
},
{
path: '/settings',
title: 'Settings',
children: <Iframe legacyUrl="settings" />
},
{
path: '/system/master-actions',
title: 'Master Actions',
children: <Iframe legacyUrl="masterActions" />
},
{
path: '/system/diagnostics',
title: 'Diagnostics',
children: <Iframe legacyUrl="diagnostics" />
},
{
path: '/system/console-log',
title: 'Console Log',
children: <Iframe legacyUrl="systemLog#nav-console" />
},
{
path: '/system/action-log',
title: 'Action Log',
children: <Iframe legacyUrl="systemLog#nav-actions" />
},

//Server Routes
{
path: '/',
title: 'Dashboard',
children: <Iframe legacyUrl="dashboard" />
},
{
path: '/server/console',
title: 'Live Console',
children: <Iframe legacyUrl="console" />
},
{
path: '/server/resources',
title: 'Resources',
children: <Iframe legacyUrl="resources" />
},
{
path: '/server/server-log',
title: 'Server Log',
children: <Iframe legacyUrl="serverLog" />
},
{
path: '/server/cfg-editor',
title: 'CFG Editor',
children: <Iframe legacyUrl="cfgEditor" />
},
{
path: '/advanced',
title: 'Advanced',
children: <Iframe legacyUrl="advanced" />
},
];


function Route(props: RouteType){
const setPageTitle = useSetPageTitle();
setPageTitle(props.title);
return <WouterRoute path={props.path}>{props.children}</WouterRoute>
}


export default function MainRouter() {
const setPageErrorStatus = useSetAtom(pageErrorStatusAtom);
const contentRefreshKey = useAtomValue(contentRefreshKeyAtom);
Expand All @@ -29,28 +124,15 @@ export default function MainRouter() {
}}
>
<Switch>
{/* Global Routes */}
<Route path="/players"><Iframe legacyUrl="players" /></Route>
{/* TODO: history */}
<Route path="/whitelist"><Iframe legacyUrl="whitelist" /></Route>
<Route path="/admins"><Iframe legacyUrl="adminManager" /></Route>
<Route path="/settings"><Iframe legacyUrl="settings" /></Route>
<Route path="/system/master-actions"><Iframe legacyUrl="masterActions" /></Route>
<Route path="/system/diagnostics"><Iframe legacyUrl="diagnostics" /></Route>
<Route path="/system/console-log"><Iframe legacyUrl="systemLog#nav-console" /></Route>
<Route path="/system/action-log"><Iframe legacyUrl="systemLog#nav-actions" /></Route>

{/* Server Routes */}
<Route path="/"><Iframe legacyUrl="dashboard" /></Route>
<Route path="/server/console"><Iframe legacyUrl="console" /></Route>
<Route path="/server/resources"><Iframe legacyUrl="resources" /></Route>
<Route path="/server/server-log"><Iframe legacyUrl="serverLog" /></Route>
<Route path="/server/cfg-editor"><Iframe legacyUrl="cfgEditor" /></Route>
<Route path="/advanced"><Iframe legacyUrl="advanced" /></Route>

{/* Other Routes */}
<Route path="/test"><TestingPage /></Route>
<Route path="/:fullPath*" component={NotFound} />
{allRoutes.map((route) => (
<Route key={route.path} path={route.path} title={route.title}>
{route.children}
</Route>
))}

{/* Other Routes - they need to set the title manuually */}
<WouterRoute path="/test"><TestingPage /></WouterRoute>
<WouterRoute path="/:fullPath*" component={NotFound} />
</Switch>
</ErrorBoundary>
);
Expand Down
4 changes: 4 additions & 0 deletions panel/src/layout/MainShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ import BreakpointDebugger from '@/components/BreakpointDebugger';
import { useEffect, useRef } from 'react';
import { getSocket, useSetGlobalStatus } from '@/hooks/socketio';
import { useSetOfflineWarning } from '@/hooks/useWarningBar';
import { pageTitleWatcher } from '@/hooks/pages';
import { useAtomValue } from 'jotai';



export default function MainShell() {
useAtomValue(pageTitleWatcher);
const expireSession = useExpireAuthData();
useEventListener('message', (e: MessageEventFromIframe) => {
if (e.data.type === 'logoutNotice') {
Expand Down
3 changes: 3 additions & 0 deletions panel/src/pages/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import InlineCode from "@/components/InlineCode";
import { useSetPageTitle } from "@/hooks/pages";
import { Link } from "wouter";

type Props = {
Expand All @@ -7,6 +8,8 @@ type Props = {
};
};
export default function NotFound({ params }: Props) {
const setPageTitle = useSetPageTitle();
setPageTitle('Not Found');
return (
<div className="w-full flex items-center justify-center">
<div className="text-center">
Expand Down
4 changes: 3 additions & 1 deletion panel/src/pages/testing/TestingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import TmpSocket from "./TmpSocket";


export default function TestingPage() {
useSocketio();
const setPageTitle = useSetPageTitle();
setPageTitle();

return <div className="flex flex-col gap-4 w-full m-4">
<TmpSocket />
{/* <TmpWarningBarState /> */}
Expand Down

0 comments on commit c57fd29

Please sign in to comment.