Merge pull request #280 from plebbit/development

Development
This commit is contained in:
plebeius.eth
2023-09-30 21:57:59 +02:00
committed by GitHub
21 changed files with 813 additions and 468 deletions
+142 -189
View File
@@ -28,209 +28,162 @@ import packageJson from '../package.json';
const commitRef = process?.env?.REACT_APP_COMMIT_REF || '';
export default function App() {
const {
bodyStyle,
setBodyStyle,
setDefaultSubplebbits,
isCaptchaOpen,
setIsCaptchaOpen,
setIsSettingsOpen,
selectedStyle,
setSelectedStyle,
setShowPostForm,
setShowPostFormLink,
} = useGeneralStore((state) => state);
const { bodyStyle, setBodyStyle, setDefaultSubplebbits, isCaptchaOpen, setIsCaptchaOpen, setIsSettingsOpen, selectedStyle, setShowPostForm, setShowPostFormLink } =
useGeneralStore((state) => state);
const location = useLocation();
const isHomeRoute = location.pathname === '/';
const isElectron = window.electron && window.electron.isElectron;
const location = useLocation();
const isElectron = window.electron && window.electron.isElectron;
const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess();
const [, setNewInfoMessage] = useInfo();
const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess();
const [, setNewInfoMessage] = useInfo();
const [infoMessageShown, setInfoMessageShown] = useState(false);
const [infoMessageShown, setInfoMessageShown] = useState(false);
useEffect(() => {
const successToast = localStorage.getItem('successToast');
const errorToast = localStorage.getItem('errorToast');
if (successToast) {
setNewSuccessMessage(successToast);
localStorage.removeItem('successToast');
} else if (errorToast) {
setNewErrorMessage(errorToast);
localStorage.removeItem('errorToast');
} else {
return;
}
}, [setNewErrorMessage, setNewSuccessMessage]);
useEffect(() => {
const successToast = localStorage.getItem('successToast');
const errorToast = localStorage.getItem('errorToast');
if (successToast) {
setNewSuccessMessage(successToast);
localStorage.removeItem('successToast');
} else if (errorToast) {
setNewErrorMessage(errorToast);
localStorage.removeItem('errorToast');
} else {
return;
}
}, [setNewErrorMessage, setNewSuccessMessage]);
// check for new version
// TODO: delete this code and toast when v1.0.0 is released
useEffect(() => {
const fetchVersionInfo = async () => {
try {
const packageRes = await fetch('https://raw.githubusercontent.com/plebbit/plebchan/master/package.json', { cache: 'no-cache' });
const packageData = await packageRes.json();
// check for new version
// TODO: delete this code and toast when v1.0.0 is released
useEffect(() => {
const fetchVersionInfo = async () => {
try {
const packageRes = await fetch('https://raw.githubusercontent.com/plebbit/plebchan/master/package.json', { cache: 'no-cache' });
const packageData = await packageRes.json();
if (packageJson.version !== packageData.version && !infoMessageShown) {
const newVersionInfo = isElectron
? `New version available, plebchan v${packageData.version}. You are using v${packageJson.version}. Download the latest version here: https://github.com/plebbit/plebchan/releases/latest`
: `New version available, plebchan v${packageData.version}. You are using v${packageJson.version}. Refresh to update.`;
setNewInfoMessage(newVersionInfo);
setInfoMessageShown(true);
}
if (packageJson.version !== packageData.version && !infoMessageShown) {
const newVersionInfo = isElectron
? `New version available, plebchan v${packageData.version}. You are using v${packageJson.version}. Download the latest version here: https://github.com/plebbit/plebchan/releases/latest`
: `New version available, plebchan v${packageData.version}. You are using v${packageJson.version}. Refresh to update.`;
setNewInfoMessage(newVersionInfo);
setInfoMessageShown(true);
}
if (commitRef.length > 0) {
const commitRes = await fetch('https://api.github.com/repos/plebbit/plebchan/commits?per_page=1&sha=development', { cache: 'no-cache' });
const commitData = await commitRes.json();
if (commitRef.length > 0) {
const commitRes = await fetch('https://api.github.com/repos/plebbit/plebchan/commits?per_page=1&sha=development', { cache: 'no-cache' });
const commitData = await commitRes.json();
const latestCommitHash = commitData[0].sha;
const latestCommitHash = commitData[0].sha;
if (latestCommitHash.trim() !== commitRef.trim() && !infoMessageShown) {
const newVersionInfo = `New dev version available, commit ${latestCommitHash.slice(0, 7)}. You are using commit ${commitRef.slice(0, 7)}. Refresh to update.`;
setNewInfoMessage(newVersionInfo);
setInfoMessageShown(true);
}
}
} catch (error) {
console.error('Failed to fetch latest version info:', error);
}
};
if (latestCommitHash.trim() !== commitRef.trim() && !infoMessageShown) {
const newVersionInfo = `New dev version available, commit ${latestCommitHash.slice(0, 7)}. You are using commit ${commitRef.slice(0, 7)}. Refresh to update.`;
setNewInfoMessage(newVersionInfo);
setInfoMessageShown(true);
}
}
} catch (error) {
console.error('Failed to fetch latest version info:', error);
}
};
fetchVersionInfo();
}, [setNewInfoMessage, isElectron, infoMessageShown]);
fetchVersionInfo();
}, [setNewInfoMessage, isElectron, infoMessageShown]);
// preload banners
useEffect(() => {
const loadImages = async () => {
const images = await importAll(require.context('../public/assets', true, /\.(png|jpe?g|svg)$/));
const imageUrls = images.map((image) => image.default);
preloadImages(imageUrls);
};
// preload banners
useEffect(() => {
const loadImages = async () => {
const images = await importAll(require.context('../public/assets', true, /\.(png|jpe?g|svg)$/));
const imageUrls = images.map((image) => image.default);
preloadImages(imageUrls);
};
loadImages();
}, []);
loadImages();
}, []);
// automatic dark mode without interefering with user's selected style
useEffect(() => {
if (isHomeRoute) return;
// fetch default subplebbits
useEffect(() => {
let didCancel = false;
fetch('https://raw.githubusercontent.com/plebbit/temporary-default-subplebbits/master/subplebbits.json', { cache: 'no-cache' })
.then((res) => res.json())
.then((res) => {
if (!didCancel) {
setDefaultSubplebbits(res);
}
});
return () => {
didCancel = true;
};
}, [setDefaultSubplebbits]);
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const isDarkMode = darkModeMediaQuery.matches;
// handle nested routes
useEffect(() => {
const path = location.pathname;
if (path.endsWith('/post')) {
setShowPostFormLink(false);
setShowPostForm(true);
} else {
setShowPostFormLink(true);
setShowPostForm(false);
}
if (isDarkMode && !isHomeRoute) {
setSelectedStyle('Tomorrow');
setBodyStyle({
background: '#1d1f21 none',
color: '#c5c8c6',
fontFamily: 'Arial, Helvetica, sans-serif',
});
localStorage.setItem('selectedStyle', 'Tomorrow');
}
if (path.endsWith('/settings')) {
setIsSettingsOpen(true);
} else {
setIsSettingsOpen(false);
}
}, [location.pathname, setIsSettingsOpen, setShowPostForm, setShowPostFormLink]);
const darkModeListener = (e) => {
if (e.matches && !isHomeRoute) {
setSelectedStyle('Tomorrow');
setBodyStyle({
background: '#1d1f21 none',
color: '#c5c8c6',
fontFamily: 'Arial, Helvetica, sans-serif',
});
localStorage.setItem('selectedStyle', 'Tomorrow');
}
};
darkModeMediaQuery.addEventListener('change', darkModeListener);
return () => {
darkModeMediaQuery.removeEventListener('change', darkModeListener);
};
}, [isHomeRoute, setBodyStyle, setSelectedStyle]);
// fetch default subplebbits
useEffect(() => {
let didCancel = false;
fetch('https://raw.githubusercontent.com/plebbit/temporary-default-subplebbits/master/subplebbits.json', { cache: 'no-cache' })
.then((res) => res.json())
.then((res) => {
if (!didCancel) {
setDefaultSubplebbits(res);
}
});
return () => {
didCancel = true;
};
}, [setDefaultSubplebbits]);
// handle nested routes
useEffect(() => {
const path = location.pathname;
if (path.endsWith('/post')) {
setShowPostFormLink(false);
setShowPostForm(true);
} else {
setShowPostFormLink(true);
setShowPostForm(false);
}
if (path.endsWith('/settings')) {
setIsSettingsOpen(true);
} else {
setIsSettingsOpen(false);
}
}, [location.pathname, setIsSettingsOpen, setShowPostForm, setShowPostFormLink]);
return (
<div>
<Helmet>
<link rel='apple-touch-icon' sizes='180x180' href='assets/logo/apple-touch-icon.png' />
<link rel='icon' type='image/png' sizes='32x32' href='assets/logo/favicon-32x32.png' />
<link rel='icon' type='image/png' sizes='16x16' href='assets/logo/favicon-16x16.png' />
<link rel='manifest' href='site.webmanifest' />
<meta name='msapplication-TileColor' content='#fee9cd' />
<meta name='theme-color' content='#ffffff' />
</Helmet>
<GlobalStyle background={bodyStyle.background} color={bodyStyle.color} fontFamily={bodyStyle.fontFamily} />
<Routes>
<Route exact path='/' element={<Home setBodyStyle={setBodyStyle} />} />
<Route path={`/p/:subplebbitAddress`} element={<Board setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Board />} />
<Route path='settings' element={<Board />} />
</Route>
<Route path={`/p/:subplebbitAddress/c/:threadCid`} element={<Thread setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Thread />} />
<Route path='settings' element={<Thread />} />
</Route>
<Route path={`/p/:subplebbitAddress/catalog`} element={<Catalog setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Catalog />} />
<Route path='settings' element={<Catalog />} />
</Route>
<Route path={`/p/:subplebbitAddress/description`} element={<Description setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Description />} />
</Route>
<Route path={`/p/:subplebbitAddress/rules`} element={<Rules setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Rules />} />
</Route>
<Route path={`/profile/c/:index`} element={<Pending setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Pending />} />
</Route>
<Route path={`/p/subscriptions`} element={<Subscriptions setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Subscriptions />} />
</Route>
<Route path={`p/subscriptions/catalog`} element={<SubscriptionsCatalog setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<SubscriptionsCatalog />} />
</Route>
<Route path={`p/all`} element={<All setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<All />} />
</Route>
<Route path={`p/all/catalog`} element={<AllCatalog setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<AllCatalog />} />
</Route>
<Route path='*' element={<NotFound setBodyStyle={setBodyStyle} />} />
</Routes>
<Toast />
<CaptchaModal selectedStyle={selectedStyle} isOpen={isCaptchaOpen} closeModal={() => setIsCaptchaOpen(false)} />
</div>
);
return (
<div>
<Helmet>
<link rel='apple-touch-icon' sizes='180x180' href='assets/logo/apple-touch-icon.png' />
<link rel='icon' type='image/png' sizes='32x32' href='assets/logo/favicon-32x32.png' />
<link rel='icon' type='image/png' sizes='16x16' href='assets/logo/favicon-16x16.png' />
<link rel='manifest' href='site.webmanifest' />
<meta name='msapplication-TileColor' content='#fee9cd' />
<meta name='theme-color' content='#ffffff' />
</Helmet>
<GlobalStyle background={bodyStyle.background} color={bodyStyle.color} fontFamily={bodyStyle.fontFamily} />
<Routes>
<Route exact path='/' element={<Home setBodyStyle={setBodyStyle} />} />
<Route path={`/p/:subplebbitAddress`} element={<Board setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Board />} />
<Route path='settings' element={<Board />} />
</Route>
<Route path={`/p/:subplebbitAddress/c/:threadCid`} element={<Thread setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Thread />} />
<Route path='settings' element={<Thread />} />
</Route>
<Route path={`/p/:subplebbitAddress/catalog`} element={<Catalog setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Catalog />} />
<Route path='settings' element={<Catalog />} />
</Route>
<Route path={`/p/:subplebbitAddress/description`} element={<Description setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Description />} />
</Route>
<Route path={`/p/:subplebbitAddress/rules`} element={<Rules setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Rules />} />
</Route>
<Route path={`/profile/c/:index`} element={<Pending setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Pending />} />
</Route>
<Route path={`/p/subscriptions`} element={<Subscriptions setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Subscriptions />} />
</Route>
<Route path={`p/subscriptions/catalog`} element={<SubscriptionsCatalog setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<SubscriptionsCatalog />} />
</Route>
<Route path={`p/all`} element={<All setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<All />} />
</Route>
<Route path={`p/all/catalog`} element={<AllCatalog setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<AllCatalog />} />
</Route>
<Route path='*' element={<NotFound setBodyStyle={setBodyStyle} />} />
</Routes>
<Toast />
<CaptchaModal selectedStyle={selectedStyle} isOpen={isCaptchaOpen} closeModal={() => setIsCaptchaOpen(false)} />
</div>
);
}
-1
View File
@@ -81,7 +81,6 @@ const Post = ({ content, postQuoteOnClick, postQuoteOnOver, postQuoteOnLeave, po
parts.push(
<ForwardRefLink
key={`link-${i}-${matchedText}`}
className='quotelink'
to={linkTo}
target={linkTarget}
+15 -13
View File
@@ -43,10 +43,8 @@ const AdminListModal = ({ isOpen, closeModal, roles }) => {
maxHeight: '250px',
}}
>
<button className='icon' onClick={() => closeModal()} title='close' />
<div className='modal-header' style={{ margin: '10px 10px 0px 10px' }}>
Moderators
</div>
<button className='icon' style={{ imageRendering: 'pixelated', margin: '1px 1px 0 0' }} onClick={() => closeModal()} title='close' />
<div className='modal-header'>   Moderators</div>
<div
className='list'
style={{
@@ -60,15 +58,19 @@ const AdminListModal = ({ isOpen, closeModal, roles }) => {
}}
>
<BoardForm selectedStyle={selectedStyle} style={{ all: 'unset' }}>
{rolesList.map(({ address, role }, index) => (
<p key={index}>
{' '}
<Link to={() => {}} className='quote-link'>
u/{address}
</Link>
: {role}
</p>
))}
{roles ? (
rolesList.map(({ address, role }, index) => (
<p key={index}>
{' '}
<Link to={() => {}} className='quote-link'>
u/{address}
</Link>
: {role}
</p>
))
) : (
<p>This board doesn't have moderators yet.</p>
)}
</BoardForm>
</div>
</div>
@@ -2,94 +2,95 @@ import styled from 'styled-components';
import Modal from 'react-modal';
export const StyledModal = styled(Modal)`
.hide-modal-overlay {
display: none;
}
.hide-modal-overlay {
display: none;
}
.modal-content {
position: fixed;
top: calc(50% - 150px);
left: calc(50% - 150px);
display: block;
padding: 2px;
font-size: 10pt;
border-left: none;
border-top: none;
}
.modal-content {
position: fixed;
top: calc(50% - 150px);
left: calc(50% - 150px);
display: block;
padding: 2px;
font-size: 10pt;
border-left: none;
border-top: none;
}
.modal-header {
font-size: 10pt;
text-align: center;
margin-bottom: 1px;
padding: 0;
height: 18px;
line-height: 18px;
cursor: move;
font-weight: 700;
}
.modal-header {
font-size: 10pt;
text-align: center;
margin-bottom: 1px;
padding: 0;
height: 18px;
line-height: 18px;
cursor: move;
font-weight: 700;
}
.icon {
all: unset;
float: right;
cursor: pointer;
margin-bottom: -4px;
width: 18px;
height: 18px;
border: none;
}
.icon {
all: unset;
float: right;
cursor: pointer;
margin-bottom: -4px;
width: 18px;
height: 18px;
border: none;
image-rendering: pixelated;
}
#field {
border: 1px solid #aaa;
font-family: Arial, Helvetica, sans-serif;
font-size: 10pt;
outline: medium none;
width: 298px;
padding: 2px;
}
#field {
border: 1px solid #aaa;
font-family: Arial, Helvetica, sans-serif;
font-size: 10pt;
outline: medium none;
width: 298px;
padding: 2px;
}
textarea {
min-width: 296px;
float: left;
font-size: 10pt;
font-family: Arial, Helvetica, sans-serif;
}
textarea {
min-width: 296px;
float: left;
font-size: 10pt;
font-family: Arial, Helvetica, sans-serif;
}
#captcha-container {
position: relative;
width: 302px;
height: 100px;
overflow: hidden;
margin-bottom: 17px;
}
#captcha-container {
position: relative;
width: 302px;
height: 100px;
overflow: hidden;
margin-bottom: 17px;
}
#response {
width: 100%;
box-sizing: border-box;
font-size: 11px;
height: 18px;
margin: 0px;
padding: 0px 2px;
font-family: monospace;
vertical-align: middle;
}
#response {
width: 100%;
box-sizing: border-box;
font-size: 11px;
height: 18px;
margin: 0px;
padding: 0px 2px;
font-family: monospace;
vertical-align: middle;
}
img {
height: 100%;
width: 100%;
position: relative;
display: block;
}
img {
height: 100%;
width: 100%;
position: relative;
display: block;
}
#nav {
float: right;
margin: 0;
width: auto;
}
#nav {
float: right;
margin: 0;
width: auto;
}
${({ selectedStyle }) => {
switch (selectedStyle) {
case 'Yotsuba':
return `
${({ selectedStyle }) => {
switch (selectedStyle) {
case 'Yotsuba':
return `
.modal-content {
background-color: #f0e0d6;
border: 1px solid #d9bfb7;
@@ -109,8 +110,8 @@ export const StyledModal = styled(Modal)`
color: maroon;
}`;
case 'Yotsuba-B':
return `
case 'Yotsuba-B':
return `
.modal-content {
background-color: #d6daf0;
border: 1px solid #b7c5d9;
@@ -130,8 +131,8 @@ export const StyledModal = styled(Modal)`
color: #000;
}`;
case 'Futaba':
return `
case 'Futaba':
return `
.modal-content {
background-color: #f0e0d6;
border: 1px solid #d9bfb7;
@@ -151,8 +152,8 @@ export const StyledModal = styled(Modal)`
color: maroon;
}`;
case 'Burichan':
return `
case 'Burichan':
return `
.modal-content {
background-color: #d6daf0;
border: 1px solid #b7c5d9;
@@ -172,8 +173,8 @@ export const StyledModal = styled(Modal)`
color: #000;
}`;
case 'Tomorrow':
return `
case 'Tomorrow':
return `
.modal-content {
background-color: #282a2e;
border: 1px solid #111;
@@ -216,8 +217,8 @@ export const StyledModal = styled(Modal)`
filter: brightness(80%);
}`;
case 'Photon':
return `
case 'Photon':
return `
.modal-content {
background-color: #ddd;
border: 1px solid #ccc;
@@ -236,8 +237,8 @@ export const StyledModal = styled(Modal)`
color: #333;
}`;
default:
return '';
}
}}
default:
return '';
}
}}
`;
@@ -1,5 +1,5 @@
import styled from "styled-components";
import Modal from "react-modal";
import styled from 'styled-components';
import Modal from 'react-modal';
export const StyledModal = styled(Modal)`
.modal-content {
@@ -9,10 +9,10 @@ export const StyledModal = styled(Modal)`
transform: translate(-50%, -50%);
width: 450px;
height: auto;
max-height: calc(100vh - 2*50px);
max-height: calc(100vh - 2 * 50px);
overflow-y: auto;
padding: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, .25);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
}
.modal-header {
@@ -33,9 +33,12 @@ export const StyledModal = styled(Modal)`
width: 18px;
height: 18px;
border: none;
image-rendering: pixelated;
}
#name, #description, #rule {
#name,
#description,
#rule {
border: 1px solid #aaa;
font-family: Arial, Helvetica, sans-serif;
font-size: 10pt;
@@ -73,7 +76,6 @@ export const StyledModal = styled(Modal)`
}
#rule {
}
#rule-btn {
@@ -324,10 +326,10 @@ export const StyledModal = styled(Modal)`
span {
color: #000;
}`;
default:
return '';
}
}`;
default:
return '';
}
}}
`;
`;
@@ -1,4 +1,4 @@
import styled from "styled-components";
import styled from 'styled-components';
import Modal from 'react-modal';
export const StyledModal = styled(Modal)`
@@ -13,7 +13,7 @@ export const StyledModal = styled(Modal)`
position: absolute;
padding: 2px 5px 5px;
font-size: 14px;
box-shadow: 0 0 5px rgba(0, 0, 0, .25);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
@media (max-width: 480px) {
width: 320px !important;
@@ -27,12 +27,12 @@ export const StyledModal = styled(Modal)`
width: 700px;
height: auto;
max-height: 80%;
left: calc(50% - 350px);
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);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
@media (max-width: 800px) {
width: 80%;
@@ -66,6 +66,7 @@ export const StyledModal = styled(Modal)`
cursor: pointer;
position: absolute;
top: 5px;
image-rendering: pixelated;
}
h4 {
@@ -171,7 +172,8 @@ export const StyledModal = styled(Modal)`
margin-bottom: 10px;
}
#save-board-settings, #reset-board-settings {
#save-board-settings,
#reset-board-settings {
text-align: center;
}
@@ -184,7 +186,7 @@ export const StyledModal = styled(Modal)`
}
.settings-info strong {
margin-bottom: 10px;
margin-bottom: 10px;
}
${({ selectedStyle }) => {
@@ -378,9 +380,9 @@ export const StyledModal = styled(Modal)`
color: #f30 !important;
}
}`;
default:
return '';
}
default:
return '';
}
}}
`;
`;
@@ -1,5 +1,5 @@
import styled from "styled-components";
import Modal from "react-modal";
import styled from 'styled-components';
import Modal from 'react-modal';
export const StyledModal = styled(Modal)`
.modal-content {
@@ -32,6 +32,7 @@ export const StyledModal = styled(Modal)`
width: 18px;
height: 18px;
border: none;
image-rendering: pixelated;
}
#name {
@@ -249,10 +250,10 @@ export const StyledModal = styled(Modal)`
span {
color: #000;
}`;
default:
return '';
}
}`;
default:
return '';
}
}}
`;
`;
@@ -50,6 +50,7 @@ export const StyledModal = styled(Modal)`
cursor: pointer;
position: absolute;
top: 5px;
image-rendering: pixelated;
}
h4 {
@@ -80,6 +81,7 @@ export const StyledModal = styled(Modal)`
background-repeat: no-repeat;
background-position: center;
display: inline-block;
image-rendering: pixelated;
}
.settings-cat {
+72 -4
View File
@@ -1698,10 +1698,6 @@ export const BoardForm = styled.div`
margin-right: 14px;
}
.capcode-admin {
color: red !important;
}
.ellipsis:after {
content: '\\2026';
position: absolute;
@@ -1811,6 +1807,12 @@ export const BoardForm = styled.div`
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu {
@@ -1838,6 +1840,12 @@ export const BoardForm = styled.div`
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu {
@@ -1862,6 +1870,12 @@ export const BoardForm = styled.div`
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu {
@@ -1886,6 +1900,12 @@ export const BoardForm = styled.div`
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu {
@@ -1911,6 +1931,12 @@ export const BoardForm = styled.div`
.capcode {
color: #81a2be !important;
cursor: pointer;
}
.capcode-admin {
color: #81a2be !important;
cursor: pointer;
}
#post-menu {
@@ -1935,6 +1961,12 @@ export const BoardForm = styled.div`
.capcode {
color: #f60 !important;
cursor: pointer;
}
.capcode-admin {
color: #f60 !important;
cursor: pointer;
}
#post-menu {
@@ -3367,6 +3399,12 @@ export const BoardForm = styled.div`
return `
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
.op-container {
background-color: #f5e9e1;
@@ -3487,6 +3525,12 @@ export const BoardForm = styled.div`
return `
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
.op-container {
background-color: #d6daf0;
@@ -3603,6 +3647,12 @@ export const BoardForm = styled.div`
return `
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
.op-container {
background-color: #f5e9e1;
@@ -3722,6 +3772,12 @@ export const BoardForm = styled.div`
return `
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
.op-container {
background-color: #d6daf0;
@@ -3837,6 +3893,12 @@ export const BoardForm = styled.div`
return `
.capcode {
color: #81a2be !important;
cursor: pointer;
}
.capcode-admin {
color: #81a2be !important;
cursor: pointer;
}
.op-container {
@@ -3963,6 +4025,12 @@ export const BoardForm = styled.div`
return `
.capcode {
color: #f60 !important;
cursor: pointer;
}
.capcode-admin {
color: #f60 !important;
cursor: pointer;
}
.op-container {
background-color: #eee;
+34 -17
View File
@@ -17,12 +17,14 @@ export const Threads = styled.div`
padding: 5px 0 3px;
}
video, audio, img {
video,
audio,
img {
max-width: 150px;
max-height: 150px;
}
}
.file-thumb {
.file-thumb {
background-color: rgba(0, 0, 0, 0.05);
display: inline-flex;
justify-content: center;
@@ -31,8 +33,8 @@ export const Threads = styled.div`
}
.card {
box-shadow: 0 0 5px rgba(0, 0, 0, .25);
border: 0;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
border: 0;
}
.thread-icons {
@@ -64,7 +66,7 @@ export const Threads = styled.div`
}
.offline-icon-no-link-hovered {
transform: translate(16px,0);
transform: translate(16px, 0);
}
.sticky-icon {
background-image: url(assets/sticky.gif);
@@ -94,7 +96,6 @@ export const Threads = styled.div`
word-wrap: break-word;
}
${({ selectedStyle }) => {
switch (selectedStyle) {
case 'Yotsuba':
@@ -155,7 +156,6 @@ export const PostPreview = styled.div`
font-weight: 700;
}
${({ selectedStyle }) => {
switch (selectedStyle) {
case 'Yotsuba':
@@ -284,9 +284,27 @@ export const PostMenuCatalog = styled.div`
${({ selectedStyle }) => {
switch (selectedStyle) {
case 'Yotsuba':
return `.post-subject{
color:red;
}`;
return `.highlighted, .highlighted-click, .highlighted-address {
background-color: #f0c0b0 !important;
border: 1px solid #d9bfb7 !important;
border-left: none !important;
border-top: none !important;
}
.post-menu-catalog {
border-right: 1px solid #d9bfb7;
border-bottom: 2px solid #d9bfb7;
li {
border: 1px solid #d9bfb7;
background-color: #f0e0d6;
border-bottom: none;
:hover {
background-color: #ffe;
}
}
}`;
case 'Yotsuba-B':
return `.highlighted, .highlighted-click, .highlighted-address {
@@ -395,9 +413,8 @@ export const PostMenuCatalog = styled.div`
}
}`;
default:
return '';
}
}}
`;
default:
return '';
}
}}
`;
+96 -9
View File
@@ -906,10 +906,6 @@ export const BoardForm = styled.div`
margin-right: 14px;
}
.capcode-admin {
color: red !important;
}
.ellipsis:after {
content: '\\2026';
position: absolute;
@@ -1001,6 +997,16 @@ export const BoardForm = styled.div`
border-left: none !important;
border-top: none !important;
}
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu {
ul {
@@ -1026,6 +1032,16 @@ export const BoardForm = styled.div`
border-left: none !important;
border-top: none !important;
}
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu {
ul {
@@ -1047,6 +1063,16 @@ export const BoardForm = styled.div`
return `.highlighted, .highlighted-click, .highlighted-address {
background-color: #f0c0b0 !important;
}
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu {
font-size: 13px !important;
@@ -1070,6 +1096,16 @@ export const BoardForm = styled.div`
return `.highlighted, .highlighted-click, .highlighted-address {
background-color: #d6bad0 !important;
}
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu {
font-size: 13px !important;
@@ -1094,6 +1130,16 @@ export const BoardForm = styled.div`
background-color: #1d1d21 !important;
outline: 1px solid #111 !important;
}
.capcode {
color: #81a2be !important;
cursor: pointer;
}
.capcode-admin {
color: #81a2be !important;
cursor: pointer;
}
#post-menu {
ul {
@@ -1116,6 +1162,16 @@ export const BoardForm = styled.div`
background-color: #ccc !important;
outline: 1px solid #ccc !important;
}
.capcode {
color: #f60 !important;
cursor: pointer;
}
.capcode-admin {
color: #f60 !important;
cursor: pointer;
}
#post-menu {
ul {
@@ -2506,6 +2562,12 @@ export const BoardForm = styled.div`
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
.subject-mobile {
@@ -2627,6 +2689,12 @@ export const BoardForm = styled.div`
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
.subject-mobile {
@@ -2744,11 +2812,12 @@ export const BoardForm = styled.div`
.capcode {
color: purple !important;
cursor: pointer;
}
.subject-mobile {
color: #cc1105;
font-weight: 700;
.capcode-admin {
color: red !important;
cursor: pointer;
}
.date-time-mobile {
@@ -2864,6 +2933,12 @@ export const BoardForm = styled.div`
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
.subject-mobile {
@@ -2980,6 +3055,12 @@ export const BoardForm = styled.div`
.capcode {
color: #81a2be !important;
cursor: pointer;
}
.capcode-admin {
color: #81a2be !important;
cursor: pointer;
}
.poster-address-mobile {
@@ -3106,7 +3187,13 @@ export const BoardForm = styled.div`
.capcode {
color: #f60 !important;
}
cursor: pointer;
}
.capcode-admin {
color: #f60 !important;
cursor: pointer;
}
.subject-mobile {
color: #111;
+65 -17
View File
@@ -119,6 +119,7 @@ const All = () => {
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
const [deletePost, setDeletePost] = useState(false);
const [moderatorPermissions, setModeratorPermissions] = useState({});
const [moderatorRole, setModeratorRole] = useState({});
const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [cidTracker, setCidTracker] = useState({});
const [isThreadThumbnailClicked, setIsThreadThumbnailClicked] = useState({});
@@ -180,6 +181,7 @@ const All = () => {
useEffect(() => {
let permissions = {};
let roles = {};
selectedFeed.forEach((thread) => {
const subplebbit = subplebbits.find((s) => s && s.address === thread.subplebbitAddress);
@@ -192,10 +194,16 @@ const All = () => {
} else {
permissions[thread.subplebbitAddress] = false;
}
if (!roles[thread.subplebbitAddress]) {
roles[thread.subplebbitAddress] = {};
}
roles[thread.subplebbitAddress][account?.author.address] = role;
}
});
setModeratorPermissions(permissions);
setModeratorRole(roles);
}, [account?.author.address, selectedFeed, subplebbits]);
const handleOptionClick = () => {
@@ -717,7 +725,11 @@ const All = () => {
const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {};
const commentMediaInfo = getCommentMediaInfo(thread);
const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isModerator = moderatorPermissions[thread.subplebbitAddress];
const canModerate = moderatorPermissions[thread.subplebbitAddress];
const userRole = moderatorRole[thread.subplebbitAddress]?.[thread?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile;
if (thread.linkWidth && thread.linkHeight) {
let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight));
@@ -897,7 +909,7 @@ const All = () => {
<Fragment key={`fragment3-${index}`}>
<span
key={`n-${index}`}
className='name'
className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName}
data-tooltip-place='top'
@@ -906,15 +918,22 @@ const All = () => {
</span>
</Fragment>
) : (
<span key={`n-${index}`} className='name'>
<span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName}
</span>
)
) : (
<span key={`n-${index}`} className='name'>
<span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;(u/
<span
key={`pa-${index}`}
@@ -1037,7 +1056,7 @@ const All = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -1255,6 +1274,10 @@ const All = () => {
}
const replyMediaInfo = getCommentMediaInfo(reply);
const fallbackImgUrl = 'assets/filedeleted-res.gif';
const userRole = moderatorRole[reply.subplebbitAddress]?.[reply?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress;
@@ -1283,7 +1306,7 @@ const All = () => {
<Fragment key={`fragment6-${index}`}>
<span
key={`mob-n-${index}`}
className='name'
className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName}
data-tooltip-place='top'
@@ -1292,15 +1315,22 @@ const All = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name'>
<span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name'>
<span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;(u/
<span
key={`pa-${index}`}
@@ -1434,7 +1464,7 @@ const All = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2019,7 +2049,7 @@ const All = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2085,7 +2115,7 @@ const All = () => {
<Fragment key={`fragment9-${index}`}>
<span
key={`mob-n-${index}`}
className='name-mobile'
className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName}
data-tooltip-place='top'
@@ -2094,15 +2124,22 @@ const All = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;
<span
key={`mob-pa-${index}`}
@@ -2454,6 +2491,10 @@ const All = () => {
}
const replyMediaInfo = getCommentMediaInfo(reply);
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
const userRole = moderatorRole[reply.subplebbitAddress]?.[reply?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress;
if (storedSigners[selectedThreadCidRef]) {
@@ -2512,7 +2553,7 @@ const All = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2578,7 +2619,7 @@ const All = () => {
<Fragment key={`fragment13-${index}`}>
<span
key={`mob-n-${index}`}
className='name-mobile'
className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName}
data-tooltip-place='top'
@@ -2587,15 +2628,22 @@ const All = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;
<span
key={`mob-pa-${index}`}
+4 -4
View File
@@ -69,7 +69,7 @@ const CatalogPost = ({ post }) => {
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [isModerator, setIsModerator] = useState(false);
const [canModerate, setCanModerate] = useState(false);
const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess();
@@ -161,9 +161,9 @@ const CatalogPost = ({ post }) => {
const role = subplebbit.roles[account?.author.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true);
setCanModerate(true);
} else {
setIsModerator(false);
setCanModerate(false);
}
}
}, [account?.author.address, subplebbit.roles]);
@@ -573,7 +573,7 @@ const CatalogPost = ({ post }) => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
+85 -29
View File
@@ -145,7 +145,7 @@ const Board = () => {
const [deletePost, setDeletePost] = useState(false);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [isModerator, setIsModerator] = useState(false);
const [canModerate, setCanModerate] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
const [mobileMenuPosition, setMobileMenuPosition] = useState({ top: 0, left: 0 });
@@ -177,12 +177,12 @@ const Board = () => {
useEffect(() => {
if (subplebbit?.roles !== undefined) {
const role = subplebbit?.roles[account?.author.address]?.role;
const role = subplebbit?.roles?.[account?.author.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true);
setCanModerate(true);
} else {
setIsModerator(false);
setCanModerate(false);
}
}
}, [account?.author.address, subplebbit?.roles]);
@@ -463,11 +463,6 @@ const Board = () => {
const handleSubmit = async (event) => {
event.preventDefault();
if (subjectRef.current.value === '') {
setNewErrorMessage('Subject field is mandatory');
return;
}
setPublishCommentOptions((prevPublishCommentOptions) => ({
...prevPublishCommentOptions,
author: {
@@ -933,7 +928,7 @@ const Board = () => {
>
Catalog
</Link>
]{subplebbit.roles && subplebbit?.roles[account?.author?.address]?.role === 'admin' ? <BoardSettings subplebbit={subplebbit} /> : null}
]{subplebbit.roles && subplebbit?.roles?.[account?.author?.address]?.role === 'admin' ? <BoardSettings subplebbit={subplebbit} /> : null}
</div>
{subplebbit?.state === 'succeeded' ? (
<>
@@ -1039,7 +1034,7 @@ const Board = () => {
>
<div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'>
{/* {isModerator ? (
{/* {canModerate ? (
<>
change rules
</>
@@ -1264,7 +1259,7 @@ const Board = () => {
>
<div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'>
{/* {isModerator ? (
{/* {canModerate ? (
<>
change rules
</>
@@ -1509,7 +1504,7 @@ const Board = () => {
style={{ display: openMenuCid === subplebbit.pubsubTopic ? 'block' : 'none' }}
>
<ul className='post-menu-catalog'>
{/* {isModerator ? (
{/* {canModerate ? (
<>
change description
</>
@@ -1744,6 +1739,9 @@ const Board = () => {
const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {};
const commentMediaInfo = getCommentMediaInfo(thread);
const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isOwner = subplebbit?.roles?.[thread.author.address]?.role === 'owner';
const isAdmin = subplebbit?.roles?.[thread.author.address]?.role === 'admin';
const isModerator = subplebbit?.roles?.[thread.author.address]?.role === 'moderator';
let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile;
if (thread.linkWidth && thread.linkHeight) {
let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight));
@@ -1923,7 +1921,7 @@ const Board = () => {
<Fragment key={`fragment3-${index}`}>
<span
key={`n-${index}`}
className='name'
className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName}
data-tooltip-place='top'
@@ -1932,15 +1930,28 @@ const Board = () => {
</span>
</Fragment>
) : (
<span key={`n-${index}`} className='name'>
<span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName}
</span>
)
) : (
<span key={`n-${index}`} className='name'>
<span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;(u/
<span
key={`pa-${index}`}
@@ -2080,7 +2091,7 @@ const Board = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2299,6 +2310,9 @@ const Board = () => {
}
const replyMediaInfo = getCommentMediaInfo(reply);
const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
const isAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
const isModerator = subplebbit?.roles?.[reply.author.address]?.role === 'moderator';
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress;
@@ -2328,7 +2342,7 @@ const Board = () => {
<Fragment key={`fragment6-${index}`}>
<span
key={`mob-n-${index}`}
className='name'
className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName}
data-tooltip-place='top'
@@ -2337,15 +2351,28 @@ const Board = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name'>
<span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name'>
<span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;(u/
<span
key={`pa-${index}`}
@@ -2465,7 +2492,7 @@ const Board = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -3057,7 +3084,7 @@ const Board = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -3139,7 +3166,7 @@ const Board = () => {
<Fragment key={`fragment9-${index}`}>
<span
key={`mob-n-${index}`}
className='name-mobile'
className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName}
data-tooltip-place='top'
@@ -3148,15 +3175,28 @@ const Board = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;
<span
key={`mob-pa-${index}`}
@@ -3504,6 +3544,9 @@ const Board = () => {
{displayedReplies?.map((reply, index) => {
const replyMediaInfo = getCommentMediaInfo(reply);
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
const isOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
const isAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
const isModerator = subplebbit?.roles?.[reply.author.address]?.role === 'moderator';
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress;
if (storedSigners[selectedThreadCidRef]) {
@@ -3562,7 +3605,7 @@ const Board = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -3644,7 +3687,7 @@ const Board = () => {
<Fragment key={`fragment13-${index}`}>
<span
key={`mob-n-${index}`}
className='name-mobile'
className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName}
data-tooltip-place='top'
@@ -3653,15 +3696,28 @@ const Board = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;
<span
key={`mob-pa-${index}`}
+8 -13
View File
@@ -52,7 +52,7 @@ const CatalogPost = ({ post }) => {
setIsAuthorEdit,
setIsCaptchaOpen,
setIsEditModalOpen,
isModerator,
canModerate,
setModeratingCommentCid,
setOriginalCommentContent,
setPendingComment,
@@ -443,7 +443,7 @@ const CatalogPost = ({ post }) => {
>
<div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'>
{/* {isModerator ? (
{/* {canModerate ? (
<>
change rules
</>
@@ -647,7 +647,7 @@ const CatalogPost = ({ post }) => {
>
<div className={`post-menu-thread post-menu-thread-${'description'}`} style={{ display: openMenuCid === 'description' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'>
{/* {isModerator ? (
{/* {canModerate ? (
<>
change description
</>
@@ -999,7 +999,7 @@ const CatalogPost = ({ post }) => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -1133,7 +1133,7 @@ const Catalog = () => {
setIsCaptchaOpen,
isModerationOpen,
setIsModerationOpen,
setIsModerator,
setCanModerate,
isSettingsOpen,
setIsSettingsOpen,
originalCommentContent,
@@ -1198,12 +1198,12 @@ const Catalog = () => {
const role = subplebbit.roles[account?.author.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true);
setCanModerate(true);
} else {
setIsModerator(false);
setCanModerate(false);
}
}
}, [account?.author.address, subplebbit.roles, setIsModerator]);
}, [account?.author.address, subplebbit.roles, setCanModerate]);
useEffect(() => {
setSelectedAddress(subplebbitAddress);
@@ -1328,11 +1328,6 @@ const Catalog = () => {
const handleSubmit = async (event) => {
event.preventDefault();
if (subjectRef.current.value === '') {
setNewErrorMessage('Subject field is mandatory');
return;
}
setPublishCommentOptions((prevPublishCommentOptions) => ({
...prevPublishCommentOptions,
author: {
+1 -1
View File
@@ -427,7 +427,7 @@ const Description = () => {
style={{ display: openMenuCid === subplebbit.pubsubTopic ? 'block' : 'none' }}
>
<ul className='post-menu-catalog'>
{/* {isModerator ? (
{/* {canModerate ? (
<>
change description
</>
+1 -1
View File
@@ -412,7 +412,7 @@ const Rules = () => {
>
<div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'>
{/* {isModerator ? (
{/* {canModerate ? (
<>
change rules
</>
+65 -17
View File
@@ -119,6 +119,7 @@ const Subscriptions = () => {
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
const [deletePost, setDeletePost] = useState(false);
const [moderatorPermissions, setModeratorPermissions] = useState({});
const [moderatorRole, setModeratorRole] = useState({});
const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [cidTracker, setCidTracker] = useState({});
const [isThreadThumbnailClicked, setIsThreadThumbnailClicked] = useState({});
@@ -179,6 +180,7 @@ const Subscriptions = () => {
useEffect(() => {
let permissions = {};
let roles = {};
selectedFeed.forEach((thread) => {
const subplebbit = subplebbits.find((s) => s && s.address === thread.subplebbitAddress);
@@ -191,10 +193,16 @@ const Subscriptions = () => {
} else {
permissions[thread.subplebbitAddress] = false;
}
if (!roles[thread.subplebbitAddress]) {
roles[thread.subplebbitAddress] = {};
}
roles[thread.subplebbitAddress][account?.author.address] = role;
}
});
setModeratorPermissions(permissions);
setModeratorRole(roles);
}, [account?.author.address, selectedFeed, subplebbits]);
const handleOptionClick = () => {
@@ -721,7 +729,11 @@ const Subscriptions = () => {
const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {};
const commentMediaInfo = getCommentMediaInfo(thread);
const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isModerator = moderatorPermissions[thread.subplebbitAddress];
const canModerate = moderatorPermissions[thread.subplebbitAddress];
const userRole = moderatorRole[thread.subplebbitAddress]?.[thread?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile;
if (thread.linkWidth && thread.linkHeight) {
let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight));
@@ -901,7 +913,7 @@ const Subscriptions = () => {
<Fragment key={`fragment3-${index}`}>
<span
key={`n-${index}`}
className='name'
className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName}
data-tooltip-place='top'
@@ -910,15 +922,22 @@ const Subscriptions = () => {
</span>
</Fragment>
) : (
<span key={`n-${index}`} className='name'>
<span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName}
</span>
)
) : (
<span key={`n-${index}`} className='name'>
<span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;(u/
<span
key={`pa-${index}`}
@@ -1047,7 +1066,7 @@ const Subscriptions = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -1265,6 +1284,10 @@ const Subscriptions = () => {
}
const replyMediaInfo = getCommentMediaInfo(reply);
const fallbackImgUrl = 'assets/filedeleted-res.gif';
const userRole = moderatorRole[reply.subplebbitAddress]?.[reply?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress;
@@ -1293,7 +1316,7 @@ const Subscriptions = () => {
<Fragment key={`fragment6-${index}`}>
<span
key={`mob-n-${index}`}
className='name'
className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName}
data-tooltip-place='top'
@@ -1302,15 +1325,22 @@ const Subscriptions = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name'>
<span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name'>
<span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;(u/
<span
key={`pa-${index}`}
@@ -1444,7 +1474,7 @@ const Subscriptions = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2029,7 +2059,7 @@ const Subscriptions = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2095,7 +2125,7 @@ const Subscriptions = () => {
<Fragment key={`fragment9-${index}`}>
<span
key={`mob-n-${index}`}
className='name-mobile'
className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName}
data-tooltip-place='top'
@@ -2104,15 +2134,22 @@ const Subscriptions = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;
<span
key={`mob-pa-${index}`}
@@ -2464,6 +2501,10 @@ const Subscriptions = () => {
}
const replyMediaInfo = getCommentMediaInfo(reply);
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
const userRole = moderatorRole[reply.subplebbitAddress]?.[reply?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress;
if (storedSigners[selectedThreadCidRef]) {
@@ -2522,7 +2563,7 @@ const Subscriptions = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2588,7 +2629,7 @@ const Subscriptions = () => {
<Fragment key={`fragment13-${index}`}>
<span
key={`mob-n-${index}`}
className='name-mobile'
className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName}
data-tooltip-place='top'
@@ -2597,15 +2638,22 @@ const Subscriptions = () => {
</span>
</Fragment>
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name-mobile'>
<span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;
<span
key={`mob-pa-${index}`}
@@ -69,7 +69,7 @@ const CatalogPost = ({ post }) => {
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [isModerator, setIsModerator] = useState(false);
const [canModerate, setCanModerate] = useState(false);
const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess();
@@ -161,9 +161,9 @@ const CatalogPost = ({ post }) => {
const role = subplebbit.roles[account?.author.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true);
setCanModerate(true);
} else {
setIsModerator(false);
setCanModerate(false);
}
}
}, [account?.author.address, subplebbit.roles]);
@@ -573,7 +573,7 @@ const CatalogPost = ({ post }) => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
+77 -13
View File
@@ -23,6 +23,7 @@ import PostOnHover from '../PostOnHover';
import StateLabel from '../StateLabel';
import VerifiedAuthor from '../VerifiedAuthor';
import CreateBoardModal from '../modals/CreateBoardModal';
import AdminListModal from '../modals/AdminListModal';
import EditModal from '../modals/EditModal';
import ModerationModal from '../modals/ModerationModal';
import ReplyModal from '../modals/ReplyModal';
@@ -119,7 +120,7 @@ const Thread = () => {
const [visible, setVisible] = useState(true);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [isModerator, setIsModerator] = useState(false);
const [canModerate, setCanModerate] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
const [mobileMenuPosition, setMobileMenuPosition] = useState({ top: 0, left: 0 });
@@ -138,11 +139,15 @@ const Thread = () => {
useAnonMode(selectedThread, anonymousMode && executeAnonMode);
const [isAdminListOpen, setIsAdminListOpen] = useState(false);
const originalComment = useComment({ commentCid: selectedThread });
const [comment, setComment] = useState(originalComment);
const { subplebbitAddress, threadCid } = useParams();
const subplebbit = useSubplebbit({ subplebbitAddress: originalComment.subplebbitAddress });
const selectedAddress = subplebbit.address;
const isOwner = subplebbit?.roles?.[comment.author?.address]?.role === 'owner';
const isAdmin = subplebbit?.roles?.[comment.author?.address]?.role === 'admin';
const isModerator = subplebbit?.roles?.[comment.author?.address]?.role === 'moderator';
const stateString = useStateString(comment);
@@ -200,9 +205,9 @@ const Thread = () => {
const role = subplebbit.roles[account?.author?.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true);
setCanModerate(true);
} else {
setIsModerator(false);
setCanModerate(false);
}
}
}, [account?.author.address, subplebbit.roles]);
@@ -642,6 +647,7 @@ const Thread = () => {
</title>
</Helmet>
<Container>
<AdminListModal selectedStyle={selectedStyle} isOpen={isAdminListOpen} closeModal={() => setIsAdminListOpen(false)} roles={subplebbit?.roles} />
<CreateBoardModal selectedStyle={selectedStyle} isOpen={isCreateBoardOpen} closeModal={() => setIsCreateBoardOpen(false)} />
<ReplyModal selectedStyle={selectedStyle} isOpen={isReplyOpen} closeModal={() => setIsReplyOpen(false)} />
<SettingsModal selectedStyle={selectedStyle} isOpen={isSettingsOpen} closeModal={() => setIsSettingsOpen(false)} />
@@ -1078,7 +1084,7 @@ const Thread = () => {
<>
<span
key={`n-${comment.cid}`}
className='name'
className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={comment?.author?.displayName}
data-tooltip-place='top'
@@ -1087,15 +1093,28 @@ const Thread = () => {
</span>
</>
) : (
<span key={`n-${comment.cid}`} className='name'>
<span key={`n-${comment.cid}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{comment?.author?.displayName}
</span>
)
) : (
<span key={`n-${comment.cid}`} className='name'>
<span key={`n-${comment.cid}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;
<span
className='poster-address address-desktop'
@@ -1205,7 +1224,7 @@ const Thread = () => {
<li onClick={() => handleAuthorDeleteClick(comment)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -1375,6 +1394,9 @@ const Thread = () => {
}
const replyMediaInfo = getCommentMediaInfo(reply);
const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isReplyOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
const isReplyAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
const isReplyModerator = subplebbit?.roles?.[reply.author.address]?.role === 'moderator';
const shortParentCid = findShortParentCid(reply.parentCid, comment);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress;
@@ -1404,7 +1426,7 @@ const Thread = () => {
<>
<span
key={`mob-n-${index}`}
className='name'
className={`name ${isReplyAdmin || isReplyOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip'
data-tooltip-content={reply.author?.displayName}
data-tooltip-place='top'
@@ -1413,15 +1435,28 @@ const Thread = () => {
</span>
</>
) : (
<span key={`mob-n-${index}`} className='name'>
<span key={`mob-n-${index}`} className={`name ${isReplyAdmin || isReplyOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author?.displayName ?? reply.displayName}
</span>
)
) : (
<span key={`mob-n-${index}`} className='name'>
<span key={`mob-n-${index}`} className={`name ${isReplyAdmin || isReplyOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous
</span>
)}
{isReplyOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isReplyAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isReplyModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;(u/
<span
key={`pa-${index}`}
@@ -1531,7 +1566,7 @@ const Thread = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -1986,7 +2021,7 @@ const Thread = () => {
<li onClick={() => handleAuthorDeleteClick(comment)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2086,6 +2121,19 @@ const Thread = () => {
Anonymous
</span>
)}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;
<span
key={`mob-pa-${comment.cid}`}
@@ -2340,6 +2388,9 @@ const Thread = () => {
{sortedReplies.map((reply, index) => {
const replyMediaInfo = getCommentMediaInfo(reply);
const shortParentCid = findShortParentCid(reply.parentCid, comment);
const isReplyOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
const isReplyAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
const isReplyModerator = subplebbit?.roles?.[reply.author.address]?.role === 'moderator';
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress;
if (storedSigners[selectedThread]) {
@@ -2398,7 +2449,7 @@ const Thread = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
{canModerate ? (
<>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li
@@ -2498,6 +2549,19 @@ const Thread = () => {
Anonymous
</span>
)}
{isReplyOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isReplyAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isReplyModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
<span key={`fix1-ha-${index}`} className='poster-address-mobile'>
&nbsp;(u/
</span>
+13 -13
View File
@@ -30,12 +30,13 @@ const useGeneralStore = create((set) => ({
setEditedComments: (comments) => set({ editedComments: comments }),
feedCacheStates: {},
setFeedCacheState: (address, isCached) => set((prev) => ({
feedCacheStates: {
...prev.feedCacheStates,
[address]: isCached,
}
})),
setFeedCacheState: (address, isCached) =>
set((prev) => ({
feedCacheStates: {
...prev.feedCacheStates,
[address]: isCached,
},
})),
isAuthorDelete: false,
setIsAuthorDelete: (isAuthorDelete) => set({ isAuthorDelete }),
@@ -49,8 +50,8 @@ const useGeneralStore = create((set) => ({
isEditModalOpen: false,
setIsEditModalOpen: (isOpen) => set({ isEditModalOpen: isOpen }),
isModerator: false,
setIsModerator: (isModerator) => set({ isModerator }),
canModerate: false,
setCanModerate: (canModerate) => set({ canModerate }),
isModerationOpen: false,
setIsModerationOpen: (isOpen) => set({ isModerationOpen: isOpen }),
@@ -81,7 +82,7 @@ const useGeneralStore = create((set) => ({
resolveCaptchaPromise: null,
setResolveCaptchaPromise: (resolve) => set({ resolveCaptchaPromise: resolve }),
selectedAddress: '',
setSelectedAddress: (address) => set({ selectedAddress: address }),
@@ -90,7 +91,7 @@ const useGeneralStore = create((set) => ({
selectedShortCid: '',
setSelectedShortCid: (shortCid) => set({ selectedShortCid: shortCid }),
selectedStyle: localStorage.getItem('selectedStyle') || 'Yotsuba',
setSelectedStyle: (style) => {
localStorage.setItem('selectedStyle', style);
@@ -99,7 +100,7 @@ const useGeneralStore = create((set) => ({
selectedText: '',
setSelectedText: (text) => set({ selectedText: text }),
selectedThread: '',
setSelectedThread: (thread) => set({ selectedThread: thread }),
@@ -114,7 +115,6 @@ const useGeneralStore = create((set) => ({
triggerInsertion: 0,
setTriggerInsertion: (trigger) => set({ triggerInsertion: trigger }),
}));
export default useGeneralStore;
export default useGeneralStore;