diff --git a/src/plugins/holynotes/components/modals/Error.tsx b/src/plugins/holynotes/components/modals/Error.tsx index 30d33a334..3f8e9c9de 100644 --- a/src/plugins/holynotes/components/modals/Error.tsx +++ b/src/plugins/holynotes/components/modals/Error.tsx @@ -4,11 +4,12 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -import { findByCodeLazy } from "@webpack"; +import { findByCodeLazy, findByProps } from "@webpack"; -const classes = findByCodeLazy("emptyResultsWrap"); export default ({ error }: { error?: Error; } = {}) => { + const classes = findByProps("emptyResultsWrap"); + if (error) { // Error console.log(error); diff --git a/src/plugins/holynotes/components/modals/HelpModal.tsx b/src/plugins/holynotes/components/modals/HelpModal.tsx new file mode 100644 index 000000000..c61761047 --- /dev/null +++ b/src/plugins/holynotes/components/modals/HelpModal.tsx @@ -0,0 +1,67 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize } from "@utils/modal"; +import { findByProps } from "@webpack"; +import { Button, Forms, Text, TextArea } from "@webpack/common"; +import noteHandler from "plugins/holynotes/noteHandler"; + +export default ({ onClose, ...modalProps }: { onClose: () => void; }) => { + const { colorStatusGreen } = findByProps("colorStatusGreen"); + + return ( + + + Help Modal + + + +
+ Adding Notes + + 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. +
+ + Protip: + {" "} + Clicking the "Note Message" button by itself will note to Main by default! +
+
+ Deleting Notes + + Note you can either right click the note and hit "Delete Note" or you can hold the + 'DELETE' key on your keyboard and click on a note; it's like magic! + +
+ Moving Notes + + To move a note right click on a note and hover over the "Move Note" item and click on + the button corresponding to the notebook you would like to move the note to. + +
+ Jump To Message + + To jump to the location that the note was originally located at just right click on the + note and hit "Jump to Message". + +
+
+ +
+ +
+
+
+ ); +}; diff --git a/src/plugins/holynotes/components/modals/ManageNotebookButton.tsx b/src/plugins/holynotes/components/modals/ManageNotebookButton.tsx new file mode 100644 index 000000000..bc1fe3860 --- /dev/null +++ b/src/plugins/holynotes/components/modals/ManageNotebookButton.tsx @@ -0,0 +1,28 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { openModal } from "@utils/modal"; +import { Button, React } from "@webpack/common"; + +import NotebookCreateModal from "./NotebookCreateModal"; +import NotebookDeleteModal from "./NotebookDeleteModal"; + +export default ({ notebook }: { notebook: string, setNotebook: React.Dispatch>; }) => { + const isNotMain = notebook !== "Main"; + + return ( + + ); +}; diff --git a/src/plugins/holynotes/components/modals/Notebook.tsx b/src/plugins/holynotes/components/modals/Notebook.tsx index 6cbb614c5..8bb6a57bb 100644 --- a/src/plugins/holynotes/components/modals/Notebook.tsx +++ b/src/plugins/holynotes/components/modals/Notebook.tsx @@ -5,15 +5,18 @@ */ import ErrorBoundary from "@components/ErrorBoundary"; -import { Flex } from "@components/Flex"; -import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal"; -import { React, TabBar, Text, TextInput } from "@webpack/common"; +import { classes } from "@utils/misc"; +import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal"; +import { findByProps } from "@webpack"; +import { ContextMenuApi, Flex, Menu, React, TabBar, Text, TextInput } from "@webpack/common"; import noteHandler from "plugins/holynotes/noteHandler"; import { HolyNotes } from "plugins/holynotes/types"; import HelpIcon from "../icons/HelpIcon"; import Errors from "./Error"; -import RenderMessage from "./RenderMessage"; +import ManageNotebookButton from "./ManageNotebookButton"; +import { RenderMessage } from "./RenderMessage"; +import HelpModal from "./HelpModal"; const renderNotebook = ({ notes, notebook, updateParent, sortDirection, sortType, searchInput, closeModal @@ -26,15 +29,15 @@ const renderNotebook = ({ searchInput: string; closeModal: () => void; }) => { - const messageArray = Object.values(notes).map((note) => { + const messageArray = Object.values(notes).map((note) => ( ; - }); + /> + )); if (sortType) messageArray.sort( @@ -43,7 +46,7 @@ const renderNotebook = ({ ); if (sortDirection) messageArray.reverse(); - console.log(messageArray); + const filteredMessages = messageArray.filter((message) => message.props.note.content.toLowerCase().includes(searchInput.toLowerCase()), ); @@ -61,6 +64,8 @@ export const NoteModal = (props) => { const [notes, setNotes] = React.useState({}); const [notebooks, setNotebooks] = React.useState([]); + const { quickSelect, quickSelectLabel, quickSelectQuick, quickSelectValue, quickSelectArrow } = findByProps("quickSelect"); + const forceUpdate = React.useReducer(() => ({}), {})[1] as () => void; React.useEffect(() => { @@ -86,37 +91,37 @@ export const NoteModal = (props) => { return ( - - -
- + + +
+ + className={classes("vc-notebook-heading")}> NOTEBOOK -
openModal()}> +
openModal(HelpModal)}>
-
+
setSearch(e)} + onChange={e => setSearch(e)} />
-
+
{notebooks.map(notebook => ( - + {notebook} ))} @@ -138,7 +143,53 @@ export const NoteModal = (props) => { - + +
+ ) => { + ContextMenuApi.openContextMenu(event, () => ( + <> + { + setSortDirection(true); + setSortType(true); + }} /> { + setSortDirection(true); + setSortType(false); + }} /> { + setSortDirection(false); + setSortType(true); + }} /> { + setSortDirection(false); + setSortType(false); + }} /> + + )); + }} + > + Change Sorting: + + + {sortDirection ? "Ascending" : "Descending"} /{" "} + {sortType ? "Date Added" : "Message Date"} + +
+ + +
diff --git a/src/plugins/holynotes/components/modals/NotebookCreateModal.tsx b/src/plugins/holynotes/components/modals/NotebookCreateModal.tsx new file mode 100644 index 000000000..4a49673ed --- /dev/null +++ b/src/plugins/holynotes/components/modals/NotebookCreateModal.tsx @@ -0,0 +1,40 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize } from "@utils/modal"; +import { Button, React, Text, TextInput } from "@webpack/common"; +import noteHandler from "plugins/holynotes/noteHandler"; + +export default props => { + const [notebookName, setNotebookName] = React.useState(""); + + const handleCreateNotebook = React.useCallback(() => { + if (notebookName !== "") noteHandler.newNoteBook(notebookName); + props.onClose(); + }, [notebookName]); + console.log(props); + + return ( +
+ + + Create Notebook + + + + setNotebookName(value)} + style={{ marginBottom: "10px" }} /> + + + + + +
+ ); +}; diff --git a/src/plugins/holynotes/components/modals/NotebookDeleteModal.tsx b/src/plugins/holynotes/components/modals/NotebookDeleteModal.tsx new file mode 100644 index 000000000..2cc0f2cd1 --- /dev/null +++ b/src/plugins/holynotes/components/modals/NotebookDeleteModal.tsx @@ -0,0 +1,64 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2024 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import ErrorBoundary from "@components/ErrorBoundary"; +import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize } from "@utils/modal"; +import { Button, React, Text } from "@webpack/common"; +import noteHandler from "plugins/holynotes/noteHandler"; + +import Error from "./Error"; +import { RenderMessage } from "./RenderMessage"; + +export default ({ onClose, notebook, ...props }: { onClose: () => void; notebook: string; }) => { + const [notes, setNotes] = React.useState({}); + + React.useEffect(() => { + const update = async () => { + const notes = await noteHandler.getNotes(notebook); + setNotes(notes); + }; + update(); + }, []); + + if (!notes) return <>; + + return ( + + + Confirm Deletion + + + + + {Object.keys(notes).length === 0 || !notes ? ( + + ) : ( + Object.values(notes).map(note => ( + + )) + )} + + + + + + + ); +}; diff --git a/src/plugins/holynotes/components/modals/RenderMessage.tsx b/src/plugins/holynotes/components/modals/RenderMessage.tsx index 6d749be3e..64a7fade9 100644 --- a/src/plugins/holynotes/components/modals/RenderMessage.tsx +++ b/src/plugins/holynotes/components/modals/RenderMessage.tsx @@ -4,17 +4,14 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -import { findByCodeLazy, findByProps, findByPropsLazy } from "@webpack"; +import { classes } from "@utils/misc"; +import { findByCode, findByProps } from "@webpack"; import { ContextMenuApi, FluxDispatcher, Menu, NavigationRouter, React } from "@webpack/common"; import noteHandler from "plugins/holynotes/noteHandler"; import { HolyNotes } from "plugins/holynotes/types"; -const { message, groupStart, cozyMessage } = findByPropsLazy("cozyMessage"); -const User = findByCodeLazy("isClyde(){"); -const Message = findByCodeLazy("isEdited(){"); -const Channel = findByCodeLazy("ChannelRecordBase"); -export default ({ +export const RenderMessage = ({ note, notebook, updateParent, @@ -28,6 +25,10 @@ export default ({ closeModal?: () => void; }) => { const ChannelMessage = findByProps("ThreadStarterChatMessage").default; + const { message, groupStart, cozyMessage } = findByProps("cozyMessage"); + const User = findByCode("isClyde(){"); + const Message = findByCode("isEdited(){"); + const Channel = findByProps("ChannelRecordBase").ChannelRecordBase; const [isHoldingDelete, setHoldingDelete] = React.useState(false); @@ -44,11 +45,9 @@ export default ({ }; }, []); - console.log(note, notebook, updateParent, fromDeleteModal, closeModal); - - const render = ( + return (
- {/* */} + />
); - - console.log(render); - return render; }; const NoteContextMenu = (props) => { diff --git a/src/plugins/holynotes/noteHandler.ts b/src/plugins/holynotes/noteHandler.ts index 837ea21ed..6caae5d4f 100644 --- a/src/plugins/holynotes/noteHandler.ts +++ b/src/plugins/holynotes/noteHandler.ts @@ -5,11 +5,12 @@ */ import { DataStore } from "@api/index"; -import { ChannelStore, Toasts, lodash } from "@webpack/common"; +import { ChannelStore, Toasts, UserStore, lodash, showToast } from "@webpack/common"; import { Channel, Message } from "discord-types/general"; import { Discord, HolyNotes } from "./types"; import { HolyNoteStore } from "./utils"; +import { findByCode } from "@webpack"; export default new (class NoteHandler { @@ -119,4 +120,30 @@ export default new (class NoteHandler { type: Toasts.Type.SUCCESS, }); }; + + public refreshAvatars = async () => { + const notebooks = await this.getAllNotes(); + + const User = findByCode("tag", "isClyde"); + + for (const notebook in notebooks) + for (const noteId in notebooks[notebook]) { + const note = notebooks[notebook][noteId]; + const user = UserStore.getUser(note.author.id) ?? new User({ ...note.author }); + + Object.assign(notebooks[notebook][noteId].author, { + avatar: user.avatar, + discriminator: user.discriminator, + username: user.username, + }); + } + + for (const notebook in notebooks) await DataStore.set(notebook, notebooks[notebook]); + Toasts.show({ + id: Toasts.genId(), + message: "Successfully refreshed avatars.", + type: Toasts.Type.SUCCESS, + }); + + }; }); diff --git a/src/plugins/holynotes/style.css b/src/plugins/holynotes/style.css index 8f890926b..646be422d 100644 --- a/src/plugins/holynotes/style.css +++ b/src/plugins/holynotes/style.css @@ -1,20 +1,21 @@ /* $modifier: var(--background-modifier-accent); */ -.notebook-search { + +.vc-notebook-search { flex: auto; margin-right: 15px; margin-bottom: 6px; background-color: var(--background-tertiary); border: solid 2px var(--background-secondary); - } - -.notebook-header { - margin-bottom: 10px; - padding: 16px 16px 10px; } -.notebook-header-main { +.vc-notebook-header { + margin-bottom: 10px; + padding: 16px 16px 10px 16px; +} + +.vc-notebook-header-main { padding-top: 15px; padding-left: 10px; padding-bottom: 0px; @@ -22,85 +23,85 @@ $modifier: var(--background-modifier-accent); box-shadow: 0 1px 0 0 var(--background-tertiary), 0 1px 2px 0 var(--background-tertiary) !important; } -.notebook-heading { +.vc-notebook-heading { max-width: 110px; margin-right: 0px; padding-bottom: 6px; transform: scale(1); - } +} -.notebook-tabbar { +.vc-notebook-tabbar { margin: 0; padding: 10px 20px 0; background-color: var(--background-tertiary); } -.notebook-tabbar-item { +.vc-notebook-tabbar-item { font-size: 14px; } -.notebook-display-left { +.vc-notebook-display-left { flex: auto; display: flex; } -.notebook-flex { - overflow: hidden; +.vc-notebook-flex { + overflow: hidden; } -.notebook-flex .help-icon { - width: 23px; - opacity: 0.5; - cursor: pointer; - padding-left: 0px; - margin: 0px 14px 6px 0px; - color: var(--interactive-normal); - transition: opacity 0.2s ease-in-out; +.vc-notebook-flex .vc-help-icon { + width: 23px; + opacity: 0.5; + cursor: pointer; + padding-left: 0px; + margin: 0px 14px 6px 0px; + color: var(--interactive-normal); + transition: opacity 0.2s ease-in-out; } -.notebook-flex .help-icon:hover { - opacity: 1; +.vc-notebook-flex .help-icon:hover { + opacity: 1; } -.help-markdown { - margin-top: 6px; +.vc-help-markdown { + margin-top: 6px; } -.help-markdown hr { - border: 0; - height: 2px; - margin: 12px 0px 16px 0px; - background-color: var(--background-modifier-accent); +.vc-help-markdown hr { + border: 0; + height: 2px; + margin: 12px 0px 16px 0px; + background-color: var(--background-modifier-accent); } -.holy-note [class*="buttonContainer"] { - display: none; +.vc-holy-note [class*="buttonContainer"] { + display: none; } -.holy-note [class*="messageListItem"] { - list-style-type: none; +.vc-holy-note [class*="messageListItem"] { + list-style-type: none; } -.notebook-tabbar-Bar { - align-items: stretch; - display: flex; - gap: 40px; +.vc-notebook-tabbar-bar { + align-items: stretch; + display: flex; + gap: 40px; } -.notebook-tabbar-Container { - border-bottom: 1px solid var(--profile-body-divider-color); - margin: 20px 12px 0; - padding: 0; +.vc-notebook-tabbar-container { + border-bottom: 1px solid var(--profile-body-divider-color); + margin: 20px 12px 0; + padding: 0; } -.notebook-tabbar-barItem { - display: inline; - border-bottom: 2px solid transparent; - height: 39px; - font-size: 14px; +.vc-notebook-tabbar-bar-item { + display: inline; + border-bottom: 2px solid transparent; + height: 39px; + font-size: 14px; } -.notebook-topSection { - margin-bottom: calc(-8px + .5*(var(--custom-user-profile-modal-header-avatar-size) + var(--custom-user-profile-modal-header-total-avatar-border-size))); - z-index: 1; +.vc-notebook-top-section { + margin-bottom: calc(-8px + .5*(var(--custom-user-profile-modal-header-avatar-size) + var(--custom-user-profile-modal-header-total-avatar-border-size))); + z-index: 1; }