diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx
index d09fdfcc3..390939f6d 100644
--- a/web/pages/_app.tsx
+++ b/web/pages/_app.tsx
@@ -1,4 +1,3 @@
-import 'antd/dist/antd.dark.css';
import 'antd/dist/antd.compact.css';
import "../styles/globals.scss";
diff --git a/web/pages/components/log-table.tsx b/web/pages/components/log-table.tsx
index 86469aa6f..6d0c01cb0 100644
--- a/web/pages/components/log-table.tsx
+++ b/web/pages/components/log-table.tsx
@@ -1,6 +1,6 @@
import React from "react";
import { timeFormat } from "d3-time-format";
-import { Table, } from "antd";
+import { Table, Tag} from "antd";
import Linkify from "react-linkify";
import { SortOrder } from "antd/lib/table/interface";
@@ -13,10 +13,7 @@ function renderColumnLevel(text, entry) {
color = "red";
}
- const style = {
- color,
- };
- return
{text}
;
+ return {text};
}
function renderMessage(text) {
diff --git a/web/pages/components/main-layout.tsx b/web/pages/components/main-layout.tsx
index 052cc3bc3..bd502bfd5 100644
--- a/web/pages/components/main-layout.tsx
+++ b/web/pages/components/main-layout.tsx
@@ -1,6 +1,7 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import Link from 'next/link';
+import { differenceInSeconds } from "date-fns";
import { useRouter } from 'next/router';
import { Layout, Menu } from 'antd';
import {
@@ -12,7 +13,7 @@ import {
MinusSquareFilled,
} from '@ant-design/icons';
import classNames from 'classnames';
-
+import {parseSecondsToDurationString} from '../../utils/format'
import OwncastLogo from './logo';
import { BroadcastStatusContext } from '../../utils/broadcast-status-context';
@@ -31,10 +32,14 @@ export default function MainLayout(props) {
const { Header, Footer, Content, Sider } = Layout;
const { SubMenu } = Menu;
+ const streamDurationString = broadcastActive ?
+ parseSecondsToDurationString(differenceInSeconds(new Date(), new Date(context.broadcaster.time))) : ""
+
const statusIcon = broadcastActive ?
: ;
- const statusMessage = broadcastActive ?
- 'Online' : 'Offline';
+ const statusMessage = broadcastActive
+ ? `Online ${ streamDurationString}`
+ : "Offline";
const appClass = classNames({
'owncast-layout': true,
diff --git a/web/pages/viewer-info.tsx b/web/pages/viewer-info.tsx
index bc2d9adae..a3b367c60 100644
--- a/web/pages/viewer-info.tsx
+++ b/web/pages/viewer-info.tsx
@@ -1,6 +1,5 @@
/* eslint-disable react/prop-types */
import React, { useState, useEffect, useContext } from 'react';
-import { timeFormat } from "d3-time-format";
import { Table, Row } from "antd";
import { formatDistanceToNow } from "date-fns";
import { UserOutlined} from "@ant-design/icons";
diff --git a/web/utils/format.ts b/web/utils/format.ts
index 4f618e16e..a34ce1773 100644
--- a/web/utils/format.ts
+++ b/web/utils/format.ts
@@ -17,3 +17,25 @@ export function formatIPAddress(ipAddress: string): string {
export function isEmptyObject(obj) {
return !obj || Object.keys(obj).length === 0;
}
+
+export function parseSecondsToDurationString(seconds = 0) {
+ const finiteSeconds = Number.isFinite(+seconds) ? Math.abs(seconds) : 0;
+
+ const days = Math.floor(finiteSeconds / 86400);
+ const daysString = days > 0 ? `${days} day${days > 1 ? 's' : ''} ` : '';
+
+ const hours = Math.floor((finiteSeconds / 3600) % 24);
+ const hoursString = hours || days ? padLeft(`${hours}:`, '0', 3) : '';
+
+ const mins = Math.floor((finiteSeconds / 60) % 60);
+ const minString = padLeft(`${mins}:`, '0', 3);
+
+ const secs = Math.floor(finiteSeconds % 60);
+ const secsString = padLeft(`${secs}`, '0', 2);
+
+ return daysString + hoursString + minString + secsString;
+}
+
+export function padLeft(text, pad, size) {
+ return String(pad.repeat(size) + text).slice(-size);
+}
\ No newline at end of file