mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
146 lines
5.8 KiB
TypeScript
146 lines
5.8 KiB
TypeScript
import { useEffect, useState, useMemo } from 'react';
|
|
import { useAccount } from '@plebbit/plebbit-react-hooks';
|
|
import Plebbit from '@plebbit/plebbit-js';
|
|
import useTopbarEditModalStore from '../../stores/use-topbar-edit-modal-store';
|
|
import useTopbarVisibilityStore from '../../stores/use-topbar-visibility-store';
|
|
import { getAllBoardCodes } from '../../constants/board-codes';
|
|
import { getBoardPath } from '../../lib/utils/route-utils';
|
|
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
|
import styles from './topbar-edit-modal.module.css';
|
|
|
|
const TopbarEditModal = () => {
|
|
const { showModal, closeTopbarEditModal } = useTopbarEditModalStore();
|
|
const { visibleDirectories, visibleSubscriptions, setDirectoryVisibility, setSubscriptionVisibility } = useTopbarVisibilityStore();
|
|
const account = useAccount();
|
|
const subscriptions = account?.subscriptions || [];
|
|
const defaultSubplebbits = useDefaultSubplebbits();
|
|
|
|
// Convert visible directories set to space-separated string for input
|
|
const directoriesToString = (dirs: Set<string>): string => {
|
|
return Array.from(dirs).sort().join(' ');
|
|
};
|
|
|
|
// Convert space-separated string to set of directory codes
|
|
const stringToDirectories = (str: string): Set<string> => {
|
|
const codes = str
|
|
.trim()
|
|
.split(/\s+/)
|
|
.filter((code) => code.length > 0)
|
|
.map((code) => code.toLowerCase());
|
|
return new Set(codes);
|
|
};
|
|
|
|
// Memoize board codes to avoid recalculating
|
|
const allBoardCodes = useMemo(() => getAllBoardCodes(), []);
|
|
|
|
// Check if all directories are visible (default state)
|
|
const allDirectoriesVisible = useMemo(() => allBoardCodes.every((code) => visibleDirectories.has(code)), [allBoardCodes, visibleDirectories]);
|
|
|
|
// Local state for text input (will be saved on Save click)
|
|
// Empty string means all directories visible (default), otherwise show only the specified codes
|
|
const [localDirectoryInput, setLocalDirectoryInput] = useState<string>(allDirectoriesVisible ? '' : directoriesToString(visibleDirectories));
|
|
const [localSubscriptionVisibility, setLocalSubscriptionVisibility] = useState<Set<string>>(visibleSubscriptions);
|
|
|
|
// Update local state when modal opens or store changes
|
|
useEffect(() => {
|
|
if (showModal) {
|
|
const allVisible = allBoardCodes.every((code) => visibleDirectories.has(code));
|
|
setLocalDirectoryInput(allVisible ? '' : directoriesToString(visibleDirectories));
|
|
setLocalSubscriptionVisibility(new Set(visibleSubscriptions));
|
|
}
|
|
}, [showModal, visibleDirectories, visibleSubscriptions, allBoardCodes]);
|
|
|
|
if (!showModal) {
|
|
return null;
|
|
}
|
|
|
|
const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
if (e.target === e.currentTarget) {
|
|
closeTopbarEditModal();
|
|
}
|
|
};
|
|
|
|
const handleSubscriptionToggle = (address: string) => {
|
|
const newSet = new Set(localSubscriptionVisibility);
|
|
if (newSet.has(address)) {
|
|
newSet.delete(address);
|
|
} else {
|
|
newSet.add(address);
|
|
}
|
|
setLocalSubscriptionVisibility(newSet);
|
|
};
|
|
|
|
const handleSave = () => {
|
|
// If input is empty, show all directories (default behavior)
|
|
// Otherwise, show only the directories specified in the input
|
|
if (localDirectoryInput.trim() === '') {
|
|
// Show all directories
|
|
allBoardCodes.forEach((code) => {
|
|
setDirectoryVisibility(code, true);
|
|
});
|
|
} else {
|
|
// Show only specified directories
|
|
const inputDirectories = stringToDirectories(localDirectoryInput);
|
|
allBoardCodes.forEach((code) => {
|
|
setDirectoryVisibility(code, inputDirectories.has(code));
|
|
});
|
|
}
|
|
|
|
// Apply subscription visibility changes
|
|
subscriptions.forEach((address: string) => {
|
|
setSubscriptionVisibility(address, localSubscriptionVisibility.has(address));
|
|
});
|
|
|
|
closeTopbarEditModal();
|
|
};
|
|
|
|
return (
|
|
<div className={styles.backdrop} onClick={handleBackdropClick}>
|
|
<div className={styles.topbarEditDialog}>
|
|
<div className={styles.hd}>
|
|
<h2>Custom Board List</h2>
|
|
<button className={styles.closeButton} onClick={closeTopbarEditModal} title='Close' />
|
|
</div>
|
|
<div className={styles.bd}>
|
|
<div className={styles.section}>
|
|
<h3>Directory Boards</h3>
|
|
<p>Enter directory codes separated by spaces (e.g., "jp tg mu"):</p>
|
|
<input
|
|
type='text'
|
|
className={styles.directoryInput}
|
|
placeholder='Example: jp tg mu'
|
|
value={localDirectoryInput}
|
|
onChange={(e) => setLocalDirectoryInput(e.target.value)}
|
|
/>
|
|
</div>
|
|
|
|
{subscriptions.length > 0 && (
|
|
<div className={styles.section}>
|
|
<h3>Subscriptions</h3>
|
|
<p>Select which subscriptions to show in the topbar:</p>
|
|
<div className={styles.checkboxGroup}>
|
|
{subscriptions.map((address: string) => {
|
|
const boardPath = getBoardPath(address, defaultSubplebbits);
|
|
const displayText = address.endsWith('.eth') || address.endsWith('.sol') ? address : Plebbit.getShortAddress(address);
|
|
const isChecked = localSubscriptionVisibility.has(address);
|
|
return (
|
|
<div key={address} className={styles.checkboxItem}>
|
|
<input type='checkbox' id={`subscription-${address}`} checked={isChecked} onChange={() => handleSubscriptionToggle(address)} />
|
|
<label htmlFor={`subscription-${address}`}>{boardPath || displayText}</label>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className={styles.topbarEditFooter}>
|
|
<button onClick={handleSave}>Save</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default TopbarEditModal;
|