diff --git a/html/statbrowser.css b/html/statbrowser.css
index 0e20233b47..d8c0f92b62 100644
--- a/html/statbrowser.css
+++ b/html/statbrowser.css
@@ -1,150 +1,147 @@
body {
font-family: Verdana, Geneva, Tahoma, sans-serif;
- font-size: 12px !important;
+ font-size: 12px;
margin: 0 !important;
padding: 0 !important;
- overflow-x: hidden;
- overflow-y: scroll;
-}
-
-body.dark {
- background-color: #131313;
- color: #b2c4dd;
- scrollbar-base-color: #1c1c1c;
- scrollbar-face-color: #3b3b3b;
- scrollbar-3dlight-color: #252525;
- scrollbar-highlight-color: #252525;
- scrollbar-track-color: #1c1c1c;
- scrollbar-arrow-color: #929292;
- scrollbar-shadow-color: #3b3b3b;
-}
-
-#menu {
- background-color: #F0F0F0;
- position: fixed;
- width: 100%;
- z-index: 100;
-}
-
-.dark #menu {
- background-color: #202020;
-}
-
-#statcontent {
- padding: 7px 7px 7px 7px;
+ overflow: hidden;
}
a {
- color: black;
- text-decoration: none
-}
-
-.dark a {
- color: #b2c4dd;
-}
-
-a:hover,
-.dark a:hover {
- text-decoration: underline;
-}
-
-ul {
- list-style-type: none;
- margin: 0;
- padding: 0;
- background-color: #333;
-}
-
-li {
- float: left;
-}
-
-li a {
- display: block;
- color: white;
- text-align: center;
- padding: 14px 16px;
+ color: #003399;
text-decoration: none;
}
-li a:hover:not(.active) {
- background-color: #111;
+a:hover {
+ color: #007fff;
}
-.button-container {
- display: inline-flex;
+h3 {
+ margin: 0 -0.5em 0.5em;
+ padding: 1em 0.66em 0.5em;
+ border-bottom: 0.1667em solid;
+}
+
+
+img {
+ -ms-interpolation-mode: nearest-neighbor;
+ image-rendering: pixelated;
+}
+
+.stat-container {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+}
+
+#menu {
+ display: flex;
+ overflow-x: auto;
+ overflow-y: hidden;
+ padding: 0.25em 0.25em 0;
+ background-color: #ffffff;
+}
+
+.menu-wrap {
flex-wrap: wrap-reverse;
- flex-direction: row;
- align-items: flex-start;
- overflow-x: hidden;
- white-space: pre-wrap;
- padding: 0 4px;
+}
+
+#menu.tabs-classic {
+ padding: 0.15em;
+}
+
+#menu.tabs-classic .button {
+ min-width: 2em;
+ margin: 0.1em;
+ padding: 0.25em 0.4em;
+ border: 0;
+ border-radius: 0.25em;
+}
+
+#menu.tabs-classic .button.active {
+ background-color: #0668b8;
+ color: white;
}
.button {
- background-color: #dfdfdf;
- border: 1px solid #cecece;
- border-bottom-width: 2px;
- color: rgba(0, 0, 0, 0.7);
- padding: 6px 4px 4px;
- text-align: center;
- text-decoration: none;
- font-size: 12px;
- margin: 0;
+ display: inline-table;
cursor: pointer;
- transition-duration: 100ms;
- order: 3;
- min-width: 40px;
-}
-
-.dark button {
- background-color: #222222;
- border-color: #343434;
- color: rgba(255, 255, 255, 0.5);
+ user-select: none;
+ -ms-user-select: none; /* Remove after Byond 516 */
+ text-align: center;
+ font-size: 1em;
+ min-width: 2.9em;
+ padding: 0.5em 0.5em 0.4em;
+ background-color: transparent;
+ color: rgba(0, 0, 0, 0.5);
+ border: 0;
+ border-bottom: 0.1667em solid transparent;
+ border-radius: 0.25em 0.25em 0 0;
}
.button:hover {
background-color: #ececec;
- transition-duration: 0;
}
-.dark button:hover {
- background-color: #2e2e2e;
-}
-
-.button:active,
.button.active {
- background-color: #ffffff;
+ cursor: default;
+ background-color: #dfdfdf;
color: black;
- border-top-color: #cecece;
- border-left-color: #cecece;
- border-right-color: #cecece;
- border-bottom-color: #ffffff;
+ border-bottom-color: #000000;
}
-.dark .button:active,
-.dark .button.active {
- background-color: #444444;
- color: white;
- border-top-color: #343434;
- border-left-color: #343434;
- border-right-color: #343434;
- border-bottom-color: #ffffff;
+#under-menu {
+ height: 0.5em;
+ background-color: #eeeeee;
+}
+
+#statcontent {
+ flex: 1;
+ padding: 0.75em 0.5em;
+ overflow-y: scroll;
+ overflow-x: hidden;
}
.grid-container {
- margin: -2px;
- margin-right: -15px;
+ margin: -0.25em;
}
.grid-item {
+ display: inline-flex;
position: relative;
- display: inline-block;
+ user-select: none;
+ -ms-user-select: none; /* Remove after Byond 516 */
width: 100%;
- box-sizing: border-box;
- overflow: visible;
- padding: 3px 2px;
+ max-height: 1.85em;
text-decoration: none;
+ background-color: transparent;
+ color: black;
+}
+
+.grid-item:hover,
+.grid-item:active {
+ color: #003399;
+ z-index: 1;
+}
+
+.grid-item-text {
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ pointer-events: none;
+ width: 100%;
+ padding: 0.33em 0.5em;
+ border-radius: 0.25em;
+}
+
+.grid-item:hover .grid-item-text {
+ overflow: visible;
+ white-space: normal;
+ background-color: #ececec;
+}
+
+.grid-item:active .grid-item-text {
+ background-color: #dfdfdf;
}
@media only screen and (min-width: 300px) {
@@ -171,91 +168,72 @@ li a:hover:not(.active) {
}
}
-.grid-item:hover {
- z-index: 1;
+.status-info {
+ margin: 0 0.33em 0.25em;
}
-.grid-item:hover .grid-item-text {
- width: auto;
- text-decoration: underline;
+.interview_panel_stats,
+.interview_panel_controls {
+ margin-bottom: 1em;
}
-.grid-item-text {
- display: inline-block;
- width: 100%;
- background-color: #ffffff;
- margin: 0 -6px;
- padding: 0 6px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- pointer-events: none;
+/* Dark theme colors */
+body.dark {
+ background-color: #131313;
+ color: #b2c4dd;
+ scrollbar-base-color: #1c1c1c;
+ scrollbar-face-color: #3b3b3b;
+ scrollbar-3dlight-color: #252525;
+ scrollbar-highlight-color: #252525;
+ scrollbar-track-color: #1c1c1c;
+ scrollbar-arrow-color: #929292;
+ scrollbar-shadow-color: #3b3b3b;
}
-.dark .grid-item-text {
+.dark a {
+ color: #6699ff;
+}
+
+.dark a:hover,
+.dark .grid-item:hover,
+.dark .grid-item:active {
+ color: #80bfff;
+}
+
+.dark #menu {
background-color: #131313;
}
-.link {
- display: inline;
- background: none;
- border: none;
- padding: 7px 14px;
- color: black;
- text-decoration: none;
- cursor: pointer;
- font-size: 13px;
- margin: 2px 2px;
+.dark #menu.tabs-classic .button.active {
+ background-color: #20b142;
}
-.linkelem {
- display: inline;
- background: none;
- border: none;
- padding: 0px 14px;
- color: black;
- text-decoration: none;
- cursor: pointer;
- font-size: 13px;
- margin: 2px 2px;
+.dark .button {
+ color: rgba(255, 255, 255, 0.5);
}
-.elemcontainer {
- border-collapse: separate;
- border-spacing: 0 5px;
- display: flex;
+.dark .button:hover {
+ background-color: #252525;
}
-.elem {
- background: none;
- border: none;
- padding: 0px 14px;
- font-size: 13px;
- margin: 2px 2px;
+.dark .button.active {
+ background-color: #313131;
+ color: #d4dfec;
+ border-bottom-color: #d4dfec;
}
-.dark .link {
- color: #abc6ec;
+.dark #under-menu {
+ background-color: #202020;
}
-.dark .linkelem {
- color: #abc6ec;
+.dark .grid-item{
+ color: #b2c4dd;
}
-.link:hover {
- text-decoration: underline;
+.dark .grid-item:hover .grid-item-text {
+ background-color: #252525;
}
-.linkelem:hover {
- text-decoration: underline;
-}
-
-img {
- -ms-interpolation-mode: nearest-neighbor;
- image-rendering: pixelated;
-}
-
-.interview_panel_controls,
-.interview_panel_stats {
- margin-bottom: 10px;
+.dark .grid-item:active .grid-item-text {
+ background-color: #313131;
}
diff --git a/html/statbrowser.html b/html/statbrowser.html
index 1aea8811d5..ffd7425bd2 100644
--- a/html/statbrowser.html
+++ b/html/statbrowser.html
@@ -1,3 +1,5 @@
-
-
-
+
diff --git a/html/statbrowser.js b/html/statbrowser.js
index 2572d121ef..7f49fd2486 100644
--- a/html/statbrowser.js
+++ b/html/statbrowser.js
@@ -33,7 +33,6 @@ var turfname = "";
var imageRetryDelay = 500;
var imageRetryLimit = 50;
var menu = document.getElementById('menu');
-var under_menu = document.getElementById('under_menu');
var statcontentdiv = document.getElementById('statcontent');
var storedimages = [];
var split_admin_tabs = false;
@@ -59,26 +58,25 @@ function createStatusTab(name) {
if (!verb_tabs.includes(name) && !permanent_tabs.includes(name)) {
return;
}
- var B = document.createElement("BUTTON");
- B.onclick = function () {
+ var button = document.createElement("DIV");
+ button.onclick = function () {
tab_change(name);
this.blur();
};
- B.id = name;
- B.textContent = name;
- B.className = "button";
+ button.id = name;
+ button.textContent = name;
+ button.className = "button";
//ORDERING ALPHABETICALLY
- B.style.order = name.charCodeAt(0);
+ button.style.order = name.charCodeAt(0);
if (name == "Status" || name == "MC") {
- B.style.order = name == "Status" ? 1 : 2;
+ button.style.order = name == "Status" ? 1 : 2;
}
if (name == "Tickets") {
- B.style.order = 3;
+ button.style.order = 3;
}
//END ORDERING
- menu.appendChild(B);
+ menu.appendChild(button);
SendTabToByond(name);
- under_menu.style.height = menu.clientHeight + 'px';
}
function removeStatusTab(name) {
@@ -92,7 +90,6 @@ function removeStatusTab(name) {
}
menu.removeChild(document.getElementById(name));
TakeTabFromByond(name);
- under_menu.style.height = menu.clientHeight + 'px';
}
function sortVerbs() {
@@ -108,10 +105,6 @@ function sortVerbs() {
})
}
-window.onresize = function () {
- under_menu.style.height = menu.clientHeight + 'px';
-}
-
function addPermanentTab(name) {
if (!permanent_tabs.includes(name)) {
permanent_tabs.push(name);
@@ -383,6 +376,7 @@ function draw_status() {
} else {
var div = document.createElement("div");
div.textContent = status_tab_parts[i];
+ div.className = "status-info";
document.getElementById("statcontent").appendChild(div);
}
}
@@ -777,6 +771,23 @@ function set_theme(which) {
}
}
+function set_font_size(size) {
+ document.body.style.setProperty('font-size', size);
+}
+
+function set_tabs_style(style) {
+ if (style == "default") {
+ menu.classList.add('menu-wrap');
+ menu.classList.remove('tabs-classic');
+ } else if (style == "classic") {
+ menu.classList.add('menu-wrap');
+ menu.classList.add('tabs-classic');
+ } else if (style == "scrollable") {
+ menu.classList.remove('menu-wrap');
+ menu.classList.remove('tabs-classic');
+ }
+}
+
function set_style_sheet(sheet) {
if (document.getElementById("goonStyle")) {
var currentSheet = document.getElementById("goonStyle");
diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.tsx b/tgui/packages/tgui-panel/settings/SettingsPanel.tsx
index e017d83c12..a141b09e93 100644
--- a/tgui/packages/tgui-panel/settings/SettingsPanel.tsx
+++ b/tgui/packages/tgui-panel/settings/SettingsPanel.tsx
@@ -11,6 +11,7 @@ import { ChatPageSettings } from '../chat';
import { changeSettingsTab } from './actions';
import { SETTINGS_TABS } from './constants';
import { selectActiveTab } from './selectors';
+import { SettingsStatPanel } from './SettingsStatPanel';
import { AdminSettings } from './SettingTabs/AdminSettings';
import { ExportTab } from './SettingTabs/ExportTab';
import { MessageLimits } from './SettingTabs/MessageLimits';
@@ -49,6 +50,7 @@ export const SettingsPanel = (props) => {
{activeTab === 'export' && }
{activeTab === 'chatPage' && }
{activeTab === 'textHighlight' && }
+ {activeTab === 'statPanel' && }
{activeTab === 'adminSettings' && }
diff --git a/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx b/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx
new file mode 100644
index 0000000000..68ca14131c
--- /dev/null
+++ b/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx
@@ -0,0 +1,84 @@
+import { toFixed } from 'common/math';
+import { capitalize } from 'common/string';
+import { useDispatch, useSelector } from 'tgui/backend';
+import {
+ Button,
+ LabeledList,
+ NoticeBox,
+ Section,
+ Slider,
+ Stack,
+} from 'tgui/components';
+
+import { updateSettings } from './actions';
+import { selectSettings } from './selectors';
+
+const TabsViews = ['default', 'classic', 'scrollable'];
+const LinkedToChat = () => (
+ Unlink Stat Panel from chat!
+);
+
+export function SettingsStatPanel(props) {
+ const { statLinked, statFontSize, statTabsStyle } =
+ useSelector(selectSettings);
+ const dispatch = useDispatch();
+
+ return (
+
+
+
+
+
+ {TabsViews.map((view) => (
+
+ ))}
+
+
+
+ {statLinked ? (
+
+ ) : (
+ toFixed(value)}
+ onChange={(e, value) =>
+ dispatch(updateSettings({ statFontSize: value }))
+ }
+ />
+ )}
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/tgui/packages/tgui-panel/settings/constants.ts b/tgui/packages/tgui-panel/settings/constants.ts
index 8be68f3d2c..8bb3222a1b 100644
--- a/tgui/packages/tgui-panel/settings/constants.ts
+++ b/tgui/packages/tgui-panel/settings/constants.ts
@@ -29,6 +29,10 @@ export const SETTINGS_TABS = [
id: 'chatPage',
name: 'Chat Tabs',
},
+ {
+ id: 'statPanel',
+ name: 'Stat Panel',
+ },
];
export const FONTS_DISABLED = 'Default';
diff --git a/tgui/packages/tgui-panel/settings/middleware.ts b/tgui/packages/tgui-panel/settings/middleware.ts
index fc09fe5d2c..078b9a7874 100644
--- a/tgui/packages/tgui-panel/settings/middleware.ts
+++ b/tgui/packages/tgui-panel/settings/middleware.ts
@@ -13,11 +13,12 @@ import {
removeHighlightSetting,
updateHighlightSetting,
updateSettings,
- updateToggle,
} from './actions';
import { FONTS_DISABLED } from './constants';
import { selectSettings } from './selectors';
+let statFontTimer: NodeJS.Timeout;
+let statTabsTimer: NodeJS.Timeout;
let overrideRule: HTMLStyleElement;
let overrideFontFamily: string | undefined;
let overrideFontSize: string;
@@ -45,14 +46,37 @@ function updateGlobalOverrideRule() {
document.body.style.setProperty('font-size', overrideFontSize);
}
-function setGlobalFontSize(fontSize: string) {
+function setGlobalFontSize(
+ fontSize: string,
+ statFontSize: string,
+ statLinked: boolean,
+) {
overrideFontSize = `${fontSize}px`;
+
+ // Used solution from theme.ts
+ clearInterval(statFontTimer);
+ Byond.command(
+ `.output statbrowser:set_font_size ${statLinked ? fontSize : statFontSize}px`,
+ );
+ statFontTimer = setTimeout(() => {
+ Byond.command(
+ `.output statbrowser:set_font_size ${statLinked ? fontSize : statFontSize}px`,
+ );
+ }, 1500);
}
function setGlobalFontFamily(fontFamily: string) {
overrideFontFamily = fontFamily === FONTS_DISABLED ? undefined : fontFamily;
}
+function setStatTabsStyle(style: string) {
+ clearInterval(statTabsTimer);
+ Byond.command(`.output statbrowser:set_tabs_style ${style}`);
+ statTabsTimer = setTimeout(() => {
+ Byond.command(`.output statbrowser:set_tabs_style ${style}`);
+ }, 1500);
+}
+
export function settingsMiddleware(store) {
let initialized = false;
@@ -66,7 +90,6 @@ export function settingsMiddleware(store) {
});
}
if (
- type !== updateToggle.type &&
type !== updateSettings.type &&
type !== loadSettings.type &&
type !== addHighlightSetting.type &&
@@ -87,8 +110,15 @@ export function settingsMiddleware(store) {
const settings = selectSettings(store.getState());
+ // Update stat panel settings
+ setStatTabsStyle(settings.statTabsStyle);
+
// Update global UI font size
- setGlobalFontSize(settings.fontSize);
+ setGlobalFontSize(
+ settings.fontSize,
+ settings.statFontSize,
+ settings.statLinked,
+ );
setGlobalFontFamily(settings.fontFamily);
updateGlobalOverrideRule();
diff --git a/tgui/packages/tgui-panel/settings/reducer.ts b/tgui/packages/tgui-panel/settings/reducer.ts
index a4f6d3c56a..2fd2e0b94d 100644
--- a/tgui/packages/tgui-panel/settings/reducer.ts
+++ b/tgui/packages/tgui-panel/settings/reducer.ts
@@ -62,6 +62,9 @@ const initialState = {
hideImportantInAdminTab: false,
interleave: false,
interleaveColor: '#909090',
+ statLinked: true,
+ statFontSize: 12,
+ statTabsStyle: 'default',
} as const;
export function settingsReducer(