diff --git a/web/components/news-feed.tsx b/web/components/news-feed.tsx
new file mode 100644
index 000000000..8224f1cd9
--- /dev/null
+++ b/web/components/news-feed.tsx
@@ -0,0 +1,64 @@
+/* eslint-disable camelcase */
+/* eslint-disable react/no-danger */
+import React, { useState, useEffect } from 'react';
+import { Typography } from 'antd';
+import format from 'date-fns/format';
+
+import { fetchExternalData } from '../utils/apis';
+
+const { Title, Link } = Typography;
+
+const OWNCAST_FEED_URL = 'https://owncast.online/news/index.json';
+const OWNCAST_BASE_URL = 'https://owncast.online';
+
+interface Article {
+ title: string;
+ url: string;
+ content_html: string;
+ date_published: string;
+}
+
+function ArticleItem({ title, url, content_html: content, date_published: date }: Article) {
+ const dateObject = new Date(date);
+ const dateString = format(dateObject, 'MMM dd, yyyy, HH:mm');
+ return (
+
+ {dateString}
+
+
+ {title}
+
+
+
+
+ );
+}
+
+export default function NewsFeed() {
+ const [feed, setFeed] = useState([]);
+ const getFeed = async () => {
+ try {
+ const result = await fetchExternalData(OWNCAST_FEED_URL);
+ setFeed(result.items);
+ } catch (error) {
+ console.log('==== error', error);
+ }
+ };
+
+ useEffect(() => {
+ getFeed();
+ }, []);
+
+ if (!feed.length) {
+ return null;
+ }
+
+ return (
+
+ News & Updates from Owncast
+ {feed.map(item => (
+
+ ))}
+
+ );
+}
diff --git a/web/pages/index.tsx b/web/pages/index.tsx
index bf03c3c94..a5718d52c 100644
--- a/web/pages/index.tsx
+++ b/web/pages/index.tsx
@@ -8,6 +8,7 @@ import Offline from './offline-notice';
import { LOGS_WARN, fetchData, FETCH_INTERVAL } from '../utils/apis';
import { formatIPAddress, isEmptyObject } from '../utils/format';
+import NewsFeed from '../components/news-feed';
function streamDetailsFormatter(streamDetails) {
return (
@@ -135,13 +136,16 @@ export default function Home() {
-
-
+
+
{videoQualitySettings}
-
-
+
+
+
diff --git a/web/pages/offline-notice.tsx b/web/pages/offline-notice.tsx
index c0f0903a0..b3e7004ec 100644
--- a/web/pages/offline-notice.tsx
+++ b/web/pages/offline-notice.tsx
@@ -1,5 +1,5 @@
import Link from 'next/link';
-import { Result, Card, Row, Col } from 'antd';
+import { Typography, Card, Row, Col } from 'antd';
import {
MessageTwoTone,
QuestionCircleTwoTone,
@@ -9,7 +9,9 @@ import {
} from '@ant-design/icons';
import OwncastLogo from '../components/logo';
import LogTable from '../components/log-table';
+import NewsFeed from '../components/news-feed';
+const { Title } = Typography;
const { Meta } = Card;
export default function Offline({ logs = [], config }) {
@@ -77,15 +79,20 @@ export default function Offline({ logs = [], config }) {
return (
<>
-
-
- }
- title="No stream is active."
- subTitle="You should start one."
- />
+
+
+
+
+
+
+
+
No stream is active
+
You should start one.
+
+
-
+
+
{data.map(item => (
@@ -93,6 +100,9 @@ export default function Offline({ logs = [], config }) {
))}
+
+
+
>
diff --git a/web/styles/home.scss b/web/styles/home.scss
index 7a5a211a4..2266bbecb 100644
--- a/web/styles/home.scss
+++ b/web/styles/home.scss
@@ -34,12 +34,14 @@
}
}
- .outbound-details,
- .inbound-details {
+ .stream-details {
> .ant-card-bordered {
border-color: rgba(255, 255, 255, 0.1);
}
}
+ .outbound-details {
+ margin-bottom: 1em;
+ }
}
.offline-content {
@@ -75,3 +77,45 @@
}
}
}
+
+.offline-intro {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-evenly;
+ align-items: center;
+ margin-bottom: 2em;
+ .logo-svg {
+ height: 6em;
+ width: 6em;
+ }
+}
+
+.news-feed {
+ margin-top: 0;
+ padding: 1.5em;
+
+ h2 {
+ font-size: 1.2em;
+ margin-top: 0;
+ color: var(--pink);
+ }
+ article {
+ padding: 1em 0.25em;
+ font-size: 14px;
+ color: var(--white-75);
+ border-bottom: 1px solid var(--gray);
+
+ h3 {
+ font-size: 1.2em;
+ a {
+ font-weight: 400;
+ font-size: 1em;
+ }
+ }
+ .timestamp {
+ margin-top: 0;
+ font-size: 0.75em;
+ color: var(--white-50);
+ }
+ }
+}
diff --git a/web/utils/apis.ts b/web/utils/apis.ts
index 24c9a558d..c737a0826 100644
--- a/web/utils/apis.ts
+++ b/web/utils/apis.ts
@@ -116,9 +116,9 @@ export async function fetchData(url: string, options?: FetchOptions) {
return {};
}
-export async function getGithubRelease() {
+export async function fetchExternalData(url: string) {
try {
- const response = await fetch(GITHUB_RELEASE_URL);
+ const response = await fetch(url);
if (!response.ok) {
const message = `An error has occured: ${response.status}`;
throw new Error(message);
@@ -131,6 +131,10 @@ export async function getGithubRelease() {
return {};
}
+export async function getGithubRelease() {
+ return fetchExternalData(GITHUB_RELEASE_URL);
+}
+
// Stolen from https://gist.github.com/prenagha/98bbb03e27163bc2f5e4
const VPAT = /^\d+(\.\d+){0,2}$/;
function upToDate(local, remote) {