diff --git a/web/components/config/edit-instance-details.tsx b/web/components/config/edit-instance-details.tsx
index 4f7311467..70e1dbac1 100644
--- a/web/components/config/edit-instance-details.tsx
+++ b/web/components/config/edit-instance-details.tsx
@@ -13,15 +13,14 @@ import {
TEXTFIELD_PROPS_SERVER_NAME,
TEXTFIELD_PROPS_SERVER_SUMMARY,
TEXTFIELD_PROPS_SERVER_WELCOME_MESSAGE,
- TEXTFIELD_PROPS_LOGO,
API_YP_SWITCH,
FIELD_PROPS_YP,
FIELD_PROPS_NSFW,
} from '../../utils/config-constants';
-import { NEXT_PUBLIC_API_HOST } from '../../utils/apis';
import { UpdateArgs } from '../../types/config-section';
import ToggleSwitch from './form-toggleswitch';
+import EditLogo from './edit-logo';
const { Title } = Typography;
@@ -106,16 +105,11 @@ export default function EditInstanceDetails() {
initialValue={instanceDetails.welcomeMessage}
onChange={handleFieldChange}
/>
-
- {instanceDetails.logo && }
-
+ {/* Logo section */}
+
+
+
Increase your audience by appearing in the{' '}
diff --git a/web/components/config/edit-logo.tsx b/web/components/config/edit-logo.tsx
new file mode 100644
index 000000000..89ff83812
--- /dev/null
+++ b/web/components/config/edit-logo.tsx
@@ -0,0 +1,122 @@
+import { Button, Upload } from 'antd';
+import { RcFile } from 'antd/lib/upload/interface';
+import { LoadingOutlined, UploadOutlined } from '@ant-design/icons';
+import React, { useState, useContext } from 'react';
+import FormStatusIndicator from './form-status-indicator';
+import { ServerStatusContext } from '../../utils/server-status-context';
+import {
+ postConfigUpdateToAPI,
+ RESET_TIMEOUT,
+ TEXTFIELD_PROPS_LOGO,
+} from '../../utils/config-constants';
+import {
+ createInputStatus,
+ StatusState,
+ STATUS_ERROR,
+ STATUS_PROCESSING,
+ STATUS_SUCCESS,
+} from '../../utils/input-statuses';
+
+const ACCEPTED_FILE_TYPES = ['image/svg+xml', 'image/png', 'image/jpeg', 'image/gif'];
+
+function getBase64(img: File | Blob, callback: (imageUrl: string | ArrayBuffer) => void) {
+ const reader = new FileReader();
+ reader.addEventListener('load', () => callback(reader.result));
+ reader.readAsDataURL(img);
+}
+
+export default function EditLogo() {
+ const [logoUrl, setlogoUrl] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const serverStatusData = useContext(ServerStatusContext);
+ const { setFieldInConfigState, serverConfig } = serverStatusData || {};
+ const currentLogo = serverConfig?.instanceDetails?.logo;
+
+ const [submitStatus, setSubmitStatus] = useState(null);
+ let resetTimer = null;
+
+ const { apiPath, tip } = TEXTFIELD_PROPS_LOGO;
+
+ // Clear out any validation states and messaging
+ const resetStates = () => {
+ setSubmitStatus(null);
+ clearTimeout(resetTimer);
+ resetTimer = null;
+ };
+
+ // validate file type and create base64 encoded img
+ const beforeUpload = (file: RcFile) => {
+ setLoading(true);
+
+ // eslint-disable-next-line consistent-return
+ return new Promise((res, rej) => {
+ if (!ACCEPTED_FILE_TYPES.includes(file.type)) {
+ const msg = `File type is not supported: ${file.type}`;
+ setSubmitStatus(createInputStatus(STATUS_ERROR, `There was an error: ${msg}`));
+ resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
+ setLoading(false);
+ return rej();
+ }
+
+ getBase64(file, (url: string) => {
+ setlogoUrl(url);
+ return res();
+ });
+ });
+ };
+
+ // Post new logo to api
+ const handleLogoUpdate = async () => {
+ if (logoUrl !== currentLogo) {
+ setSubmitStatus(createInputStatus(STATUS_PROCESSING));
+
+ await postConfigUpdateToAPI({
+ apiPath,
+ data: { value: logoUrl },
+ onSuccess: () => {
+ setFieldInConfigState({ fieldName: 'logo', value: logoUrl, path: '' });
+ setSubmitStatus(createInputStatus(STATUS_SUCCESS));
+ setLoading(false);
+ },
+ onError: (msg: string) => {
+ setSubmitStatus(createInputStatus(STATUS_ERROR, `There was an error: ${msg}`));
+ setLoading(false);
+ },
+ });
+ resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
+ }
+ };
+
+ return (
+
+
+ Logo
+
+
+
+
+
+
+ {loading ? (
+
+ ) : (
+ } />
+ )}
+
+
+
+
{tip}
+
+
+ );
+}
diff --git a/web/styles/config-public-details.scss b/web/styles/config-public-details.scss
index c03d9a13b..69835a009 100644
--- a/web/styles/config-public-details.scss
+++ b/web/styles/config-public-details.scss
@@ -38,13 +38,6 @@
}
.instance-details-container {
width: 100%;
-
- .logo-preview {
- display: inline-block;
- margin: -1em 0 1em 11em;
- height: 120px;
- border: 1px solid var(--white-25);
- }
}
.social-items-container {
background-color: var(--container-bg-color-alt);
@@ -74,3 +67,19 @@
.other-field-container {
margin: 0.5em 0;
}
+
+
+.logo-upload-container {
+ .input-group {
+ align-items: center;
+ }
+ img.logo-preview {
+ min-height: 120px;
+ min-width: 120px;
+ max-height: 256px;
+ max-width: 256px;
+ margin-right: 1em;
+ display: inline-block;
+ border: 1px solid var(--white-25);
+ }
+}
diff --git a/web/utils/config-constants.tsx b/web/utils/config-constants.tsx
index ac5b68891..af04be30f 100644
--- a/web/utils/config-constants.tsx
+++ b/web/utils/config-constants.tsx
@@ -79,7 +79,7 @@ export const TEXTFIELD_PROPS_LOGO = {
placeholder: '/img/mylogo.png',
label: 'Logo',
tip:
- 'Name of your logo in the data directory. We recommend that you use a square image that is at least 256x256.',
+ 'Upload your logo if you have one. We recommend that you use a square image that is at least 256x256.',
};
export const TEXTFIELD_PROPS_STREAM_KEY = {
apiPath: API_STREAM_KEY,