HolyNotes: fix some horror (#494)

* HolyNotes: fix horror

* NoteButton

---------

Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
prism 2025-11-11 23:02:44 +01:00 • committed by GitHub
parent f7911d15d4
commit 264b963fdf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 110 additions and 53 deletions

View file

@ -397,6 +397,27 @@ export function NotesIcon(props: IconProps) {
);
}
export function IDIcon(props: IconProps) {
return (
<Icon
{...props}
className={classes(props.className, "vc-id-icon")}
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M15.3 14.48c-.46.45-1.08.67-1.86.67h-1.39V9.2h1.39c.78 0 1.4.22 1.86.67.46.45.68 1.22.68 2.31 0 1.1-.22 1.86-.68 2.31Z"
/>
<path
fill="currentColor"
fillRule="evenodd"
d="M5 2a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V5a3 3 0 0 0-3-3H5Zm1 15h2.04V7.34H6V17Zm4-9.66V17h3.44c1.46 0 2.6-.42 3.38-1.25.8-.83 1.2-2.02 1.2-3.58s-.4-2.75-1.2-3.58c-.79-.83-1.92-1.25-3.38-1.25H10Z"
clipRule="evenodd"
/>
</Icon>
);
}
export function FolderIcon(props: IconProps) {
return (
<Icon

View file

@ -7,7 +7,12 @@
import { JSX } from "react";
const component = (props: React.SVGProps<SVGSVGElement>): JSX.Element => (
<svg viewBox="6 3.7 16 16" width={24} height={24} {...(props as React.SVGProps<SVGSVGElement>)}>
<svg
viewBox="6 3.7 16 16"
width={24}
height={24}
{...(props as React.SVGProps<SVGSVGElement>)}
>
<path
fill="currentColor"
d="M15.44,5H12.88v6.42L11.12,9.67,9.38,11.42V5H7a.58.58,0,0,0-.58.58V16.5a.56.56,0,0,0,.09.31l1.18,1.91a.55.55,0,0,0,.49.28H17a.58.58,0,0,0,.58-.58V8.48a.52.52,0,0,0-.07-.27L16,5.31A.6.6,0,0,0,15.44,5Zm.94,12.83H8.52l-.71-1.16h7.4a.58.58,0,0,0,.58-.59V7.41l.59,1.25Z"

View file

@ -18,21 +18,20 @@ export default ({ onClose, ...modalProps }: ModalProps & { onClose: () => void;
return (
<ModalRoot {...modalProps} className="vc-help-modal" size={ModalSize.MEDIUM}>
<ModalHeader className="notebook-header">
<BaseText tag="h3">Help Modal</BaseText>
<ModalHeader className="vc-help-modal-header">
<BaseText tag="h3" style={{ flexGrow: 1 }}>Help Modal</BaseText>
<ModalCloseButton onClick={onClose} />
</ModalHeader>
<ModalContent>
<div className="vc-help-markdown">
<BaseText>Adding Notes</BaseText>
<Paragraph>
To add a note right click on a message then hover over the "Note Message" item and click
<br />
the button with the notebook name you would like to note the message to.
<br />
<span style={{ fontWeight: "bold" }} className={statusTagGreen}>
Protip:
</span>{" "}
To add a note right click on a message then hover over the "Note Message" item and click the button with the notebook name you would like to note the message to.
</Paragraph>
<div style={{ marginTop: "12px" }}>
<span className={statusTagGreen}>Protip:</span>
</div>
<Paragraph style={{ marginTop: "8px" }}>
Clicking the "Note Message" button by itself will note to Main by default!
</Paragraph>
<hr />
@ -56,25 +55,22 @@ export default ({ onClose, ...modalProps }: ModalProps & { onClose: () => void;
</div>
</ModalContent>
<ModalFooter>
<div className="vc-notebook-display-left">
<div className="vc-help-modal-footer">
<Button
look={Button.Looks.FILLED}
color={Button.Colors.GREEN}
style={{ marginRight: "10px" }}
onClick={() => {
noteHandler.refreshAvatars();
}}>Refresh Avatars</Button>
<Button
look={Button.Looks.FILLED}
color={Button.Colors.GREEN}
style={{ marginRight: "10px" }}
onClick={() => {
uploadNotes();
}}>Import Notes</Button>
<Button
look={Button.Looks.FILLED}
color={Button.Colors.GREEN}
style={{ marginRight: "10px" }}
onClick={() => {
downloadNotes();
}}>Export Notes</Button>

View file

@ -170,8 +170,6 @@ export function CreateTabBar({ tabs, firstSelectedTab, onChangeTab }) {
firstSelectedTab || (tabKeys.length > 0 ? tabKeys[0] : null)
);
const renderSelectedTab = React.useCallback(() => {
const selectedTabId = tabKeys.find(tab => tab === selectedTab);
return selectedTabId;

View file

@ -31,9 +31,28 @@ const renderNotebook = ({
searchInput: string;
closeModal: () => void;
}) => {
const messageArray = Object.values(notes).map(note => (
let notesArray = Object.values(notes);
if (searchInput) {
const searchLower = searchInput.toLowerCase();
notesArray = notesArray.filter(note =>
note.content?.toLowerCase().includes(searchLower)
);
}
if (!notesArray.length) return <Errors />;
if (sortType) {
notesArray.sort((a, b) =>
new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
);
}
if (sortDirection) notesArray.reverse();
return notesArray.map(note => (
<RenderMessage
key={notebook}
key={note.id || notebook}
note={note}
notebook={notebook}
updateParent={updateParent}
@ -41,20 +60,6 @@ const renderNotebook = ({
closeModal={closeModal}
/>
));
if (sortType)
messageArray.sort(
(a, b) =>
new Date(b.props.note?.timestamp)?.getTime() - new Date(a.props.note?.timestamp)?.getTime(),
);
if (sortDirection) messageArray.reverse();
const filteredMessages = messageArray.filter(message =>
message.props.note?.content?.toLowerCase().includes(searchInput.toLowerCase()),
);
return filteredMessages.length > 0 ? filteredMessages : <Errors />;
};
@ -65,7 +70,7 @@ export const NoteModal = (props: ModalProps & { onClose: () => void; }) => {
const [sortDirection, setSortDirection] = React.useState(true);
const [currentNotebook, setCurrentNotebook] = React.useState("Main");
const { quickSelect, quickSelectLabel, quickSelectQuick, quickSelectValue, quickSelectArrow } = findByProps("quickSelect");
const { quickSelect, quickSelectLabel, quickSelectQuick, quickSelectValue, quickSelectArrow } = findByProps("quickSelect") || {};
const forceUpdate = React.useReducer(() => ({}), {})[1] as () => void;

View file

@ -4,17 +4,22 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { CopyIcon, DeleteIcon, IDIcon, LinkIcon, OpenExternalIcon } from "@components/Icons";
import { makeDummyUser } from "@components/settings/tabs/plugins/PluginModal";
import { MessageType } from "@equicordplugins/holyNotes";
import { copyToClipboard } from "@utils/clipboard";
import { classes } from "@utils/misc";
import { ModalProps } from "@utils/modal";
import { findByCodeLazy, findByProps, findComponentByCodeLazy } from "@webpack";
import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { ContextMenuApi, FluxDispatcher, Menu, NavigationRouter, React } from "@webpack/common";
import { noteHandler } from "../../NoteHandler";
import { HolyNotes } from "../../types";
const messageClasses = findByPropsLazy("message", "groupStart", "cozyMessage");
const Channel = findByCodeLazy("computeLurkerPermissionsAllowList(){");
const ChannelMessage = findComponentByCodeLazy("Message must not be a thread");
export const RenderMessage = ({
note,
notebook,
@ -28,15 +33,18 @@ export const RenderMessage = ({
fromDeleteModal: boolean;
closeModal?: () => void;
}) => {
const { message, groupStart, cozyMessage } = findByProps("cozyMessage");
const Channel = findByCodeLazy("computeLurkerPermissionsAllowList(){");
const ChannelMessage = findComponentByCodeLazy("Message must not be a thread");
const [isHoldingDelete, setHoldingDelete] = React.useState(false);
const isHoldingDeleteRef = React.useRef(false);
const [, forceUpdate] = React.useReducer(x => x + 1, 0);
React.useEffect(() => {
const deleteHandler = (e: { key: string; type: string; }) =>
e.key.toLowerCase() === "delete" && setHoldingDelete(e.type.toLowerCase() === "keydown");
const deleteHandler = (e: KeyboardEvent) => {
if (e.key.toLowerCase() !== "delete") return;
const newState = e.type === "keydown";
if (isHoldingDeleteRef.current !== newState) {
isHoldingDeleteRef.current = newState;
forceUpdate();
}
};
document.addEventListener("keydown", deleteHandler);
document.addEventListener("keyup", deleteHandler);
@ -57,7 +65,7 @@ export const RenderMessage = ({
paddingBottom: "4px",
}}
onClick={() => {
if (isHoldingDelete && !fromDeleteModal) {
if (isHoldingDeleteRef.current && !fromDeleteModal) {
noteHandler.deleteNote(note.id, notebook);
updateParent?.();
}
@ -78,7 +86,7 @@ export const RenderMessage = ({
}}
>
<ChannelMessage
className={classes("vc-holy-render", message, groupStart, cozyMessage)}
className={classes("vc-holy-render", messageClasses?.message, messageClasses?.groupStart, messageClasses?.cozyMessage)}
key={note.id}
groupId={note.id}
id={note.id}
@ -135,26 +143,26 @@ const NoteContextMenu = (
NavigationRouter.transitionTo(`/channels/${note.guild_id ?? "@me"}/${note.channel_id}/${note.id}`);
closeModal?.();
}}
icon={OpenExternalIcon}
/>
<Menu.MenuItem
label="Copy Text"
id="copy-text"
action={() => copyToClipboard(note.content)}
icon={CopyIcon}
/>
{note?.attachments.length ? (
<Menu.MenuItem
label="Copy Attachment URL"
id="copy-url"
action={() => copyToClipboard(note.attachments[0].url)}
icon={LinkIcon}
/>) : null}
<Menu.MenuItem
color="danger"
label="Delete Note"
id="delete"
action={() => {
noteHandler.deleteNote(note.id, notebook);
updateParent?.();
}}
label="Copy ID"
id="copy-id"
action={() => copyToClipboard(note.id)}
icon={IDIcon}
/>
{Object.keys(noteHandler.getAllNotes()).length !== 1 ? (
<Menu.MenuItem
@ -179,9 +187,14 @@ const NoteContextMenu = (
</Menu.MenuItem>
) : null}
<Menu.MenuItem
label="Copy ID"
id="copy-id"
action={() => copyToClipboard(note.id)}
color="danger"
label="Delete Note"
id="delete"
action={() => {
noteHandler.deleteNote(note.id, notebook);
updateParent?.();
}}
icon={DeleteIcon}
/>
</Menu.Menu>
);

View file

@ -134,3 +134,22 @@ $modifier: var(--input-border);
margin-bottom: calc(-8px + .15*(var(--custom-user-profile-modal-header-avatar-size) + var(--custom-user-profile-modal-header-total-avatar-border-size)));
z-index: 1;
}
.vc-help-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
}
.vc-help-modal-footer {
display: flex;
flex-wrap: wrap;
gap: 10px;
width: 100%;
}
.vc-help-markdown span[class*="statusTag"] {
display: inline-block;
width: auto;
}