1
0
Fork 1
mirror of https://github.com/Vendicated/Vencord.git synced 2025-01-11 02:16:23 +00:00

HolyNotes Completed

Need Few small tweaks to be fixed
This commit is contained in:
Wolfie 2024-03-09 13:41:34 -04:00
parent a029aae719
commit 07840e2445
No known key found for this signature in database
GPG key ID: DE384EE9BF2D909A
9 changed files with 365 additions and 90 deletions

View file

@ -4,11 +4,12 @@
* SPDX-License-Identifier: GPL-3.0-or-later * 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; } = {}) => { export default ({ error }: { error?: Error; } = {}) => {
const classes = findByProps("emptyResultsWrap");
if (error) { if (error) {
// Error // Error
console.log(error); console.log(error);

View file

@ -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 (
<ModalRoot {...modalProps} className="vc-help-modal" size={ModalSize.MEDIUM}>
<ModalHeader className="notebook-header">
<Text tag="h3">Help Modal</Text>
<ModalCloseButton onClick={onClose} />
</ModalHeader>
<ModalContent>
<div className="vc-help-markdown">
<Text>Adding Notes</Text>
<Forms.FormText>
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={colorStatusGreen}>
Protip:
</span>{" "}
Clicking the "Note Message" button by itself will note to Main by default!
</Forms.FormText>
<hr />
<Text>Deleting Notes</Text>
<Forms.FormText>
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!
</Forms.FormText>
<hr />
<Text>Moving Notes</Text>
<Forms.FormText>
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.
</Forms.FormText>
<hr />
<Text>Jump To Message</Text>
<Forms.FormText>
To jump to the location that the note was originally located at just right click on the
note and hit "Jump to Message".
</Forms.FormText>
</div>
</ModalContent>
<ModalFooter>
<div className="vc-notebook-display-left">
<Button
look={Button.Looks.FILLED}
color={Button.Colors.GREEN}
onClick={() => {
noteHandler.refreshAvatars();
}}
>Refresh Avatars</Button>
</div>
</ModalFooter>
</ModalRoot>
);
};

View file

@ -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<React.SetStateAction<string>>; }) => {
const isNotMain = notebook !== "Main";
return (
<Button
color={isNotMain ? Button.Colors.RED : Button.Colors.GREEN}
onClick={
isNotMain
? () => openModal(props => <NotebookDeleteModal {...props} notebook={notebook} />)
: () => openModal(props => <NotebookCreateModal {...props} />)
}
>
{isNotMain ? "Delete Notebook" : "Create Notebook"}
</Button>
);
};

View file

@ -5,15 +5,18 @@
*/ */
import ErrorBoundary from "@components/ErrorBoundary"; import ErrorBoundary from "@components/ErrorBoundary";
import { Flex } from "@components/Flex"; import { classes } from "@utils/misc";
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal"; import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { React, TabBar, Text, TextInput } from "@webpack/common"; import { findByProps } from "@webpack";
import { ContextMenuApi, Flex, Menu, React, TabBar, Text, TextInput } from "@webpack/common";
import noteHandler from "plugins/holynotes/noteHandler"; import noteHandler from "plugins/holynotes/noteHandler";
import { HolyNotes } from "plugins/holynotes/types"; import { HolyNotes } from "plugins/holynotes/types";
import HelpIcon from "../icons/HelpIcon"; import HelpIcon from "../icons/HelpIcon";
import Errors from "./Error"; import Errors from "./Error";
import RenderMessage from "./RenderMessage"; import ManageNotebookButton from "./ManageNotebookButton";
import { RenderMessage } from "./RenderMessage";
import HelpModal from "./HelpModal";
const renderNotebook = ({ const renderNotebook = ({
notes, notebook, updateParent, sortDirection, sortType, searchInput, closeModal notes, notebook, updateParent, sortDirection, sortType, searchInput, closeModal
@ -26,15 +29,15 @@ const renderNotebook = ({
searchInput: string; searchInput: string;
closeModal: () => void; closeModal: () => void;
}) => { }) => {
const messageArray = Object.values(notes).map((note) => { const messageArray = Object.values(notes).map((note) => (
<RenderMessage <RenderMessage
note={note} note={note}
notebook={notebook} notebook={notebook}
updateParent={updateParent} updateParent={updateParent}
fromDeleteModal={false} fromDeleteModal={false}
closeModal={closeModal} closeModal={closeModal}
/>; />
}); ));
if (sortType) if (sortType)
messageArray.sort( messageArray.sort(
@ -43,7 +46,7 @@ const renderNotebook = ({
); );
if (sortDirection) messageArray.reverse(); if (sortDirection) messageArray.reverse();
console.log(messageArray);
const filteredMessages = messageArray.filter((message) => const filteredMessages = messageArray.filter((message) =>
message.props.note.content.toLowerCase().includes(searchInput.toLowerCase()), message.props.note.content.toLowerCase().includes(searchInput.toLowerCase()),
); );
@ -61,6 +64,8 @@ export const NoteModal = (props) => {
const [notes, setNotes] = React.useState({}); const [notes, setNotes] = React.useState({});
const [notebooks, setNotebooks] = React.useState([]); const [notebooks, setNotebooks] = React.useState([]);
const { quickSelect, quickSelectLabel, quickSelectQuick, quickSelectValue, quickSelectArrow } = findByProps("quickSelect");
const forceUpdate = React.useReducer(() => ({}), {})[1] as () => void; const forceUpdate = React.useReducer(() => ({}), {})[1] as () => void;
React.useEffect(() => { React.useEffect(() => {
@ -86,37 +91,37 @@ export const NoteModal = (props) => {
return ( return (
<ErrorBoundary> <ErrorBoundary>
<ModalRoot {...props} className="notebook" size="large" style={{ borderRadius: "8px" }}> <ModalRoot {...props} className={classes("vc-notebook")} size={ModalSize.LARGE} style={{ borderRadius: "8px" }}>
<Flex className="notebook-flex" style={{ width: "100%" }}> <Flex className={classes("vc-notebook-flex")} direction={Flex.Direction.VERTICAL} style={{ width: "100%" }}>
<div className="notebook-topSection"> <div className={classes("vc-notebook-top-section")}>
<ModalHeader className="notebook-header-main"> <ModalHeader className={classes("vc-notebook-header-main")}>
<Text <Text
variant="heading-lg/semibold" variant="heading-lg/semibold"
style={{ flexGrow: 1 }} style={{ flexGrow: 1 }}
className="notebook-heading"> className={classes("vc-notebook-heading")}>
NOTEBOOK NOTEBOOK
</Text> </Text>
<div className="notebook-flex help-icon" onClick={() => openModal()}> <div className={classes("vc-notebook-flex", "vc-help-icon")} onClick={() => openModal(HelpModal)}>
<HelpIcon /> <HelpIcon />
</div> </div>
<div style={{ marginBottom: "10px" }} className="notebook-search"> <div style={{ marginBottom: "10px" }} className={classes("vc-notebook-search")}>
<TextInput <TextInput
autoFocus={false} autoFocus={false}
placeholder="Search for a message..." placeholder="Search for a message..."
onChange={(e) => setSearch(e)} onChange={e => setSearch(e)}
/> />
</div> </div>
<ModalCloseButton onClick={props.onClose} /> <ModalCloseButton onClick={props.onClose} />
</ModalHeader> </ModalHeader>
<div className="notebook-tabbar-Container"> <div className={classes("vc-notebook-tabbar-container")}>
<TabBar <TabBar
type="top" type="top"
look="brand" look="brand"
className="notebook-tabbar-Bar notebook-tabbar" className={classes("vc-notebook-tabbar-bar", "vc-notebook-tabbar")}
selectedItem={currentNotebook} selectedItem={currentNotebook}
onItemSelect={setCurrentNotebook}> onItemSelect={setCurrentNotebook}>
{notebooks.map(notebook => ( {notebooks.map(notebook => (
<TabBar.Item key={notebook} id={notebook} className="notebook-tabbar-barItem notebook-tabbar-item"> <TabBar.Item key={notebook} id={notebook} className={classes("vc-notebook-tabbar-bar-item", "vc-notebook-tabbar-item")}>
{notebook} {notebook}
</TabBar.Item> </TabBar.Item>
))} ))}
@ -138,7 +143,53 @@ export const NoteModal = (props) => {
</ModalContent> </ModalContent>
</Flex> </Flex>
<ModalFooter> <ModalFooter>
<ManageNotebookButton notebook={currentNotebook} setNotebook={setCurrentNotebook} />
<div className={classes("sort-button-container", "vc-notebook-display-left")}>
<Flex
align={Flex.Align.CENTER}
className={quickSelect}
onClick={(event: React.MouseEvent<HTMLDivElement>) => {
ContextMenuApi.openContextMenu(event, () => (
<>
<Menu.MenuItem
label="Ascending / Date Added"
id="ada"
action={() => {
setSortDirection(true);
setSortType(true);
}} /><Menu.MenuItem
label="Ascending / Message Date"
id="amd"
action={() => {
setSortDirection(true);
setSortType(false);
}} /><Menu.MenuItem
label="Descending / Date Added"
id="dda"
action={() => {
setSortDirection(false);
setSortType(true);
}} /><Menu.MenuItem
label="Descending / Message Date"
id="dmd"
action={() => {
setSortDirection(false);
setSortType(false);
}} />
</>
));
}}
>
<Text className={quickSelectLabel}>Change Sorting:</Text>
<Flex grow={0} align={Flex.Align.CENTER} className={quickSelectQuick}>
<Text className={quickSelectValue}>
{sortDirection ? "Ascending" : "Descending"} /{" "}
{sortType ? "Date Added" : "Message Date"}
</Text>
<div className={quickSelectArrow} />
</Flex>
</Flex>
</div>
</ModalFooter> </ModalFooter>
</ModalRoot> </ModalRoot>
</ErrorBoundary> </ErrorBoundary>

View file

@ -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 (
<div>
<ModalRoot className="vc-create-notebook" size={ModalSize.SMALL} {...props}>
<ModalHeader className="vc-notebook-header">
<Text tag="h3">Create Notebook</Text>
<ModalCloseButton onClick={props.onClose} />
</ModalHeader>
<ModalContent>
<TextInput
value={notebookName}
placeholder="Notebook Name"
onChange={value => setNotebookName(value)}
style={{ marginBottom: "10px" }} />
</ModalContent>
<ModalFooter>
<Button onClick={handleCreateNotebook} color={Button.Colors.GREEN}>Create Notebook</Button>
</ModalFooter>
</ModalRoot>
</div>
);
};

View file

@ -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 (
<ModalRoot
{...props}
className="vc-delete-notebook"
size={ModalSize.LARGE}>
<ModalHeader>
<Text tag="h3">Confirm Deletion</Text>
<ModalCloseButton onClick={onClose} />
</ModalHeader>
<ModalContent>
<ErrorBoundary>
{Object.keys(notes).length === 0 || !notes ? (
<Error />
) : (
Object.values(notes).map(note => (
<RenderMessage
note={note}
notebook={notebook}
fromDeleteModal={true} />
))
)}
</ErrorBoundary>
</ModalContent>
<ModalFooter>
<Button
color={Button.Colors.RED}
onClick={() => {
noteHandler.deleteNotebook(notebook);
onClose();
}}
>
DELETE
</Button>
</ModalFooter>
</ModalRoot>
);
};

View file

@ -4,17 +4,14 @@
* SPDX-License-Identifier: GPL-3.0-or-later * 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 { ContextMenuApi, FluxDispatcher, Menu, NavigationRouter, React } from "@webpack/common";
import noteHandler from "plugins/holynotes/noteHandler"; import noteHandler from "plugins/holynotes/noteHandler";
import { HolyNotes } from "plugins/holynotes/types"; 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, note,
notebook, notebook,
updateParent, updateParent,
@ -28,6 +25,10 @@ export default ({
closeModal?: () => void; closeModal?: () => void;
}) => { }) => {
const ChannelMessage = findByProps("ThreadStarterChatMessage").default; 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); const [isHoldingDelete, setHoldingDelete] = React.useState(false);
@ -44,11 +45,9 @@ export default ({
}; };
}, []); }, []);
console.log(note, notebook, updateParent, fromDeleteModal, closeModal); return (
const render = (
<div <div
className="holy-note" className="vc-holy-note"
style={{ style={{
marginBottom: "8px", marginBottom: "8px",
marginTop: "8px", marginTop: "8px",
@ -76,8 +75,8 @@ export default ({
)); ));
}} }}
> >
{/* <ChannelMessage <ChannelMessage
className={`holy-render ${message} ${groupStart} ${cozyMessage}`} className={classes("vc-holy-render", message, groupStart, cozyMessage)}
key={note.id} key={note.id}
groupId={note.id} groupId={note.id}
id={note.id} id={note.id}
@ -106,13 +105,10 @@ export default ({
), ),
) )
} }
/> */} />
</div> </div>
); );
console.log(render);
return render;
}; };
const NoteContextMenu = (props) => { const NoteContextMenu = (props) => {

View file

@ -5,11 +5,12 @@
*/ */
import { DataStore } from "@api/index"; 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 { Channel, Message } from "discord-types/general";
import { Discord, HolyNotes } from "./types"; import { Discord, HolyNotes } from "./types";
import { HolyNoteStore } from "./utils"; import { HolyNoteStore } from "./utils";
import { findByCode } from "@webpack";
export default new (class NoteHandler { export default new (class NoteHandler {
@ -119,4 +120,30 @@ export default new (class NoteHandler {
type: Toasts.Type.SUCCESS, 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,
});
};
}); });

View file

@ -1,20 +1,21 @@
/* /*
$modifier: var(--background-modifier-accent); $modifier: var(--background-modifier-accent);
*/ */
.notebook-search {
.vc-notebook-search {
flex: auto; flex: auto;
margin-right: 15px; margin-right: 15px;
margin-bottom: 6px; margin-bottom: 6px;
background-color: var(--background-tertiary); background-color: var(--background-tertiary);
border: solid 2px var(--background-secondary); 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-top: 15px;
padding-left: 10px; padding-left: 10px;
padding-bottom: 0px; 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; 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; max-width: 110px;
margin-right: 0px; margin-right: 0px;
padding-bottom: 6px; padding-bottom: 6px;
transform: scale(1); transform: scale(1);
} }
.notebook-tabbar { .vc-notebook-tabbar {
margin: 0; margin: 0;
padding: 10px 20px 0; padding: 10px 20px 0;
background-color: var(--background-tertiary); background-color: var(--background-tertiary);
} }
.notebook-tabbar-item { .vc-notebook-tabbar-item {
font-size: 14px; font-size: 14px;
} }
.notebook-display-left { .vc-notebook-display-left {
flex: auto; flex: auto;
display: flex; display: flex;
} }
.notebook-flex { .vc-notebook-flex {
overflow: hidden; overflow: hidden;
} }
.notebook-flex .help-icon { .vc-notebook-flex .vc-help-icon {
width: 23px; width: 23px;
opacity: 0.5; opacity: 0.5;
cursor: pointer; cursor: pointer;
padding-left: 0px; padding-left: 0px;
margin: 0px 14px 6px 0px; margin: 0px 14px 6px 0px;
color: var(--interactive-normal); color: var(--interactive-normal);
transition: opacity 0.2s ease-in-out; transition: opacity 0.2s ease-in-out;
} }
.notebook-flex .help-icon:hover { .vc-notebook-flex .help-icon:hover {
opacity: 1; opacity: 1;
} }
.help-markdown { .vc-help-markdown {
margin-top: 6px; margin-top: 6px;
} }
.help-markdown hr { .vc-help-markdown hr {
border: 0; border: 0;
height: 2px; height: 2px;
margin: 12px 0px 16px 0px; margin: 12px 0px 16px 0px;
background-color: var(--background-modifier-accent); background-color: var(--background-modifier-accent);
} }
.holy-note [class*="buttonContainer"] { .vc-holy-note [class*="buttonContainer"] {
display: none; display: none;
} }
.holy-note [class*="messageListItem"] { .vc-holy-note [class*="messageListItem"] {
list-style-type: none; list-style-type: none;
} }
.notebook-tabbar-Bar { .vc-notebook-tabbar-bar {
align-items: stretch; align-items: stretch;
display: flex; display: flex;
gap: 40px; gap: 40px;
} }
.notebook-tabbar-Container { .vc-notebook-tabbar-container {
border-bottom: 1px solid var(--profile-body-divider-color); border-bottom: 1px solid var(--profile-body-divider-color);
margin: 20px 12px 0; margin: 20px 12px 0;
padding: 0; padding: 0;
} }
.notebook-tabbar-barItem { .vc-notebook-tabbar-bar-item {
display: inline; display: inline;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
height: 39px; height: 39px;
font-size: 14px; font-size: 14px;
} }
.notebook-topSection { .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))); 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; z-index: 1;
} }