mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
add CreateBoardModal UI
This commit is contained in:
@@ -0,0 +1,146 @@
|
|||||||
|
import React, { useRef, useState } from 'react';
|
||||||
|
import { StyledModal } from '../styled/modals/CreateBoardModal.styled';
|
||||||
|
import useGeneralStore from '../../hooks/stores/useGeneralStore';
|
||||||
|
import Modal from 'react-modal';
|
||||||
|
import useError from '../../hooks/useError';
|
||||||
|
|
||||||
|
const CreateBoardModal = ({ isOpen, closeModal }) => {
|
||||||
|
const { selectedStyle } = useGeneralStore(state => state);
|
||||||
|
|
||||||
|
const nodeRef = useRef(null);
|
||||||
|
|
||||||
|
const [boardTitle, setBoardTitle] = useState('');
|
||||||
|
const [description, setDescription] = useState('');
|
||||||
|
const [rule, setRule] = useState('');
|
||||||
|
const [rules, setRules] = useState([]);
|
||||||
|
const [editIndex, setEditIndex] = useState(-1);
|
||||||
|
|
||||||
|
const [, setNewErrorMessage] = useError();
|
||||||
|
|
||||||
|
|
||||||
|
const handleAddRule = () => {
|
||||||
|
if (rule.trim() === '') {
|
||||||
|
setNewErrorMessage('Rule field is empty');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rules.length >= 15) {
|
||||||
|
setNewErrorMessage('Maximum number of rules is 15');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(editIndex > -1){
|
||||||
|
setRules(rules.map((r, i) => i === editIndex ? rule : r));
|
||||||
|
setEditIndex(-1);
|
||||||
|
} else {
|
||||||
|
setRules([...rules, rule]);
|
||||||
|
}
|
||||||
|
setRule('');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const handleKeyDown = (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
handleAddRule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const handleEditRule = (index) => {
|
||||||
|
setRule(rules[index]);
|
||||||
|
setEditIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const handleDeleteRule = (index) => {
|
||||||
|
if (index === editIndex) {
|
||||||
|
setEditIndex(-1);
|
||||||
|
}
|
||||||
|
setRules(rules.filter((_, i) => i !== index));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledModal
|
||||||
|
isOpen={isOpen}
|
||||||
|
onRequestClose={closeModal}
|
||||||
|
contentLabel="Create Board"
|
||||||
|
selectedStyle={selectedStyle}
|
||||||
|
style={{ overlay: { backgroundColor: "rgba(0,0,0,.25)" }}}
|
||||||
|
>
|
||||||
|
<div className="modal-content" ref={nodeRef}>
|
||||||
|
<div className="modal-header">
|
||||||
|
Create Board
|
||||||
|
<button className="icon" onClick={() => closeModal()} title="close" />
|
||||||
|
</div>
|
||||||
|
<ul id="form">
|
||||||
|
<div id="explaination">NOTE: plebbit is P2P, your board will stay online for as long as you leave the plebchan desktop app (full node) connected to the Internet.</div>
|
||||||
|
<li className='settings-option disc'>
|
||||||
|
Title
|
||||||
|
</li>
|
||||||
|
<div className='settings-tip'>
|
||||||
|
Optional, useful to describe the board next to its p/address.
|
||||||
|
</div>
|
||||||
|
<div className='settings-input'>
|
||||||
|
<input
|
||||||
|
id="name"
|
||||||
|
type="text"
|
||||||
|
value={boardTitle}
|
||||||
|
onChange={(e) => setBoardTitle(e.target.value)}
|
||||||
|
placeholder="Add a title"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<li className='settings-option disc'>
|
||||||
|
Description
|
||||||
|
</li>
|
||||||
|
<div className='settings-tip'>
|
||||||
|
Optional, displayed as sticky with the board's avatar if set.
|
||||||
|
</div>
|
||||||
|
<div className='settings-input'>
|
||||||
|
<textarea
|
||||||
|
id="description"
|
||||||
|
type="text"
|
||||||
|
value={description}
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
placeholder="Add a description"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<li className='settings-option disc'>
|
||||||
|
Rules
|
||||||
|
</li>
|
||||||
|
<div className='settings-tip'>
|
||||||
|
Optional, listed in a sticky on top. Maximum 15 rules.
|
||||||
|
</div>
|
||||||
|
<div className='settings-input'>
|
||||||
|
<input
|
||||||
|
id="rule"
|
||||||
|
type="text"
|
||||||
|
value={rule}
|
||||||
|
onChange={(e) => setRule(e.target.value)}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
placeholder="Add a rule"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
<button id="rule-btn" onClick={handleAddRule}>{editIndex > -1 ? "Update Rule" : "Add Rule"}</button>
|
||||||
|
</legend>
|
||||||
|
{rules.map((rule, index) => (
|
||||||
|
<div key={index} className="rule-item">
|
||||||
|
<p>{index+1}. {rule}</p>
|
||||||
|
<button onClick={() => handleEditRule(index)}>Edit</button>
|
||||||
|
<button onClick={() => handleDeleteRule(index)}>Delete</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</fieldset>
|
||||||
|
<button id="create-board-btn">Create Board</button>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</StyledModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Modal.setAppElement('#root');
|
||||||
|
|
||||||
|
export default CreateBoardModal;
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
import styled from "styled-components";
|
||||||
|
import Modal from "react-modal";
|
||||||
|
|
||||||
|
export const StyledModal = styled(Modal)`
|
||||||
|
.modal-content {
|
||||||
|
top: 25%;
|
||||||
|
width: 450px;
|
||||||
|
max-height: 650px;
|
||||||
|
left: calc(50% - 50px);
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-left: -178px;
|
||||||
|
position: absolute;
|
||||||
|
padding: 5px 5px 5px;
|
||||||
|
box-shadow: 0 0 5px rgba(0, 0, 0, .25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-top: 1px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
all: unset;
|
||||||
|
float: right;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: -4px;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#name, #description, #rule {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
outline: medium none;
|
||||||
|
width: 298px;
|
||||||
|
padding: 2px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#form {
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
min-width: 296px;
|
||||||
|
float: left;
|
||||||
|
font-size: 10pt;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
margin-top: 0.5px;
|
||||||
|
margin-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rule-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rule-item p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px;
|
||||||
|
width: 200px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
margin-left: 24px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
margin-left: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#create-board-btn {
|
||||||
|
margin: auto;
|
||||||
|
margin-bottom: -10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-option {
|
||||||
|
margin: 5px 0 5px 0;
|
||||||
|
padding-left: 23px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-tip {
|
||||||
|
font-size: 0.85em;
|
||||||
|
margin: 0 0 5px 0;
|
||||||
|
padding-left: 23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-option.disc::before {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
width: 4px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: currentColor;
|
||||||
|
position: absolute;
|
||||||
|
margin-left: -15px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-option {
|
||||||
|
margin: 5px 0 5px 0;
|
||||||
|
padding-left: 23px;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-input {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 23px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding-left: 5px;
|
||||||
|
left: 4px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-input::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 10px;
|
||||||
|
height: 1px;
|
||||||
|
background-color: currentColor;
|
||||||
|
position: absolute;
|
||||||
|
left: 28px;
|
||||||
|
top: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-input::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 1px;
|
||||||
|
height: 12px;
|
||||||
|
background-color: currentColor;
|
||||||
|
position: absolute;
|
||||||
|
left: 28px;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin-left: 25px;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#explaination {
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin: -10px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
${({ selectedStyle }) => {
|
||||||
|
switch (selectedStyle) {
|
||||||
|
case 'Yotsuba':
|
||||||
|
return `
|
||||||
|
.modal-content {
|
||||||
|
background-color: #f0e0d6;
|
||||||
|
border: 1px solid #d9bfb7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: 1px solid #d9bfb7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-image: url(assets/buttons/cross_red.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #000;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
case 'Yotsuba-B':
|
||||||
|
return `
|
||||||
|
.modal-content {
|
||||||
|
background-color: #d6daf0;
|
||||||
|
border: 1px solid #b7c5d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: 1px solid #b7c5d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-image: url(assets/buttons/cross_blue.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #000;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
case 'Futaba':
|
||||||
|
return `
|
||||||
|
.modal-content {
|
||||||
|
background-color: #f0e0d6;
|
||||||
|
border: 1px solid #d9bfb7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-image: url(assets/buttons/cross_red.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #000;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
case 'Burichan':
|
||||||
|
return `
|
||||||
|
.modal-content {
|
||||||
|
background-color: #d6daf0;
|
||||||
|
border: 1px solid #b7c5d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-image: url(assets/buttons/cross_blue.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #000;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
case 'Tomorrow':
|
||||||
|
return `
|
||||||
|
.modal-content {
|
||||||
|
background-color: #282a2e;
|
||||||
|
border: 1px solid #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: 1px solid #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-image: url(assets/buttons/cross_dark.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#name, #description, #rule {
|
||||||
|
background-color: #282a2e;
|
||||||
|
color: #c5c8c6;
|
||||||
|
border: 1px solid #515151;
|
||||||
|
width: 296px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
background-color: #282a2e;
|
||||||
|
color: #c5c8c6;
|
||||||
|
border: 1px solid #515151;
|
||||||
|
}
|
||||||
|
|
||||||
|
#response {
|
||||||
|
background-color: #282a2e;
|
||||||
|
color: #c5c8c6;
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid #515151;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #c5c8c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
button, select, input, textarea, fieldset {
|
||||||
|
filter: brightness(80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset button {
|
||||||
|
filter: brightness(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea, input {
|
||||||
|
color: white !important;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
case 'Photon':
|
||||||
|
return `
|
||||||
|
.modal-content {
|
||||||
|
background-color: #ddd;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.20);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.20);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-image: url(assets/buttons/cross_photon.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #000;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
`;
|
||||||
Reference in New Issue
Block a user