mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
118 lines
3.5 KiB
TypeScript
118 lines
3.5 KiB
TypeScript
import { create } from 'zustand';
|
|
import useSelectedTextStore from './use-selected-text-store';
|
|
|
|
interface ReplyModalState {
|
|
showReplyModal: boolean;
|
|
/** True when opened via "Post a Reply" footer button — textarea should be empty, no quote. */
|
|
openEmpty: boolean;
|
|
activeCid: string | null;
|
|
parentNumber: number | null;
|
|
threadNumber: number | null;
|
|
threadCid: string | null;
|
|
communityAddress: string | null;
|
|
scrollY: number;
|
|
quoteInsertRequestId: number;
|
|
quoteInsertNumber: number | null;
|
|
quoteInsertSelectedText: string | null;
|
|
closeModal: () => void;
|
|
openReplyModal: (parentCid: string, parentNumber: number | undefined, postCid: string, threadNumber: number | undefined, communityAddress: string) => void;
|
|
/** Open reply modal with empty textarea, no prefilled quote. Use for "Post a Reply" footer button. */
|
|
openReplyModalEmpty: (postCid: string, threadNumber: number | undefined, communityAddress: string) => void;
|
|
}
|
|
|
|
const getQuotedSelection = () => {
|
|
const text = document.getSelection()?.toString();
|
|
if (!text) return '';
|
|
|
|
// Keep each selected line as 5chan greentext and normalize newlines.
|
|
const normalizedText = text.replace(/\r\n/g, '\n').replace(/\n+$/g, '');
|
|
|
|
if (!normalizedText) return '';
|
|
|
|
return normalizedText
|
|
.split('\n')
|
|
.map((line) => `>${line}`)
|
|
.join('\n');
|
|
};
|
|
|
|
const useReplyModalStore = create<ReplyModalState>((set, get) => ({
|
|
showReplyModal: false,
|
|
openEmpty: false,
|
|
activeCid: null,
|
|
parentNumber: null,
|
|
threadNumber: null,
|
|
threadCid: null,
|
|
communityAddress: null,
|
|
scrollY: 0,
|
|
quoteInsertRequestId: 0,
|
|
quoteInsertNumber: null,
|
|
quoteInsertSelectedText: null,
|
|
|
|
closeModal: () => {
|
|
// Reset selected text if you're using that store
|
|
useSelectedTextStore.getState().resetSelectedText();
|
|
set({
|
|
showReplyModal: false,
|
|
openEmpty: false,
|
|
activeCid: null,
|
|
parentNumber: null,
|
|
threadNumber: null,
|
|
quoteInsertNumber: null,
|
|
quoteInsertSelectedText: null,
|
|
});
|
|
},
|
|
|
|
openReplyModal: (parentCid, parentNumber, postCid, threadNumber, communityAddress) => {
|
|
const quotedSelection = getQuotedSelection();
|
|
|
|
// If the reply modal is already open, insert this quote in the current textarea at caret.
|
|
if (get().showReplyModal) {
|
|
set((state) => ({
|
|
quoteInsertRequestId: state.quoteInsertRequestId + 1,
|
|
quoteInsertNumber: parentNumber ?? null,
|
|
quoteInsertSelectedText: quotedSelection || null,
|
|
}));
|
|
return;
|
|
}
|
|
|
|
if (quotedSelection) {
|
|
useSelectedTextStore.getState().setSelectedText(`${quotedSelection}\n`);
|
|
}
|
|
|
|
// Handle mobile scrollY
|
|
const isMobile = window.innerWidth <= 768; // Simple check, adjust as needed
|
|
const scrollY = isMobile ? window.scrollY : 0;
|
|
|
|
set({
|
|
openEmpty: false,
|
|
activeCid: postCid,
|
|
parentNumber: parentNumber ?? null,
|
|
threadNumber: threadNumber ?? null,
|
|
threadCid: postCid,
|
|
showReplyModal: true,
|
|
communityAddress,
|
|
scrollY,
|
|
});
|
|
},
|
|
|
|
openReplyModalEmpty: (postCid, threadNumber, communityAddress) => {
|
|
useSelectedTextStore.getState().resetSelectedText();
|
|
const isMobile = window.innerWidth <= 768;
|
|
const scrollY = isMobile ? window.scrollY : 0;
|
|
set({
|
|
openEmpty: true,
|
|
activeCid: postCid,
|
|
parentNumber: null,
|
|
threadNumber: threadNumber ?? null,
|
|
threadCid: postCid,
|
|
showReplyModal: true,
|
|
communityAddress,
|
|
scrollY,
|
|
quoteInsertNumber: null,
|
|
quoteInsertSelectedText: null,
|
|
});
|
|
},
|
|
}));
|
|
|
|
export default useReplyModalStore;
|