diff --git a/reminder-dashboard/package-lock.json b/reminder-dashboard/package-lock.json index a405383..0420831 100644 --- a/reminder-dashboard/package-lock.json +++ b/reminder-dashboard/package-lock.json @@ -8,10 +8,10 @@ "dependencies": { "axios": "^1.5.1", "bulma": "^0.9.4", - "humanize-duration": "^3.31.0", "luxon": "^3.4.3", "preact": "^10.13.1", "react-colorful": "^5.6.1", + "react-mentions": "^4.4.10", "react-query": "^3.39.3", "tributejs": "^5.1.3", "use-debounce": "^10.0.0", @@ -3322,11 +3322,6 @@ "he": "bin/he" } }, - "node_modules/humanize-duration": { - "version": "3.31.0", - "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.31.0.tgz", - "integrity": "sha512-fRrehgBG26NNZysRlTq1S+HPtDpp3u+Jzdc/d5A4cEzOD86YLAkDaJyJg8krSdCi7CJ+s7ht3fwRj8Dl+Btd0w==" - }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -3395,6 +3390,14 @@ "node": ">= 0.4" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -4075,7 +4078,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4382,7 +4384,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -4484,8 +4485,35 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-mentions": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/react-mentions/-/react-mentions-4.4.10.tgz", + "integrity": "sha512-JHiQlgF1oSZR7VYPjq32wy97z1w1oE4x10EuhKjPr4WUKhVzG1uFQhQjKqjQkbVqJrmahf+ldgBTv36NrkpKpA==", + "dependencies": { + "@babel/runtime": "7.4.5", + "invariant": "^2.2.4", + "prop-types": "^15.5.8", + "substyle": "^9.1.0" + }, + "peerDependencies": { + "react": ">=16.8.3", + "react-dom": ">=16.8.3" + } + }, + "node_modules/react-mentions/node_modules/@babel/runtime": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", + "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", + "dependencies": { + "regenerator-runtime": "^0.13.2" + } + }, + "node_modules/react-mentions/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/react-onclickoutside": { "version": "6.13.0", @@ -4963,6 +4991,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/substyle": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/substyle/-/substyle-9.4.1.tgz", + "integrity": "sha512-VOngeq/W1/UkxiGzeqVvDbGDPM8XgUyJVWjrqeh+GgKqspEPiLYndK+XRcsKUHM5Muz/++1ctJ1QCF/OqRiKWA==", + "dependencies": { + "@babel/runtime": "^7.3.4", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": ">=16.8.3" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/reminder-dashboard/package.json b/reminder-dashboard/package.json index 1169d98..9ff1aea 100644 --- a/reminder-dashboard/package.json +++ b/reminder-dashboard/package.json @@ -5,8 +5,7 @@ "scripts": { "dev": "vite build --watch --mode development", "build": "vite build", - "preview": "vite preview", - "package": "mkdir -p reminder-dashboard/usr/share/reminder-dashboard && vite build --mode production --outDir reminder-dashboard/usr/share/reminder-dashboard && dpkg-deb --build reminder-dashboard" + "preview": "vite preview" }, "dependencies": { "axios": "^1.5.1", diff --git a/reminder-dashboard/src/components/App/useGuild.tsx b/reminder-dashboard/src/components/App/useGuild.tsx new file mode 100644 index 0000000..5be8de0 --- /dev/null +++ b/reminder-dashboard/src/components/App/useGuild.tsx @@ -0,0 +1,6 @@ +import { useParams } from "wouter"; + +export const useGuild = () => { + const { guild } = useParams() as { guild: string }; + return guild; +}; diff --git a/reminder-dashboard/src/components/App/useMentions.tsx b/reminder-dashboard/src/components/App/useMentions.tsx new file mode 100644 index 0000000..855148d --- /dev/null +++ b/reminder-dashboard/src/components/App/useMentions.tsx @@ -0,0 +1,28 @@ +import { useEffect, useMemo } from "preact/hooks"; +import { useQuery } from "react-query"; +import { fetchGuildRoles } from "../../api"; +import Tribute from "tributejs"; +import { useGuild } from "./useGuild"; + +export const useMentions = (input) => { + const guild = useGuild(); + + const { data: roles } = useQuery(fetchGuildRoles(guild)); + + const tribute = useMemo(() => { + return new Tribute({ + values: (roles || []).map(({ id, name }) => ({ key: name, value: id })), + allowSpaces: true, + selectTemplate: (item) => { + return `<@&${item.original.value}>`; + }, + }); + }, [roles]); + + useEffect(() => { + tribute.detach(input.current); + if (input.current !== null) { + tribute.attach(input.current); + } + }, [tribute]); +}; diff --git a/reminder-dashboard/src/components/Reminder/Content.tsx b/reminder-dashboard/src/components/Reminder/Content.tsx index 81d4832..3e9d6c9 100644 --- a/reminder-dashboard/src/components/Reminder/Content.tsx +++ b/reminder-dashboard/src/components/Reminder/Content.tsx @@ -1,8 +1,13 @@ import { useReminder } from "./ReminderContext"; +import { useRef } from "preact/hooks"; +import { useMentions } from "../App/useMentions"; export const Content = () => { const [reminder, setReminder] = useReminder(); + const input = useRef(null); + useMentions(input); + return ( <> @@ -12,6 +17,7 @@ export const Content = () => { maxlength={2000} name="content" rows={1} + ref={input} value={reminder.content} onInput={(ev) => { setReminder((reminder) => ({ diff --git a/reminder-dashboard/src/components/Reminder/Embed/Author.tsx b/reminder-dashboard/src/components/Reminder/Embed/Author.tsx index 04fc422..b2b448a 100644 --- a/reminder-dashboard/src/components/Reminder/Embed/Author.tsx +++ b/reminder-dashboard/src/components/Reminder/Embed/Author.tsx @@ -1,5 +1,7 @@ import { ImagePicker } from "../ImagePicker"; import { Reminder } from "../../../api"; +import { useMentions } from "../../App/useMentions"; +import { useRef } from "preact/hooks"; type Props = { name: string; @@ -8,6 +10,9 @@ type Props = { }; export const Author = ({ name, icon, setReminder }: Props) => { + const input = useRef(null); + useMentions(input); + return (