diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index 405431059..3d7236286 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -43,6 +43,7 @@ export { default as PostTooltip } from '../src/javascripts/post_tooltips.js';
export { default as PostVersion } from '../src/javascripts/post_version.js';
export { default as RelatedTag } from '../src/javascripts/related_tag.js';
export { default as Shortcuts } from '../src/javascripts/shortcuts.js';
+export { default as TagCounter } from '../src/javascripts/tag_counter.js';
export { default as Upload } from '../src/javascripts/uploads.js.erb';
export { default as UserTooltip } from '../src/javascripts/user_tooltips.js';
export { default as Utility } from '../src/javascripts/utility.js';
diff --git a/app/javascript/src/javascripts/posts.js.erb b/app/javascript/src/javascripts/posts.js.erb
index 3ed6c68ed..c85b9c6dc 100644
--- a/app/javascript/src/javascripts/posts.js.erb
+++ b/app/javascript/src/javascripts/posts.js.erb
@@ -42,8 +42,6 @@ Post.initialize_all = function() {
}
var $fields_multiple = $('[data-autocomplete="tag-edit"]');
- $fields_multiple.on("keypress.danbooru", Post.update_tag_count);
- $fields_multiple.on("click", Post.update_tag_count);
$(window).on('danbooru:initialize_saved_seraches', () => {
Post.initialize_saved_searches();
@@ -402,7 +400,6 @@ Post.initialize_post_sections = function() {
$("#post_tag_string").focus().selectEnd().height($("#post_tag_string")[0].scrollHeight);
$("#recommended").hide();
$(document).trigger("danbooru:open-post-edit-tab");
- Post.update_tag_count({target: $("#post_tag_string")});
} else if (e.target.hash === "#recommended") {
$("#comments").hide();
$("#edit").hide();
@@ -513,32 +510,6 @@ Post.initialize_recommended = function() {
});
};
-Post.update_tag_count = function(event) {
- let string = "0 tags";
- let count = 0;
-
- if (event) {
- let tags = Utility.regexp_split($(event.target).val());
- if (tags.length) {
- count = tags.length;
- string = (count === 1) ? (count + " tag") : (count + " tags")
- }
- }
-
- $("#tags-container .count").html(string);
- let klass = "";
-
- if (count < Post.LOW_TAG_COUNT) {
- klass = "frown";
- } else if (count >= Post.LOW_TAG_COUNT && count < Post.HIGH_TAG_COUNT) {
- klass = "meh";
- } else {
- klass = "smile";
- }
-
- $("#tags-container .options #face").removeClass().addClass(`far fa-${klass}`);
-}
-
$(document).ready(function() {
Post.initialize_all();
});
diff --git a/app/javascript/src/javascripts/tag_counter.js b/app/javascript/src/javascripts/tag_counter.js
new file mode 100644
index 000000000..3aa537cf7
--- /dev/null
+++ b/app/javascript/src/javascripts/tag_counter.js
@@ -0,0 +1,49 @@
+import { h, Component, render } from "preact";
+import { observable, computed, action } from "mobx";
+import { observer } from "mobx-react";
+
+import Utility from "./utility";
+
+export default @observer class TagCounter extends Component {
+ static lowCount = 10;
+ static highCount = 20;
+
+ @observable tagCount = 0;
+
+ componentDidMount() {
+ $(this.props.tags).on("input", this.updateCount);
+ this.updateCount();
+ }
+
+ render() {
+ return (
+
+ {this.tagCount} / {TagCounter.highCount} tags
+
+
+ );
+ }
+
+ @action.bound updateCount() {
+ this.tagCount = Utility.regexp_split($(this.props.tags).val()).length;
+ }
+
+ @computed get emoji() {
+ if (this.tagCount < TagCounter.lowCount) {
+ return "frown";
+ } else if (this.tagCount >= TagCounter.lowCount && this.tagCount < TagCounter.highCount) {
+ return "meh";
+ } else {
+ return "smile";
+ }
+ }
+
+ static initialize() {
+ $("[data-tag-counter]").toArray().forEach(element => {
+ let target = $($(element).attr("data-for")).get(0);
+ render(h(TagCounter, { tags: target }), element);
+ });
+ }
+}
+
+$(TagCounter.initialize);
diff --git a/app/views/posts/partials/show/_edit.html.erb b/app/views/posts/partials/show/_edit.html.erb
index 93a07e9d6..6df702965 100644
--- a/app/views/posts/partials/show/_edit.html.erb
+++ b/app/views/posts/partials/show/_edit.html.erb
@@ -50,8 +50,7 @@
<%= f.label :tag_string, "Tags" %>
-
-
+
diff --git a/app/views/uploads/new.html.erb b/app/views/uploads/new.html.erb
index c34bdaf92..8bc5b0fc1 100644
--- a/app/views/uploads/new.html.erb
+++ b/app/views/uploads/new.html.erb
@@ -66,8 +66,7 @@
<%= f.label :tag_string, "Tags" %>
-
-
+
diff --git a/babel.config.js b/babel.config.js
index 12f98da5a..2f5c9da10 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -41,6 +41,13 @@ module.exports = function(api) {
'@babel/plugin-syntax-dynamic-import',
isTestEnv && 'babel-plugin-dynamic-import-node',
'@babel/plugin-transform-destructuring',
+ ["@babel/plugin-proposal-decorators", {
+ legacy: true
+ }],
+ ["@babel/plugin-transform-react-jsx", {
+ pragma: "h",
+ pragmaFrag: "Fragment",
+ }],
[
'@babel/plugin-proposal-class-properties',
{
diff --git a/config/webpack/environment.js b/config/webpack/environment.js
index 607382c5e..1cb4e0d86 100644
--- a/config/webpack/environment.js
+++ b/config/webpack/environment.js
@@ -7,7 +7,9 @@ environment.loaders.append('erb', erb);
environment.config.output.library = ["Danbooru"];
environment.config.set("resolve.alias", {
- "jquery": "jquery/src/jquery.js"
+ "jquery": "jquery/src/jquery.js",
+ "react": "preact/compat",
+ "react-dom": "preact/compat",
});
module.exports = environment
diff --git a/package.json b/package.json
index 66940300e..c396790fb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,8 @@
{
"license": "MIT",
"dependencies": {
+ "@babel/plugin-proposal-decorators": "^7.10.5",
+ "@babel/plugin-transform-react-jsx": "^7.10.4",
"@fortawesome/fontawesome-free": "^5.11.2",
"@rails/ujs": "^6.0.2-1",
"@rails/webpacker": "^5.0.0",
@@ -9,6 +11,9 @@
"jquery": "3.5.1",
"jquery-hotkeys": "^0.2.2",
"jquery-ui": "^1.12.1",
+ "mobx": "^5.15.4",
+ "mobx-react": "^6.2.5",
+ "preact": "^10.4.6",
"rails-erb-loader": "^5.5.0",
"spark-md5": "^3.0.0",
"tippy.js": "^6.2.3",
diff --git a/yarn.lock b/yarn.lock
index 3a219010c..925a17179 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -65,6 +65,23 @@
"@babel/helper-explode-assignable-expression" "^7.10.4"
"@babel/types" "^7.10.4"
+"@babel/helper-builder-react-jsx-experimental@^7.10.4":
+ version "7.10.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.10.5.tgz#f35e956a19955ff08c1258e44a515a6d6248646b"
+ integrity sha512-Buewnx6M4ttG+NLkKyt7baQn7ScC/Td+e99G914fRU8fGIUivDDgVIQeDHFa5e4CRSJQt58WpNHhsAZgtzVhsg==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.10.4"
+ "@babel/helper-module-imports" "^7.10.4"
+ "@babel/types" "^7.10.5"
+
+"@babel/helper-builder-react-jsx@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz#8095cddbff858e6fa9c326daee54a2f2732c1d5d"
+ integrity sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.10.4"
+ "@babel/types" "^7.10.4"
+
"@babel/helper-compilation-targets@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2"
@@ -88,6 +105,18 @@
"@babel/helper-replace-supers" "^7.10.4"
"@babel/helper-split-export-declaration" "^7.10.4"
+"@babel/helper-create-class-features-plugin@^7.10.5":
+ version "7.10.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d"
+ integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==
+ dependencies:
+ "@babel/helper-function-name" "^7.10.4"
+ "@babel/helper-member-expression-to-functions" "^7.10.5"
+ "@babel/helper-optimise-call-expression" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-replace-supers" "^7.10.4"
+ "@babel/helper-split-export-declaration" "^7.10.4"
+
"@babel/helper-create-regexp-features-plugin@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8"
@@ -144,6 +173,13 @@
dependencies:
"@babel/types" "^7.10.4"
+"@babel/helper-member-expression-to-functions@^7.10.5":
+ version "7.11.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df"
+ integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==
+ dependencies:
+ "@babel/types" "^7.11.0"
+
"@babel/helper-module-imports@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
@@ -274,6 +310,15 @@
"@babel/helper-create-class-features-plugin" "^7.10.4"
"@babel/helper-plugin-utils" "^7.10.4"
+"@babel/plugin-proposal-decorators@^7.10.5":
+ version "7.10.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.5.tgz#42898bba478bc4b1ae242a703a953a7ad350ffb4"
+ integrity sha512-Sc5TAQSZuLzgY0664mMDn24Vw2P8g/VhyLyGPaWiHahhgLqeZvcGeyBZOrJW0oSKIK2mvQ22a1ENXBIQLhrEiQ==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.10.5"
+ "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/plugin-syntax-decorators" "^7.10.4"
+
"@babel/plugin-proposal-dynamic-import@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e"
@@ -361,6 +406,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
+"@babel/plugin-syntax-decorators@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.4.tgz#6853085b2c429f9d322d02f5a635018cdeb2360c"
+ integrity sha512-2NaoC6fAk2VMdhY1eerkfHV+lVYC1u8b+jmRJISqANCJlTxYy19HGdIkkQtix2UtkcPuPu+IlDgrVseZnU03bw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
"@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
@@ -375,6 +427,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
+"@babel/plugin-syntax-jsx@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.4.tgz#39abaae3cbf710c4373d8429484e6ba21340166c"
+ integrity sha512-KCg9mio9jwiARCB7WAcQ7Y1q+qicILjoK8LP/VkPkEKaf5dkaZZK1EcTe91a3JJlZ3qy6L5s9X52boEYi8DM9g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
@@ -602,6 +661,16 @@
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
+"@babel/plugin-transform-react-jsx@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.10.4.tgz#673c9f913948764a4421683b2bef2936968fddf2"
+ integrity sha512-L+MfRhWjX0eI7Js093MM6MacKU4M6dnCRa/QPDwYMxjljzSCzzlzKzj9Pk4P3OtrPcxr2N3znR419nr3Xw+65A==
+ dependencies:
+ "@babel/helper-builder-react-jsx" "^7.10.4"
+ "@babel/helper-builder-react-jsx-experimental" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/plugin-syntax-jsx" "^7.10.4"
+
"@babel/plugin-transform-regenerator@^7.10.4", "@babel/plugin-transform-regenerator@^7.8.7":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63"
@@ -799,6 +868,15 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
+"@babel/types@^7.10.5", "@babel/types@^7.11.0":
+ version "7.11.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d"
+ integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.10.4"
+ lodash "^4.17.19"
+ to-fast-properties "^2.0.0"
+
"@csstools/convert-colors@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
@@ -4969,7 +5047,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@~4.17.10:
+lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.5, lodash@~4.17.10:
version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
@@ -5374,6 +5452,23 @@ mixin-deep@^1.2.0:
dependencies:
minimist "^1.2.5"
+mobx-react-lite@>=2.0.6:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-2.0.7.tgz#1bfb3b4272668e288047cf0c7940b14e91cba284"
+ integrity sha512-YKAh2gThC6WooPnVZCoC+rV1bODAKFwkhxikzgH18wpBjkgTkkR9Sb0IesQAH5QrAEH/JQVmy47jcpQkf2Au3Q==
+
+mobx-react@^6.2.5:
+ version "6.2.5"
+ resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.2.5.tgz#9020a17b79cc6dc3d124ad89ab36eb9ea540a45b"
+ integrity sha512-LxtXXW0GkOAO6VOIg2m/6WL6ZuKlzOWwESIFdrWelI0ZMIvtKCMZVUuulcO5GAWSDsH0ApaMkGLoaPqKjzyziQ==
+ dependencies:
+ mobx-react-lite ">=2.0.6"
+
+mobx@^5.15.4:
+ version "5.15.4"
+ resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.15.4.tgz#9da1a84e97ba624622f4e55a0bf3300fb931c2ab"
+ integrity sha512-xRFJxSU2Im3nrGCdjSuOTFmxVDGeqOHL+TyADCGbT0k4HHqGmx5u2yaHNryvoORpI4DfbzjJ5jPmuv+d7sioFw==
+
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -6851,6 +6946,11 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.1
source-map "^0.6.1"
supports-color "^6.1.0"
+preact@^10.4.6:
+ version "10.4.6"
+ resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.6.tgz#86cc43396e4bdd755726a2b4b1f0529e78067cd3"
+ integrity sha512-80WJfXH53yyINig5Wza/8MD9n4lMg9G6aN00ws0ptsAaY/Fu/M7xW4zICf7OLfocVltxS30wvNQ8oIbUyZS1tw==
+
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"