diff --git a/web/pages/components/config/form-textfield.tsx b/web/pages/components/config/form-textfield.tsx
index 096ac370a..b14e3d0d1 100644
--- a/web/pages/components/config/form-textfield.tsx
+++ b/web/pages/components/config/form-textfield.tsx
@@ -60,7 +60,7 @@ export default function TextField(props: TextFieldProps) {
setHasChanged(false);
clearTimeout(resetTimer);
resetTimer = null;
- }
+ };
// if field is required but value is empty, or equals initial value, then don't show submit/update button. otherwise clear out any result messaging and display button.
const handleChange = (e: any) => {
diff --git a/web/pages/components/main-layout.tsx b/web/pages/components/main-layout.tsx
index 28ec1d1a2..f9fa310bb 100644
--- a/web/pages/components/main-layout.tsx
+++ b/web/pages/components/main-layout.tsx
@@ -150,6 +150,9 @@ export default function MainLayout(props) {
Storage
+
+ Custom page content
+
import('react-markdown-editor-lite'), {
+ ssr: false,
+});
+
+export default function PageContentEditor() {
+ const [content, setContent] = useState('');
+ const [submitStatus, setSubmitStatus] = useState('');
+ const [submitStatusMessage, setSubmitStatusMessage] = useState('');
+ const [hasChanged, setHasChanged] = useState(false);
+
+ const serverStatusData = useContext(ServerStatusContext);
+ const { serverConfig, setFieldInConfigState } = serverStatusData || {};
+
+ const { instanceDetails } = serverConfig;
+ const { extraPageContent: initialContent } = instanceDetails;
+
+ const { apiPath } = TEXTFIELD_DEFAULTS.instanceDetails.extraPageContent;
+
+ let resetTimer = null;
+
+ function handleEditorChange({ text }) {
+ setContent(text);
+ if (text !== initialContent && !hasChanged) {
+ setHasChanged(true);
+ } else if (text === initialContent && hasChanged) {
+ setHasChanged(false);
+ }
+ }
+
+ // Clear out any validation states and messaging
+ const resetStates = () => {
+ setSubmitStatus('');
+ setHasChanged(false);
+ clearTimeout(resetTimer);
+ resetTimer = null;
+ };
+
+ // posts all the tags at once as an array obj
+ async function handleSave() {
+ setSubmitStatus('validating');
+ await postConfigUpdateToAPI({
+ apiPath,
+ data: { value: content },
+ onSuccess: () => {
+ setFieldInConfigState({ fieldName: 'extraPageContent', value: content, path: apiPath });
+ setSubmitStatus('success');
+ },
+ onError: (message: string) => {
+ setSubmitStatus('error');
+ setSubmitStatusMessage(`There was an error: ${message}`);
+ },
+ });
+ resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
+ }
+
+ useEffect(() => {
+ setContent(initialContent);
+ }, [instanceDetails]);
+
+ const {
+ icon: newStatusIcon = null,
+ message: newStatusMessage = '',
+ } = SUCCESS_STATES[submitStatus] || {};
+
+
+ return (
+
+
Edit custom content
+
+
Add some content about your site with the Markdown editor below. This content shows up at the bottom half of your Owncast page.
+
+
mdParser.render(c)}
+ onChange={handleEditorChange}
+ config={{
+ htmlClass: 'markdown-editor-preview-pane',
+ markdownClass: 'markdown-editor-pane',
+ }}
+ />
+
+ { hasChanged ?
Save : null }
+
+ {newStatusIcon} {newStatusMessage} {submitStatusMessage}
+
+
+
+ );
+}
diff --git a/web/pages/config-server-details.tsx b/web/pages/config-server-details.tsx
index 39f284f46..5196983bc 100644
--- a/web/pages/config-server-details.tsx
+++ b/web/pages/config-server-details.tsx
@@ -39,7 +39,7 @@ export default function ConfigServerDetails() {
configPath: '',
};
return (
- <>
+
Edit your Server's details
@@ -53,7 +53,7 @@ export default function ConfigServerDetails() {
- >
+
);
}
diff --git a/web/pages/edit-page-content.tsx b/web/pages/edit-page-content.tsx
deleted file mode 100644
index 55e6ac349..000000000
--- a/web/pages/edit-page-content.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React, { useEffect } from 'react';
-
-import MarkdownIt from 'markdown-it';
-const mdParser = new MarkdownIt(/* Markdown-it options */);
-
-import dynamic from 'next/dynamic';
-import 'react-markdown-editor-lite/lib/index.css';
-
-import { SERVER_CONFIG, fetchData, FETCH_INTERVAL, UPDATE_CHAT_MESSGAE_VIZ } from "../utils/apis";
-
-import { Table, Typography, Tooltip, Button } from "antd";
-
-const MdEditor = dynamic(() => import('react-markdown-editor-lite'), {
- ssr: false
-});
-
-export default function PageContentEditor() {
- const [content, setContent] = React.useState("");
-
- function handleEditorChange({ html, text }) {
- setContent(text);
- }
-
- function handleSave() {
- console.log(content);
- alert("Make API call to save here." + content)
- }
-
- async function setInitialContent() {
- const serverConfig = await fetchData(SERVER_CONFIG);
- const initialContent = serverConfig.instanceDetails.extraPageContent;
- setContent(initialContent);
- }
-
- useEffect(() => {
- setInitialContent();
- }, []);
-
- return (
-
- mdParser.render(content)}
- onChange={handleEditorChange}
- config={{ htmlClass: 'markdown-editor-preview-pane', markdownClass: 'markdown-editor-pane' }}
- />
- Save
-
- );
-}
diff --git a/web/styles/config.scss b/web/styles/config.scss
index af413041f..2361c8e8a 100644
--- a/web/styles/config.scss
+++ b/web/styles/config.scss
@@ -143,3 +143,16 @@
}
}
+.config-page-content-form {
+ .page-content-actions {
+ margin-top: 1em;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+
+ .status-message {
+ margin-left: 1em;
+ }
+ }
+}
diff --git a/web/styles/globals.scss b/web/styles/globals.scss
index 5499ba26c..cd1d7cdcf 100644
--- a/web/styles/globals.scss
+++ b/web/styles/globals.scss
@@ -80,16 +80,16 @@ code {
.rc-md-editor {
// Set the background color of the preview container
.editor-container {
- background-color: black;
+ background-color: #E2E8F0;
+ color: rgba(45,55,72,1);
}
// Custom CSS for formatting the preview text
.markdown-editor-preview-pane {
- color:lightgrey;
+ // color:lightgrey;
a {
color: $owncast-purple;
}
-
h1 {
font-size: 2em;
}
@@ -97,12 +97,15 @@ code {
// Custom CSS class used to format the text of the editor
.markdown-editor-pane {
- color:lightgrey !important;
+ color: white !important;
+ background-color: black;
+ font-family: monospace;
}
// Set the background color of the editor text input
textarea {
background-color: rgb(44,44,44) !important;
+ color:lightgrey !important;
}
// Hide extra toolbar buttons.
diff --git a/web/types/config-section.ts b/web/types/config-section.ts
index 4e60b3eb4..e04c411da 100644
--- a/web/types/config-section.ts
+++ b/web/types/config-section.ts
@@ -9,6 +9,8 @@ export interface TextFieldProps {
required?: boolean;
disabled?: boolean;
onSubmit?: () => void;
+ onBlur?: () => void;
+ onChange?: () => void;
}
export interface ToggleSwitchProps {
@@ -49,7 +51,7 @@ export interface ConfigInstanceDetailsFields {
export interface VideoVariant {
audioBitrate: number;
- audioPassthrough: number;
+ audioPassthrough: false | number;
encoderPreset: 'ultrafast' | 'superfast' | 'veryfast' | 'faster' | 'fast';
framerate: number;
videoBitrate: number;
diff --git a/web/utils/server-status-context.tsx b/web/utils/server-status-context.tsx
index 8d9449961..e39e65e77 100644
--- a/web/utils/server-status-context.tsx
+++ b/web/utils/server-status-context.tsx
@@ -25,6 +25,8 @@ export const initialServerConfigState: ConfigDetails = {
instanceUrl: '',
},
videoSettings: {
+ numberOfPlaylistItems: 5,
+ segmentLengthSeconds: 4,
videoQualityVariants: [
{
audioPassthrough: false,
@@ -32,6 +34,7 @@ export const initialServerConfigState: ConfigDetails = {
videoBitrate: 0,
audioBitrate: 0,
framerate: 0,
+ encoderPreset: 'veryfast',
},
],
}
@@ -93,7 +96,7 @@ const ServerStatusProvider = ({ children }) => {
};
setConfig(updatedConfig);
- }
+ };
useEffect(() => {
@@ -108,7 +111,7 @@ const ServerStatusProvider = ({ children }) => {
return () => {
clearInterval(getStatusIntervalId);
}
- }, [])
+ }, []);
const providerValue = {
...status,