summaryrefslogtreecommitdiff
path: root/web/source/settings/admin/emoji/local
diff options
context:
space:
mode:
Diffstat (limited to 'web/source/settings/admin/emoji/local')
-rw-r--r--web/source/settings/admin/emoji/local/detail.js146
-rw-r--r--web/source/settings/admin/emoji/local/index.tsx35
-rw-r--r--web/source/settings/admin/emoji/local/new-emoji.tsx116
-rw-r--r--web/source/settings/admin/emoji/local/overview.js153
-rw-r--r--web/source/settings/admin/emoji/local/use-shortcode.js56
5 files changed, 0 insertions, 506 deletions
diff --git a/web/source/settings/admin/emoji/local/detail.js b/web/source/settings/admin/emoji/local/detail.js
deleted file mode 100644
index a78e3e499..000000000
--- a/web/source/settings/admin/emoji/local/detail.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- GoToSocial
- Copyright (C) GoToSocial Authors admin@gotosocial.org
- SPDX-License-Identifier: AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React, { useEffect } from "react";
-import { useRoute, Link, Redirect } from "wouter";
-
-import { useComboBoxInput, useFileInput, useValue } from "../../../lib/form";
-import { CategorySelect } from "../category-select";
-
-import useFormSubmit from "../../../lib/form/submit";
-import { useBaseUrl } from "../../../lib/navigation/util";
-
-import FakeToot from "../../../components/fake-toot";
-import FormWithData from "../../../lib/form/form-with-data";
-import Loading from "../../../components/loading";
-import { FileInput } from "../../../components/form/inputs";
-import MutationButton from "../../../components/form/mutation-button";
-import { Error } from "../../../components/error";
-
-import { useGetEmojiQuery, useEditEmojiMutation, useDeleteEmojiMutation } from "../../../lib/query/admin/custom-emoji";
-
-export default function EmojiDetailRoute({ }) {
- const baseUrl = useBaseUrl();
- let [_match, params] = useRoute(`${baseUrl}/:emojiId`);
- if (params?.emojiId == undefined) {
- return <Redirect to={baseUrl} />;
- } else {
- return (
- <div className="emoji-detail">
- <Link to={baseUrl}><a>&lt; go back</a></Link>
- <FormWithData dataQuery={useGetEmojiQuery} queryArg={params.emojiId} DataForm={EmojiDetailForm} />
- </div>
- );
- }
-}
-
-function EmojiDetailForm({ data: emoji }) {
- const baseUrl = useBaseUrl();
- const form = {
- id: useValue("id", emoji.id),
- category: useComboBoxInput("category", { source: emoji }),
- image: useFileInput("image", {
- withPreview: true,
- maxSize: 50 * 1024 // TODO: get from instance api
- })
- };
-
- const [modifyEmoji, result] = useFormSubmit(form, useEditEmojiMutation());
-
- // Automatic submitting of category change
- useEffect(() => {
- if (
- form.category.hasChanged() &&
- !form.category.state.open &&
- !form.category.isNew) {
- modifyEmoji();
- }
- /* eslint-disable-next-line react-hooks/exhaustive-deps */
- }, [form.category.hasChanged(), form.category.isNew, form.category.state.open]);
-
- const [deleteEmoji, deleteResult] = useDeleteEmojiMutation();
-
- if (deleteResult.isSuccess) {
- return <Redirect to={baseUrl} />;
- }
-
- return (
- <>
- <div className="emoji-header">
- <img src={emoji.url} alt={emoji.shortcode} title={emoji.shortcode} />
- <div>
- <h2>{emoji.shortcode}</h2>
- <MutationButton
- label="Delete"
- type="button"
- onClick={() => deleteEmoji(emoji.id)}
- className="danger"
- showError={false}
- result={deleteResult}
- />
- </div>
- </div>
-
- <form onSubmit={modifyEmoji} className="left-border">
- <h2>Modify this emoji {result.isLoading && <Loading />}</h2>
-
- <div className="update-category">
- <CategorySelect
- field={form.category}
- >
- <MutationButton
- name="create-category"
- label="Create"
- result={result}
- showError={false}
- style={{ visibility: (form.category.isNew ? "initial" : "hidden") }}
- />
- </CategorySelect>
- </div>
-
- <div className="update-image">
- <FileInput
- field={form.image}
- label="Image"
- accept="image/png,image/gif"
- />
-
- <MutationButton
- name="image"
- label="Replace image"
- showError={false}
- result={result}
- />
-
- <FakeToot>
- Look at this new custom emoji <img
- className="emoji"
- src={form.image.previewURL ?? emoji.url}
- title={`:${emoji.shortcode}:`}
- alt={emoji.shortcode}
- /> isn&apos;t it cool?
- </FakeToot>
-
- {result.error && <Error error={result.error} />}
- {deleteResult.error && <Error error={deleteResult.error} />}
- </div>
- </form>
- </>
- );
-} \ No newline at end of file
diff --git a/web/source/settings/admin/emoji/local/index.tsx b/web/source/settings/admin/emoji/local/index.tsx
deleted file mode 100644
index 74a891f3e..000000000
--- a/web/source/settings/admin/emoji/local/index.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- GoToSocial
- Copyright (C) GoToSocial Authors admin@gotosocial.org
- SPDX-License-Identifier: AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from "react";
-import { Switch, Route } from "wouter";
-
-import EmojiOverview from "./overview";
-import EmojiDetail from "./detail";
-
-export default function CustomEmoji({ baseUrl }) {
- return (
- <Switch>
- <Route path={`${baseUrl}/:emojiId`}>
- <EmojiDetail />
- </Route>
- <EmojiOverview />
- </Switch>
- );
-}
diff --git a/web/source/settings/admin/emoji/local/new-emoji.tsx b/web/source/settings/admin/emoji/local/new-emoji.tsx
deleted file mode 100644
index c6a203765..000000000
--- a/web/source/settings/admin/emoji/local/new-emoji.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- GoToSocial
- Copyright (C) GoToSocial Authors admin@gotosocial.org
- SPDX-License-Identifier: AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React, { useMemo, useEffect } from "react";
-
-import { useFileInput, useComboBoxInput } from "../../../lib/form";
-import useShortcode from "./use-shortcode";
-
-import useFormSubmit from "../../../lib/form/submit";
-
-import { TextInput, FileInput } from "../../../components/form/inputs";
-
-import { CategorySelect } from '../category-select';
-import FakeToot from "../../../components/fake-toot";
-import MutationButton from "../../../components/form/mutation-button";
-import { useAddEmojiMutation } from "../../../lib/query/admin/custom-emoji";
-import { useInstanceV1Query } from "../../../lib/query";
-
-export default function NewEmojiForm() {
- const shortcode = useShortcode();
-
- const { data: instance } = useInstanceV1Query();
- const emojiMaxSize = useMemo(() => {
- return instance?.configuration?.emojis?.emoji_size_limit ?? 50 * 1024;
- }, [instance]);
-
- const image = useFileInput("image", {
- withPreview: true,
- maxSize: emojiMaxSize
- });
-
- const category = useComboBoxInput("category");
-
- const [submitForm, result] = useFormSubmit({
- shortcode, image, category
- }, useAddEmojiMutation());
-
- useEffect(() => {
- if (shortcode.value === undefined || shortcode.value.length == 0) {
- if (image.value != undefined) {
- let [name, _ext] = image.value.name.split(".");
- shortcode.setter(name);
- }
- }
-
- /* We explicitly don't want to have 'shortcode' as a dependency here
- because we only want to change the shortcode 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.value]);
-
- let emojiOrShortcode;
-
- if (image.previewValue != undefined) {
- emojiOrShortcode = <img
- className="emoji"
- src={image.previewValue}
- title={`:${shortcode.value}:`}
- alt={shortcode.value}
- />;
- } else if (shortcode.value !== undefined && shortcode.value.length > 0) {
- emojiOrShortcode = `:${shortcode.value}:`;
- } else {
- emojiOrShortcode = `:your_emoji_here:`;
- }
-
- return (
- <div>
- <h2>Add new custom emoji</h2>
-
- <FakeToot>
- Look at this new custom emoji {emojiOrShortcode} isn&apos;t it cool?
- </FakeToot>
-
- <form onSubmit={submitForm} className="form-flex">
- <FileInput
- field={image}
- accept="image/png,image/gif,image/webp"
- />
-
- <TextInput
- field={shortcode}
- label="Shortcode, must be unique among the instance's local emoji"
- />
-
- <CategorySelect
- field={category}
- children={[]}
- />
-
- <MutationButton
- disabled={image.previewValue === undefined}
- label="Upload emoji"
- result={result}
- />
- </form>
- </div>
- );
-} \ No newline at end of file
diff --git a/web/source/settings/admin/emoji/local/overview.js b/web/source/settings/admin/emoji/local/overview.js
deleted file mode 100644
index 45bfd614d..000000000
--- a/web/source/settings/admin/emoji/local/overview.js
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- GoToSocial
- Copyright (C) GoToSocial Authors admin@gotosocial.org
- SPDX-License-Identifier: AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-const React = require("react");
-const { Link } = require("wouter");
-const syncpipe = require("syncpipe");
-const { matchSorter } = require("match-sorter");
-
-const NewEmojiForm = require("./new-emoji").default;
-const { useTextInput } = require("../../../lib/form");
-
-const { useEmojiByCategory } = require("../category-select");
-const { useBaseUrl } = require("../../../lib/navigation/util");
-
-const Loading = require("../../../components/loading");
-const { Error } = require("../../../components/error");
-const { TextInput } = require("../../../components/form/inputs");
-const { useListEmojiQuery } = require("../../../lib/query/admin/custom-emoji");
-
-module.exports = function EmojiOverview({ }) {
- const {
- data: emoji = [],
- isLoading,
- isError,
- error
- } = useListEmojiQuery({ filter: "domain:local" });
-
- let content = null;
-
- if (isLoading) {
- content = <Loading />;
- } else if (isError) {
- content = <Error error={error} />;
- } else {
- content = (
- <>
- <EmojiList emoji={emoji} />
- <NewEmojiForm emoji={emoji} />
- </>
- );
- }
-
- return (
- <>
- <h1>Local Custom Emoji</h1>
- <p>
- To use custom emoji in your toots they have to be 'local' to the instance.
- You can either upload them here directly, or copy from those already
- present on other (known) instances through the <Link to={`./remote`}>Remote Emoji</Link> page.
- </p>
- <p>
- <strong>Be warned!</strong> If you upload more than about 300-400 custom emojis in
- total on your instance, this may lead to rate-limiting issues for users and clients
- if they try to load all the emoji images at once (which is what many clients do).
- </p>
- {content}
- </>
- );
-};
-
-function EmojiList({ emoji }) {
- const filterField = useTextInput("filter");
- const filter = filterField.value;
-
- const emojiByCategory = useEmojiByCategory(emoji);
-
- /* Filter emoji based on shortcode match with user input, hiding empty categories */
- const { filteredEmoji, hidden } = React.useMemo(() => {
- let hidden = emoji.length;
- const filteredEmoji = syncpipe(emojiByCategory, [
- (_) => Object.entries(emojiByCategory),
- (_) => _.map(([category, entries]) => {
- let filteredEntries = matchSorter(entries, filter, { keys: ["shortcode"] });
- if (filteredEntries.length == 0) {
- return null;
- } else {
- hidden -= filteredEntries.length;
- return [category, filteredEntries];
- }
- }),
- (_) => _.filter((value) => value !== null)
- ]);
-
- return { filteredEmoji, hidden };
- }, [filter, emojiByCategory, emoji.length]);
-
- return (
- <div>
- <h2>Overview</h2>
- {emoji.length > 0
- ? <span>{emoji.length} custom emoji {hidden > 0 && `(${hidden} filtered)`}</span>
- : <span>No custom emoji yet, you can add one below.</span>
- }
- <div className="list emoji-list">
- <div className="header">
- <TextInput
- field={filterField}
- name="emoji-shortcode"
- placeholder="Search"
- />
- </div>
- <div className="entries scrolling">
- {filteredEmoji.length > 0
- ? (
- <div className="entries scrolling">
- {filteredEmoji.map(([category, entries]) => {
- return <EmojiCategory key={category} category={category} entries={entries} />;
- })}
- </div>
- )
- : <div className="entry">No local emoji matched your filter.</div>
- }
- </div>
- </div>
- </div>
- );
-}
-
-function EmojiCategory({ category, entries }) {
- const baseUrl = useBaseUrl();
- return (
- <div className="entry">
- <b>{category}</b>
- <div className="emoji-group">
- {entries.map((e) => {
- return (
- <Link key={e.id} to={`${baseUrl}/${e.id}`}>
- <a>
- <img src={e.url} alt={e.shortcode} title={`:${e.shortcode}:`} />
- </a>
- </Link>
- );
- })}
- </div>
- </div>
- );
-} \ No newline at end of file
diff --git a/web/source/settings/admin/emoji/local/use-shortcode.js b/web/source/settings/admin/emoji/local/use-shortcode.js
deleted file mode 100644
index 67255860f..000000000
--- a/web/source/settings/admin/emoji/local/use-shortcode.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- GoToSocial
- Copyright (C) GoToSocial Authors admin@gotosocial.org
- SPDX-License-Identifier: AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-const React = require("react");
-
-const { useTextInput } = require("../../../lib/form");
-const { useListEmojiQuery } = require("../../../lib/query/admin/custom-emoji");
-
-const shortcodeRegex = /^\w{2,30}$/;
-
-module.exports = function useShortcode() {
- const { data: emoji = [] } = useListEmojiQuery({
- filter: "domain:local"
- });
-
- const emojiCodes = React.useMemo(() => {
- return new Set(emoji.map((e) => e.shortcode));
- }, [emoji]);
-
- return useTextInput("shortcode", {
- validator: function validateShortcode(code) {
- // technically invalid, but hacky fix to prevent validation error on page load
- if (code == "") { return ""; }
-
- if (emojiCodes.has(code)) {
- return "Shortcode already in use";
- }
-
- if (code.length < 2 || code.length > 30) {
- return "Shortcode must be between 2 and 30 characters";
- }
-
- if (!shortcodeRegex.test(code)) {
- return "Shortcode must only contain letters, numbers, and underscores";
- }
-
- return "";
- }
- });
-}; \ No newline at end of file