mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
add board settings UI and base logic
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { StyledModal } from './styled/modals/ModerationModal.styled';
|
||||
import useError from "../hooks/useError";
|
||||
import useSuccess from "../hooks/useSuccess";
|
||||
import useGeneralStore from '../hooks/stores/useGeneralStore';
|
||||
|
||||
const BoardSettings = ({ subplebbit }) => {
|
||||
const generateSettingsFromSubplebbit = (subplebbitData) => ({
|
||||
address: subplebbitData.address,
|
||||
apiUrl: subplebbitData.apiUrl,
|
||||
description: subplebbitData.description,
|
||||
pubsubTopic: subplebbitData.pubsubTopic,
|
||||
settings: {
|
||||
fetchThumbnailUrls: subplebbitData.settings?.fetchThumbnailUrls,
|
||||
fetchThumbnailUrlsProxyUrl: subplebbitData.settings?.fetchThumbnailUrlsProxyUrl,
|
||||
},
|
||||
roles: subplebbitData.roles,
|
||||
rules: subplebbitData.rules,
|
||||
suggested: {
|
||||
avatarUrl: subplebbitData.suggested?.avatarUrl,
|
||||
backgroundUrl: subplebbitData.suggested?.backgroundUrl,
|
||||
bannerUrl: subplebbitData.suggested?.bannerUrl,
|
||||
language: subplebbitData.suggested?.language,
|
||||
primaryColor: subplebbitData.suggested?.primaryColor,
|
||||
secondaryColor: subplebbitData.suggested?.secondaryColor,
|
||||
},
|
||||
title: subplebbitData.title,
|
||||
});
|
||||
|
||||
const initialSettings = generateSettingsFromSubplebbit(subplebbit);
|
||||
const { selectedStyle } = useGeneralStore(state => state);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [boardSettingsJson, setBoardSettingsJson] = useState(JSON.stringify(initialSettings, null, 2));
|
||||
|
||||
const [, setNewErrorMessage] = useError();
|
||||
const [, setNewSuccessMessage] = useSuccess();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setBoardSettingsJson(JSON.stringify(generateSettingsFromSubplebbit(subplebbit), null, 2));
|
||||
}, [subplebbit]);
|
||||
|
||||
|
||||
function validateSettings(updatedSettings, allowedSettings) {
|
||||
for (let key in updatedSettings) {
|
||||
if (!allowedSettings.hasOwnProperty(key)) {
|
||||
throw new Error(`Unexpected setting: ${key}`);
|
||||
}
|
||||
|
||||
if (typeof updatedSettings[key] === 'object' && updatedSettings[key] !== null) {
|
||||
validateSettings(updatedSettings[key], allowedSettings[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add API logic
|
||||
const handleSaveChanges = async () => {
|
||||
try {
|
||||
const updatedSettings = JSON.parse(boardSettingsJson);
|
||||
validateSettings(updatedSettings, initialSettings);
|
||||
|
||||
|
||||
|
||||
setNewSuccessMessage("Changes saved successfully");
|
||||
} catch (error) {
|
||||
setNewErrorMessage(`Error saving changes: `, error)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleResetChanges = () => {
|
||||
setBoardSettingsJson(JSON.stringify(initialSettings, null, 2));
|
||||
};
|
||||
// TODO: add API logic
|
||||
|
||||
|
||||
function generateSettingsList(settingsObj, parentKey = '') {
|
||||
let result = [];
|
||||
|
||||
for (let key in settingsObj) {
|
||||
if (typeof settingsObj[key] === 'object' && settingsObj[key] !== null) {
|
||||
const nestedItems = generateSettingsList(settingsObj[key], `${parentKey}${key}.`);
|
||||
if (nestedItems.length > 1) {
|
||||
result.push(`${parentKey}${key}: { ${nestedItems.join(', ')} }`);
|
||||
} else {
|
||||
result.push(...nestedItems);
|
||||
}
|
||||
} else {
|
||||
result.push(`${parentKey}${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const possibleSettingsList = generateSettingsList(initialSettings);
|
||||
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledModal
|
||||
isOpen={isModalOpen}
|
||||
onRequestClose={handleCloseModal}
|
||||
contentLabel="Board Settings"
|
||||
style={{ overlay: { backgroundColor: "rgba(0,0,0,.25)" }}}
|
||||
selectedStyle={selectedStyle}
|
||||
>
|
||||
<div className="panel-board">
|
||||
<div className="panel-header">
|
||||
Board Settings
|
||||
<Link to="" onClick={handleCloseModal}>
|
||||
<span className="icon" title="close" />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="settings-info">
|
||||
<div>
|
||||
<strong>Allowed settings: </strong>
|
||||
<span>
|
||||
{`{ ${possibleSettingsList.join(', ')} }`}
|
||||
</span>
|
||||
</div>
|
||||
<strong style={{marginTop: '10px', display: 'inline-block'}}>API docs: </strong><a style={{color: 'inherit'}} href="https://github.com/plebbit/plebbit-js#readme" target="_blank" rel="noreferrer">https://github.com/plebbit/plebbit-js#readme</a>
|
||||
</div>
|
||||
<textarea
|
||||
value={boardSettingsJson}
|
||||
onChange={e => setBoardSettingsJson(e.target.value)}
|
||||
className="board-settings"
|
||||
/>
|
||||
<div className="button-group">
|
||||
<button id="reset-board-settings" onClick={handleResetChanges}>Reset</button>
|
||||
<button id="save-board-settings" onClick={handleSaveChanges}>Save Changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</StyledModal>
|
||||
[
|
||||
<span id="subscribe" style={{ cursor: 'pointer' }}>
|
||||
<span
|
||||
onClick={() => {
|
||||
window.electron && window.electron.isElectron
|
||||
? setIsModalOpen(true)
|
||||
: alert(
|
||||
'To edit this board you must be using the plebchan desktop app, which is a plebbit full node that seeds the board automatically.\n\nDownload plebchan here:\n\nhttps://github.com/plebbit/plebchan/releases/latest'
|
||||
);
|
||||
}}
|
||||
>
|
||||
Board Settings
|
||||
</span>
|
||||
</span>
|
||||
]
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoardSettings;
|
||||
@@ -22,6 +22,31 @@ export const StyledModal = styled(Modal)`
|
||||
}
|
||||
}
|
||||
|
||||
.panel-board {
|
||||
top: 120px;
|
||||
width: 700px;
|
||||
height: auto;
|
||||
max-height: 80%;
|
||||
left: calc(50% - 350px);
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
padding: 2px 5px 5px;
|
||||
font-size: 14px;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, .25);
|
||||
|
||||
@media (max-width: 800px) {
|
||||
width: 80%;
|
||||
max-height: 60%;
|
||||
left: calc(50% - 40%);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
width: 320px;
|
||||
max-height: 60%;
|
||||
left: calc(50% - 160px);
|
||||
}
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
@@ -124,6 +149,13 @@ export const StyledModal = styled(Modal)`
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.board-settings {
|
||||
width: 83%;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 20px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.save-button {
|
||||
margin: auto;
|
||||
margin-bottom: 10px;
|
||||
@@ -132,11 +164,34 @@ export const StyledModal = styled(Modal)`
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#save-board-settings, #reset-board-settings {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.settings-info {
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
margin: 10px 10px 0 10px;
|
||||
font-size: 0.9em;
|
||||
line-break: anywhere;
|
||||
}
|
||||
|
||||
.settings-info strong {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
${({ selectedStyle }) => {
|
||||
switch (selectedStyle) {
|
||||
case 'Yotsuba':
|
||||
return `
|
||||
.panel {
|
||||
.panel, .panel-board {
|
||||
background-color: #f0e0d6;
|
||||
}
|
||||
|
||||
@@ -166,7 +221,7 @@ export const StyledModal = styled(Modal)`
|
||||
|
||||
case 'Yotsuba-B':
|
||||
return `
|
||||
.panel {
|
||||
.panel, .panel-board {
|
||||
background-color: #d6daf0;
|
||||
}
|
||||
|
||||
@@ -196,7 +251,7 @@ export const StyledModal = styled(Modal)`
|
||||
|
||||
case 'Futaba':
|
||||
return `
|
||||
.panel {
|
||||
.panel, .panel-board {
|
||||
background-color: #f0e0d6;
|
||||
}
|
||||
|
||||
@@ -226,7 +281,7 @@ export const StyledModal = styled(Modal)`
|
||||
|
||||
case 'Burichan':
|
||||
return `
|
||||
.panel {
|
||||
.panel, .panel-board {
|
||||
background-color: #d6daf0;
|
||||
}
|
||||
|
||||
@@ -256,7 +311,7 @@ export const StyledModal = styled(Modal)`
|
||||
|
||||
case 'Tomorrow':
|
||||
return `
|
||||
.panel {
|
||||
.panel, .panel-board {
|
||||
background-color: #282a2e;
|
||||
}
|
||||
|
||||
@@ -296,7 +351,7 @@ export const StyledModal = styled(Modal)`
|
||||
|
||||
case 'Photon':
|
||||
return `
|
||||
.panel {
|
||||
.panel, .panel-board {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import EditLabel from '../EditLabel';
|
||||
import ImageBanner from '../ImageBanner';
|
||||
import AdminListModal from '../modals/AdminListModal';
|
||||
import ModerationModal from '../modals/ModerationModal';
|
||||
import BoardSettings from '../BoardSettings';
|
||||
import OfflineIndicator from '../OfflineIndicator';
|
||||
import PendingLabel from '../PendingLabel';
|
||||
import Post from '../Post';
|
||||
@@ -906,6 +907,9 @@ const Board = () => {
|
||||
{subplebbit?.state === "succeeded" ? (
|
||||
<>
|
||||
<span className="subscribe-button-desktop">
|
||||
{subplebbit?.roles[account?.author?.address]?.role === "admin" ? (
|
||||
<BoardSettings subplebbit={subplebbit} />
|
||||
) : null}
|
||||
[
|
||||
<span id="subscribe" style={{cursor: 'pointer'}}>
|
||||
<span onClick={() => handleSubscribe()}>
|
||||
|
||||
@@ -17,6 +17,7 @@ import ImageBanner from '../ImageBanner';
|
||||
import VerifiedAuthor from '../VerifiedAuthor';
|
||||
import CreateBoardModal from '../modals/CreateBoardModal';
|
||||
import ModerationModal from '../modals/ModerationModal';
|
||||
import BoardSettings from '../BoardSettings';
|
||||
import OfflineIndicator from '../OfflineIndicator';
|
||||
import SettingsModal from '../modals/SettingsModal';
|
||||
import countLinks from '../../utils/countLinks';
|
||||
@@ -1263,6 +1264,9 @@ const Catalog = () => {
|
||||
{subplebbit.state === "succeeded" ? (
|
||||
<>
|
||||
<span className="subscribe-button-desktop">
|
||||
{subplebbit?.roles[account?.author?.address]?.role === "admin" ? (
|
||||
<BoardSettings subplebbit={subplebbit} />
|
||||
) : null}
|
||||
[
|
||||
<span id="subscribe" style={{cursor: 'pointer'}}>
|
||||
<span onClick={() => handleSubscribe()}>
|
||||
|
||||
Reference in New Issue
Block a user