diff options
Diffstat (limited to 'web/source/settings/admin/emoji/new-emoji.js')
-rw-r--r-- | web/source/settings/admin/emoji/new-emoji.js | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/web/source/settings/admin/emoji/new-emoji.js b/web/source/settings/admin/emoji/new-emoji.js index e5bc8893d..65dc52132 100644 --- a/web/source/settings/admin/emoji/new-emoji.js +++ b/web/source/settings/admin/emoji/new-emoji.js @@ -20,30 +20,34 @@ const Promise = require('bluebird'); const React = require("react"); +const { matchSorter } = require("match-sorter"); const FakeToot = require("../../components/fake-toot"); const MutateButton = require("../../components/mutation-button"); +const ComboBox = require("../../components/combo-box"); -const { +const { useTextInput, - useFileInput + useFileInput, + useComboBoxInput } = require("../../components/form"); const query = require("../../lib/query"); +const syncpipe = require('syncpipe'); -module.exports = function NewEmojiForm({emoji}) { +module.exports = function NewEmojiForm({ emoji, emojiByCategory }) { const emojiCodes = React.useMemo(() => { return new Set(emoji.map((e) => e.shortcode)); }, [emoji]); const [addEmoji, result] = query.useAddEmojiMutation(); - const [onFileChange, resetFile, {image, imageURL, imageInfo}] = useFileInput("image", { + const [onFileChange, resetFile, { image, imageURL, imageInfo }] = useFileInput("image", { withPreview: true, maxSize: 50 * 1024 }); - const [onShortcodeChange, resetShortcode, {shortcode, setShortcode, shortcodeRef}] = useTextInput("shortcode", { + const [onShortcodeChange, resetShortcode, { shortcode, setShortcode, shortcodeRef }] = useTextInput("shortcode", { validator: function validateShortcode(code) { return emojiCodes.has(code) ? "Shortcode already in use" @@ -51,6 +55,23 @@ module.exports = function NewEmojiForm({emoji}) { } }); + const [categoryState, resetCategory, { category }] = useComboBoxInput("category"); + + // data used by the ComboBox element to select an emoji category + const categoryItems = React.useMemo(() => { + return syncpipe(emojiByCategory, [ + (_) => Object.keys(_), // just emoji category names + (_) => matchSorter(_, category), // sorted by complex algorithm + (_) => _.map((categoryName) => [ // map to input value, and selectable element with icon + categoryName, + <> + <img src={emojiByCategory[categoryName][0].static_url} aria-hidden="true"></img> + {categoryName} + </> + ]) + ]); + }, [emojiByCategory, category]); + React.useEffect(() => { if (shortcode.length == 0) { if (image != undefined) { @@ -58,6 +79,9 @@ module.exports = function NewEmojiForm({emoji}) { setShortcode(name); } } + // we explicitly don't want to add 'shortcode' as a dependency here + // because we only want this to update to the filename if the field is empty + // at the moment the file is selected, not some time after when the field is emptied // eslint-disable-next-line react-hooks/exhaustive-deps }, [image]); @@ -69,11 +93,13 @@ module.exports = function NewEmojiForm({emoji}) { Promise.try(() => { return addEmoji({ image, - shortcode + shortcode, + category }); }).then(() => { resetFile(); resetShortcode(); + resetCategory(); }); } @@ -125,8 +151,15 @@ module.exports = function NewEmojiForm({emoji}) { value={shortcode} /> </div> - - <MutateButton text="Upload emoji" result={result}/> + + <ComboBox + state={categoryState} + items={categoryItems} + label="Category" + placeHolder="e.g., reactions" + /> + + <MutateButton text="Upload emoji" result={result} /> </form> </div> ); |