mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(edit menu): add comment edit and delete for authors
This commit is contained in:
@@ -147,5 +147,6 @@
|
||||
"optional": "اختياري",
|
||||
"close_thread": "اغلق الموضوع",
|
||||
"view_spoiler": "عرض الحاضر",
|
||||
"filter": "تصفية"
|
||||
"filter": "تصفية",
|
||||
"edit": "تحرير"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "ঐচ্ছিক",
|
||||
"close_thread": "থ্রেড বন্ধ করুন",
|
||||
"view_spoiler": "স্পোয়ালার দেখুন",
|
||||
"filter": "ফিল্টার"
|
||||
"filter": "ফিল্টার",
|
||||
"edit": "সম্পাদনা"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "volitelný",
|
||||
"close_thread": "uzavřít vlákno",
|
||||
"view_spoiler": "zobrazit spoiler",
|
||||
"filter": "filtr"
|
||||
"filter": "filtr",
|
||||
"edit": "upravit"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "valgfri",
|
||||
"close_thread": "luk tråd",
|
||||
"view_spoiler": "vis spoiler",
|
||||
"filter": "filtrér"
|
||||
"filter": "filtrér",
|
||||
"edit": "rediger"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "optional",
|
||||
"close_thread": "Thread schließen",
|
||||
"view_spoiler": "Spoiler anzeigen",
|
||||
"filter": "filtern"
|
||||
"filter": "filtern",
|
||||
"edit": "bearbeiten"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "προαιρετικό",
|
||||
"close_thread": "κλείσιμο νήματος",
|
||||
"view_spoiler": "προβολή spoiler",
|
||||
"filter": "φίλτρο"
|
||||
"filter": "φίλτρο",
|
||||
"edit": "επεξεργασία"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "optional",
|
||||
"close_thread": "close thread",
|
||||
"view_spoiler": "view spoiler",
|
||||
"filter": "filter"
|
||||
"filter": "filter",
|
||||
"edit": "edit"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opcional",
|
||||
"close_thread": "cerrar hilo",
|
||||
"view_spoiler": "ver spoiler",
|
||||
"filter": "filtrar"
|
||||
"filter": "filtrar",
|
||||
"edit": "editar"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "اختیاری",
|
||||
"close_thread": "بستن موضوع",
|
||||
"view_spoiler": "نمایش اسپویلر",
|
||||
"filter": "فیلتر"
|
||||
"filter": "فیلتر",
|
||||
"edit": "ویرایش"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "valinnainen",
|
||||
"close_thread": "sulje keskustelu",
|
||||
"view_spoiler": "näytä spoiler",
|
||||
"filter": "suodatin"
|
||||
"filter": "suodatin",
|
||||
"edit": "muokkaa"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opsyonal",
|
||||
"close_thread": "isara ang thread",
|
||||
"view_spoiler": "tingnan ang spoiler",
|
||||
"filter": "salain"
|
||||
"filter": "salain",
|
||||
"edit": "i-edit"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "facultatif",
|
||||
"close_thread": "fermer le fil",
|
||||
"view_spoiler": "voir le spoiler",
|
||||
"filter": "filtre"
|
||||
"filter": "filtre",
|
||||
"edit": "modifier"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "אופציונלי",
|
||||
"close_thread": "סגור את הנושא",
|
||||
"view_spoiler": "הצג ספוילר",
|
||||
"filter": "סנן"
|
||||
"filter": "סנן",
|
||||
"edit": "ערוך"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "वैकल्पिक",
|
||||
"close_thread": "थ्रेड बंद करें",
|
||||
"view_spoiler": "स्पॉइलर देखें",
|
||||
"filter": "फ़िल्टर"
|
||||
"filter": "फ़िल्टर",
|
||||
"edit": "संपादित करें"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opcionális",
|
||||
"close_thread": "szál bezárása",
|
||||
"view_spoiler": "spoiler megtekintése",
|
||||
"filter": "szűrő"
|
||||
"filter": "szűrő",
|
||||
"edit": "szerkesztés"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opsional",
|
||||
"close_thread": "tutup utas",
|
||||
"view_spoiler": "lihat spoiler",
|
||||
"filter": "menyaring"
|
||||
"filter": "menyaring",
|
||||
"edit": "sunting"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opzionale",
|
||||
"close_thread": "chiudi il thread",
|
||||
"view_spoiler": "mostra spoiler",
|
||||
"filter": "filtro"
|
||||
"filter": "filtro",
|
||||
"edit": "modifica"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "オプショナル",
|
||||
"close_thread": "スレッドを閉じる",
|
||||
"view_spoiler": "スポイラーを表示",
|
||||
"filter": "フィルター"
|
||||
"filter": "フィルター",
|
||||
"edit": "編集"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "선택",
|
||||
"close_thread": "스레드 닫기",
|
||||
"view_spoiler": "스포일러 보기",
|
||||
"filter": "필터"
|
||||
"filter": "필터",
|
||||
"edit": "편집"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "वैकल्पिक",
|
||||
"close_thread": "थ्रेड बंद करा",
|
||||
"view_spoiler": "स्पॉईलर पहा",
|
||||
"filter": "फिल्टर"
|
||||
"filter": "फिल्टर",
|
||||
"edit": "संपादित करा"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "optioneel",
|
||||
"close_thread": "draad sluiten",
|
||||
"view_spoiler": "bekijk spoiler",
|
||||
"filter": "filter"
|
||||
"filter": "filter",
|
||||
"edit": "bewerken"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "valgfritt",
|
||||
"close_thread": "lukk tråd",
|
||||
"view_spoiler": "se spoiler",
|
||||
"filter": "filter"
|
||||
"filter": "filter",
|
||||
"edit": "rediger"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opcjonalnie",
|
||||
"close_thread": "zamknij wątek",
|
||||
"view_spoiler": "pokaż spoiler",
|
||||
"filter": "filtr"
|
||||
"filter": "filtr",
|
||||
"edit": "edytuj"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opcional",
|
||||
"close_thread": "fechar tópico",
|
||||
"view_spoiler": "ver spoiler",
|
||||
"filter": "filtro"
|
||||
"filter": "filtro",
|
||||
"edit": "editar"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opțional",
|
||||
"close_thread": "închide firul",
|
||||
"view_spoiler": "vezi spoilerul",
|
||||
"filter": "filtru"
|
||||
"filter": "filtru",
|
||||
"edit": "editați"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "необязательный",
|
||||
"close_thread": "закрыть тему",
|
||||
"view_spoiler": "посмотреть спойлер",
|
||||
"filter": "фильтр"
|
||||
"filter": "фильтр",
|
||||
"edit": "редактировать"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "opsionale",
|
||||
"close_thread": "mbyll temën",
|
||||
"view_spoiler": "shikoni spoiler",
|
||||
"filter": "filtruar"
|
||||
"filter": "filtruar",
|
||||
"edit": "redakto"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "valfritt",
|
||||
"close_thread": "stäng tråd",
|
||||
"view_spoiler": "visa spoiler",
|
||||
"filter": "filter"
|
||||
"filter": "filter",
|
||||
"edit": "redigera"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "ఐచ్ఛికం",
|
||||
"close_thread": "థ్రెడ్ను మూసేయండి",
|
||||
"view_spoiler": "స్పోయ్లర్ వీక్షించండి",
|
||||
"filter": "వడపోత"
|
||||
"filter": "వడపోత",
|
||||
"edit": "సవరించు"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "ไม่จำเป็น",
|
||||
"close_thread": "ปิดกระทู้",
|
||||
"view_spoiler": "ดูสปอยล์เลอร์",
|
||||
"filter": "ตัวกรอง"
|
||||
"filter": "ตัวกรอง",
|
||||
"edit": "แก้ไข"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "isteğe bağlı",
|
||||
"close_thread": "konuyu kapat",
|
||||
"view_spoiler": "spoileri görüntüle",
|
||||
"filter": "filtre"
|
||||
"filter": "filtre",
|
||||
"edit": "düzenle"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "необов’язково",
|
||||
"close_thread": "закрити тему",
|
||||
"view_spoiler": "переглянути спойлер",
|
||||
"filter": "фільтр"
|
||||
"filter": "фільтр",
|
||||
"edit": "редагувати"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "اختیاری",
|
||||
"close_thread": "موضوع بند کریں",
|
||||
"view_spoiler": "اسپوائلر دیکھیں",
|
||||
"filter": "فلٹر"
|
||||
"filter": "فلٹر",
|
||||
"edit": "ترمیم کریں"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "tùy chọn",
|
||||
"close_thread": "đóng chủ đề",
|
||||
"view_spoiler": "xem spoiler",
|
||||
"filter": "bộ lọc"
|
||||
"filter": "bộ lọc",
|
||||
"edit": "chỉnh sửa"
|
||||
}
|
||||
@@ -147,5 +147,6 @@
|
||||
"optional": "可选的",
|
||||
"close_thread": "关闭主题",
|
||||
"view_spoiler": "查看剧透",
|
||||
"filter": "过滤器"
|
||||
"filter": "过滤器",
|
||||
"edit": "编辑"
|
||||
}
|
||||
+14
-12
@@ -35,18 +35,20 @@ const BoardLayout = () => {
|
||||
<div className={styles.boardLayout}>
|
||||
<TopBar />
|
||||
<BoardHeader />
|
||||
{isMobile ? (
|
||||
<>
|
||||
<PostForm key={key} />
|
||||
<MobileBoardButtons />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<PostForm key={key} />
|
||||
{subplebbitAddress && <SubplebbitStats />}
|
||||
<DesktopBoardButtons />
|
||||
</>
|
||||
)}
|
||||
{isMobile
|
||||
? subplebbitAddress && (
|
||||
<>
|
||||
<PostForm key={key} />
|
||||
<MobileBoardButtons />
|
||||
</>
|
||||
)
|
||||
: subplebbitAddress && (
|
||||
<>
|
||||
<PostForm key={key} />
|
||||
<SubplebbitStats />
|
||||
<DesktopBoardButtons />
|
||||
</>
|
||||
)}
|
||||
<Outlet />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.menuItem input[type="text"] {
|
||||
|
||||
.menuItem input[type="text"], .editTextarea {
|
||||
padding: 2px;
|
||||
box-shadow: var(--box-shadow-input);
|
||||
margin-top: 2px;
|
||||
@@ -51,12 +52,12 @@
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.menuItem input[type="text"], .menuItem input[type='number'] {
|
||||
.menuItem input[type="text"], .menuItem input[type='number'], .editTextarea {
|
||||
border: var(--post-form-field-input-border);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.menuItem input[type="text"]:focus, .menuItem input[type='number']:focus {
|
||||
.menuItem input[type="text"]:focus, .menuItem input[type='number']:focus, .editTextarea:focus {
|
||||
border: var(--post-form-field-input-focus-border);
|
||||
}
|
||||
|
||||
@@ -65,6 +66,12 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.editTextarea {
|
||||
width: calc(100% - 12px);
|
||||
margin-left: 3px;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.bottom button {
|
||||
text-transform: capitalize;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { autoUpdate, flip, FloatingFocusManager, offset, shift, useClick, useDismiss, useFloating, useId, useInteractions, useRole } from '@floating-ui/react';
|
||||
import { PublishCommentEditOptions, useComment, useEditedComment, usePublishCommentEdit } from '@plebbit/plebbit-react-hooks';
|
||||
import styles from './edit-menu.module.css';
|
||||
@@ -10,35 +10,46 @@ import _ from 'lodash';
|
||||
const { addChallenge } = useChallengesStore.getState();
|
||||
|
||||
type EditMenuProps = {
|
||||
cid: string;
|
||||
commentCid: string;
|
||||
isAccountMod?: boolean;
|
||||
isAccountCommentAuthor?: boolean;
|
||||
isCommentAuthorMod?: boolean;
|
||||
};
|
||||
|
||||
const EditMenu = ({ cid, isAccountMod, isAccountCommentAuthor, isCommentAuthorMod }: EditMenuProps) => {
|
||||
const EditMenu = ({ commentCid, isAccountMod, isAccountCommentAuthor, isCommentAuthorMod }: EditMenuProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
let post: any;
|
||||
const comment = useComment({ commentCid: cid });
|
||||
const comment = useComment({ commentCid });
|
||||
const { editedComment } = useEditedComment({ comment });
|
||||
if (editedComment) {
|
||||
post = editedComment;
|
||||
} else if (comment) {
|
||||
post = comment;
|
||||
}
|
||||
const isReply = post?.parentCid;
|
||||
|
||||
const { banExpiresAt, content, deleted, locked, parentCid, pinned, removed, spoiler, subplebbitAddress } = post || {};
|
||||
const isReply = parentCid;
|
||||
|
||||
const [isEditMenuOpen, setIsEditMenuOpen] = useState(false);
|
||||
|
||||
const [isContentEditorOpen, setIsContentEditorOpen] = useState(false);
|
||||
const contentEditorRef = useRef<HTMLTextAreaElement>(null);
|
||||
useEffect(() => {
|
||||
if (contentEditorRef.current) {
|
||||
contentEditorRef.current.focus();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const defaultPublishOptions: PublishCommentEditOptions = {
|
||||
deleted: post?.deleted,
|
||||
removed: post?.removed,
|
||||
locked: post?.locked,
|
||||
spoiler: post?.spoiler,
|
||||
pinned: post?.pinned,
|
||||
commentAuthor: { banExpiresAt: post?.banExpiresAt },
|
||||
commentCid: post?.cid,
|
||||
subplebbitAddress: post?.subplebbitAddress,
|
||||
commentAuthor: { banExpiresAt },
|
||||
commentCid,
|
||||
content,
|
||||
deleted,
|
||||
locked,
|
||||
pinned,
|
||||
removed,
|
||||
spoiler,
|
||||
subplebbitAddress,
|
||||
onChallenge: (...args: any) => addChallenge([...args, post]),
|
||||
onChallengeVerification: alertChallengeVerificationFailed,
|
||||
onError: (error: Error) => {
|
||||
@@ -47,6 +58,13 @@ const EditMenu = ({ cid, isAccountMod, isAccountCommentAuthor, isCommentAuthorMo
|
||||
},
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEditMenuOpen) {
|
||||
setPublishCommentEditOptions(defaultPublishOptions);
|
||||
setIsContentEditorOpen(false);
|
||||
}
|
||||
}, [isEditMenuOpen]);
|
||||
|
||||
const [publishCommentEditOptions, setPublishCommentEditOptions] = useState(defaultPublishOptions);
|
||||
const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
|
||||
|
||||
@@ -98,15 +116,27 @@ const EditMenu = ({ cid, isAccountMod, isAccountCommentAuthor, isCommentAuthorMo
|
||||
|
||||
const headingId = useId();
|
||||
|
||||
const handleSaveClick = async () => {
|
||||
await publishCommentEdit();
|
||||
const _publishCommentEdit = async () => {
|
||||
try {
|
||||
await publishCommentEdit();
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.warn(error);
|
||||
alert(error.message);
|
||||
}
|
||||
}
|
||||
setIsEditMenuOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className={styles.checkbox} ref={refs.setReference} {...(cid && getReferenceProps())}>
|
||||
<input type='checkbox' onChange={() => cid && setIsEditMenuOpen(!isEditMenuOpen)} checked={isEditMenuOpen} />
|
||||
<span className={styles.checkbox} ref={refs.setReference} {...(commentCid && getReferenceProps())}>
|
||||
<input
|
||||
type='checkbox'
|
||||
onChange={() => commentCid && setIsEditMenuOpen(!isEditMenuOpen)}
|
||||
checked={isEditMenuOpen}
|
||||
disabled={!isAccountCommentAuthor && !isAccountMod}
|
||||
/>
|
||||
</span>
|
||||
{isEditMenuOpen && (isAccountCommentAuthor || isAccountMod) && (
|
||||
<FloatingFocusManager context={context} modal={false}>
|
||||
@@ -121,6 +151,23 @@ const EditMenu = ({ cid, isAccountMod, isAccountCommentAuthor, isCommentAuthorMo
|
||||
{_.capitalize(t('delete'))}? ]
|
||||
</label>
|
||||
</div>
|
||||
<div className={styles.menuItem}>
|
||||
<label>
|
||||
[
|
||||
<input type='checkbox' onChange={() => setIsContentEditorOpen(!isContentEditorOpen)} checked={isContentEditorOpen} />
|
||||
{_.capitalize(t('edit'))}? ]
|
||||
</label>
|
||||
</div>
|
||||
{isContentEditorOpen && (
|
||||
<div>
|
||||
<textarea
|
||||
className={styles.editTextarea}
|
||||
value={publishCommentEditOptions.content}
|
||||
ref={contentEditorRef}
|
||||
onChange={(e) => setPublishCommentEditOptions((state) => ({ ...state, content: e.target.value }))}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{isAccountMod && (
|
||||
@@ -178,11 +225,11 @@ const EditMenu = ({ cid, isAccountMod, isAccountCommentAuthor, isCommentAuthorMo
|
||||
</>
|
||||
)}
|
||||
<div className={`${styles.menuItem} ${styles.menuReason}`}>
|
||||
{_.capitalize(t('reason'))}?
|
||||
{_.capitalize(t('reason'))}? ({t('optional')})
|
||||
<input type='text' onChange={onReason} defaultValue={post?.reason} size={14} />
|
||||
</div>
|
||||
<div className={styles.bottom}>
|
||||
<button onClick={handleSaveClick}>{t('save')}</button>
|
||||
<button onClick={_publishCommentEdit}>{t('save')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -50,7 +50,7 @@ const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
||||
|
||||
return (
|
||||
<div className={styles.postInfo}>
|
||||
{!isHidden && <EditMenu cid={cid} isAccountCommentAuthor={isAccountCommentAuthor} isAccountMod={isAccountMod} isCommentAuthorMod={isCommentAuthorMod} />}
|
||||
{!isHidden && <EditMenu commentCid={cid} isAccountCommentAuthor={isAccountCommentAuthor} isAccountMod={isAccountMod} isCommentAuthorMod={isCommentAuthorMod} />}
|
||||
{title && <span className={styles.subject}>{displayTitle} </span>}
|
||||
<span className={styles.nameBlock}>
|
||||
<span className={`${styles.name} ${(isDescription || isRules || authorRole) && styles.capcodeMod}`}>
|
||||
|
||||
Reference in New Issue
Block a user