aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-09-03 18:10:02 +0800
committercrupest <crupest@outlook.com>2020-09-03 18:10:02 +0800
commit70be5235ba90a15b7798a7922382835fd680b1fc (patch)
tree9f1ed076ecb0b7ef884b8cd8aa5c7e7497cb6376
parentb06cd597488b2d1c12ef9e35b25bdba6a9d4b11e (diff)
downloadtimeline-70be5235ba90a15b7798a7922382835fd680b1fc.tar.gz
timeline-70be5235ba90a15b7798a7922382835fd680b1fc.tar.bz2
timeline-70be5235ba90a15b7798a7922382835fd680b1fc.zip
Migrate to react-bootstrap.
-rw-r--r--Timeline/ClientApp/.pnp.js132
-rw-r--r--Timeline/ClientApp/package.json2
-rw-r--r--Timeline/ClientApp/src/app/service-worker.tsx10
-rw-r--r--Timeline/ClientApp/src/app/views/about/index.tsx4
-rw-r--r--Timeline/ClientApp/src/app/views/admin/Admin.tsx25
-rw-r--r--Timeline/ClientApp/src/app/views/admin/UserAdmin.tsx47
-rw-r--r--Timeline/ClientApp/src/app/views/common/AppBar.tsx2
-rw-r--r--Timeline/ClientApp/src/app/views/common/FileInput.tsx36
-rw-r--r--Timeline/ClientApp/src/app/views/common/OperationDialog.tsx93
-rw-r--r--Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx9
-rw-r--r--Timeline/ClientApp/src/app/views/login/index.tsx53
-rw-r--r--Timeline/ClientApp/src/app/views/timeline-common/TimelineItem.tsx28
-rw-r--r--Timeline/ClientApp/src/app/views/timeline-common/TimelineMember.tsx22
-rw-r--r--Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplate.tsx6
-rw-r--r--Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx18
-rw-r--r--Timeline/ClientApp/src/app/views/timeline-common/TimelinePostEdit.tsx23
-rw-r--r--Timeline/ClientApp/src/app/views/timeline-common/timeline-common.sass25
-rw-r--r--Timeline/ClientApp/src/app/views/timeline/TimelineInfoCard.tsx46
-rw-r--r--Timeline/ClientApp/src/app/views/timeline/timeline.sass14
-rw-r--r--Timeline/ClientApp/src/app/views/user/ChangeAvatarDialog.tsx93
-rw-r--r--Timeline/ClientApp/src/app/views/user/UserInfoCard.tsx48
-rw-r--r--Timeline/ClientApp/yarn.lock113
22 files changed, 252 insertions, 597 deletions
diff --git a/Timeline/ClientApp/.pnp.js b/Timeline/ClientApp/.pnp.js
index 51c7e7ae..fbd1b188 100644
--- a/Timeline/ClientApp/.pnp.js
+++ b/Timeline/ClientApp/.pnp.js
@@ -110,10 +110,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"npm:5.1.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact-router-dom%2Fdownload%2F%40types%2Freact-router-dom-5.1.5.tgz"
],
[
- "@types/reactstrap",
- "npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freactstrap%2Fdownload%2F%40types%2Freactstrap-8.5.1.tgz"
- ],
- [
"@types/webpack-env",
"npm:1.15.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fwebpack-env%2Fdownload%2F%40types%2Fwebpack-env-1.15.2.tgz"
],
@@ -302,10 +298,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:5.2.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-router-dom%2Fdownload%2Freact-router-dom-5.2.0.tgz"
],
[
- "reactstrap",
- "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freactstrap%2Fdownload%2Freactstrap-8.5.1.tgz"
- ],
- [
"regenerator-runtime",
"npm:0.13.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.7.tgz"
],
@@ -405,7 +397,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@types/react-router", "npm:5.1.8::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact-router%2Fdownload%2F%40types%2Freact-router-5.1.8.tgz"],
["@types/react-router-bootstrap", "npm:0.24.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact-router-bootstrap%2Fdownload%2F%40types%2Freact-router-bootstrap-0.24.5.tgz"],
["@types/react-router-dom", "npm:5.1.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact-router-dom%2Fdownload%2F%40types%2Freact-router-dom-5.1.5.tgz"],
- ["@types/reactstrap", "npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freactstrap%2Fdownload%2F%40types%2Freactstrap-8.5.1.tgz"],
["@types/webpack-env", "npm:1.15.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fwebpack-env%2Fdownload%2F%40types%2Fwebpack-env-1.15.2.tgz"],
["@types/xregexp", "npm:4.3.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fxregexp%2Fdownload%2F%40types%2Fxregexp-4.3.0.tgz"],
["@typescript-eslint/eslint-plugin", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:3.10.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40typescript-eslint%2Feslint-plugin%2Fdownload%2F%40typescript-eslint%2Feslint-plugin-3.10.1.tgz"],
@@ -453,7 +444,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["react-router", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:5.2.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-router%2Fdownload%2Freact-router-5.2.0.tgz"],
["react-router-bootstrap", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:0.25.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-router-bootstrap%2Fdownload%2Freact-router-bootstrap-0.25.0.tgz"],
["react-router-dom", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:5.2.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-router-dom%2Fdownload%2Freact-router-dom-5.2.0.tgz"],
- ["reactstrap", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freactstrap%2Fdownload%2Freactstrap-8.5.1.tgz"],
["regenerator-runtime", "npm:0.13.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.7.tgz"],
["rxjs", "npm:6.6.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Frxjs%2Fdownload%2Frxjs-6.6.2.tgz"],
["sass", "npm:1.26.10::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fsass%2Fdownload%2Fsass-1.26.10.tgz"],
@@ -3523,17 +3513,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
- ["@types/reactstrap", [
- ["npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freactstrap%2Fdownload%2F%40types%2Freactstrap-8.5.1.tgz", {
- "packageLocation": "./.yarn/cache/@types-reactstrap-npm-8.5.1-9008a6014f-87b383af72.zip/node_modules/@types/reactstrap/",
- "packageDependencies": [
- ["@types/reactstrap", "npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freactstrap%2Fdownload%2F%40types%2Freactstrap-8.5.1.tgz"],
- ["@types/react", "npm:16.9.43::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact%2Fdownload%2F%40types%2Freact-16.9.43.tgz"],
- ["popper.js", "npm:1.16.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fpopper.js%2Fdownload%2Fpopper.js-1.16.1.tgz"]
- ],
- "linkType": "HARD",
- }]
- ]],
["@types/resolve", [
["npm:0.0.8::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fresolve%2Fdownload%2F%40types%2Fresolve-0.0.8.tgz", {
"packageLocation": "./.yarn/cache/@types-resolve-npm-0.0.8-86c1fa5722-f54f13e4b6.zip/node_modules/@types/resolve/",
@@ -6087,23 +6066,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
- ["create-react-context", [
- ["virtual:3edf6c5f28de9425dc8acc6598a590fa2241383598df1fae41aa7aced4929105d0fdbdc1efc064936982064228d600f97c6ec4468783d71cc55394fd7509ffb1#npm:0.3.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcreate-react-context%2Fdownload%2Fcreate-react-context-0.3.0.tgz", {
- "packageLocation": "./.yarn/$$virtual/create-react-context-virtual-3b1789c663/0/cache/create-react-context-npm-0.3.0-4a7d9dced4-dfb153bbcf.zip/node_modules/create-react-context/",
- "packageDependencies": [
- ["create-react-context", "virtual:3edf6c5f28de9425dc8acc6598a590fa2241383598df1fae41aa7aced4929105d0fdbdc1efc064936982064228d600f97c6ec4468783d71cc55394fd7509ffb1#npm:0.3.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcreate-react-context%2Fdownload%2Fcreate-react-context-0.3.0.tgz"],
- ["gud", "npm:1.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fgud%2Fdownload%2Fgud-1.0.0.tgz"],
- ["prop-types", "npm:15.7.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fprop-types%2Fdownload%2Fprop-types-15.7.2.tgz"],
- ["react", "npm:16.13.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact%2Fdownload%2Freact-16.13.1.tgz"],
- ["warning", "npm:4.0.3::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fwarning%2Fdownload%2Fwarning-4.0.3.tgz"]
- ],
- "packagePeers": [
- "prop-types",
- "react"
- ],
- "linkType": "HARD",
- }]
- ]],
["cross-spawn", [
["npm:6.0.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-spawn%2Fdownload%2Fcross-spawn-6.0.5.tgz", {
"packageLocation": "./.yarn/cache/cross-spawn-npm-6.0.5-b596e42a26-05fbbf957d.zip/node_modules/cross-spawn/",
@@ -6673,14 +6635,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]
]],
["dom-helpers", [
- ["npm:3.4.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fdom-helpers%2Fdownload%2Fdom-helpers-3.4.0.tgz", {
- "packageLocation": "./.yarn/cache/dom-helpers-npm-3.4.0-f3b5be067d-7625598dbf.zip/node_modules/dom-helpers/",
- "packageDependencies": [
- ["dom-helpers", "npm:3.4.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fdom-helpers%2Fdownload%2Fdom-helpers-3.4.0.tgz"],
- ["@babel/runtime", "npm:7.10.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.10.5.tgz"]
- ],
- "linkType": "HARD",
- }],
["npm:5.2.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fdom-helpers%2Fdownload%2Fdom-helpers-5.2.0.tgz", {
"packageLocation": "./.yarn/cache/dom-helpers-npm-5.2.0-50f26cbd58-9ef27628f4.zip/node_modules/dom-helpers/",
"packageDependencies": [
@@ -8259,15 +8213,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
- ["gud", [
- ["npm:1.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fgud%2Fdownload%2Fgud-1.0.0.tgz", {
- "packageLocation": "./.yarn/cache/gud-npm-1.0.0-e29c6f7e18-08be6bf30e.zip/node_modules/gud/",
- "packageDependencies": [
- ["gud", "npm:1.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fgud%2Fdownload%2Fgud-1.0.0.tgz"]
- ],
- "linkType": "HARD",
- }]
- ]],
["handle-thing", [
["npm:2.0.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fhandle-thing%2Fdownload%2Fhandle-thing-2.0.1.tgz", {
"packageLocation": "./.yarn/cache/handle-thing-npm-2.0.1-05158d71e6-7509fca9eb.zip/node_modules/handle-thing/",
@@ -11401,15 +11346,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
- ["popper.js", [
- ["npm:1.16.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fpopper.js%2Fdownload%2Fpopper.js-1.16.1.tgz", {
- "packageLocation": "./.yarn/cache/popper.js-npm-1.16.1-45dd821913-eb53806fb7.zip/node_modules/popper.js/",
- "packageDependencies": [
- ["popper.js", "npm:1.16.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fpopper.js%2Fdownload%2Fpopper.js-1.16.1.tgz"]
- ],
- "linkType": "HARD",
- }]
- ]],
["portfinder", [
["npm:1.0.27::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fportfinder%2Fdownload%2Fportfinder-1.0.27.tgz", {
"packageLocation": "./.yarn/cache/portfinder-npm-1.0.27-519aa211df-dfecedbaf8.zip/node_modules/portfinder/",
@@ -12448,26 +12384,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
- ["react-popper", [
- ["virtual:3b2ce7b5c8060bb05f2f5c2935213be0b80cbf02d12c698b50272c06d2940bcce3e52fed2f822d06cfa7b13a6aae64654f797a522ecaeb419458c4c10e644495#npm:1.3.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-popper%2Fdownload%2Freact-popper-1.3.7.tgz", {
- "packageLocation": "./.yarn/$$virtual/react-popper-virtual-3edf6c5f28/0/cache/react-popper-npm-1.3.7-0019173f32-09ef58054b.zip/node_modules/react-popper/",
- "packageDependencies": [
- ["react-popper", "virtual:3b2ce7b5c8060bb05f2f5c2935213be0b80cbf02d12c698b50272c06d2940bcce3e52fed2f822d06cfa7b13a6aae64654f797a522ecaeb419458c4c10e644495#npm:1.3.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-popper%2Fdownload%2Freact-popper-1.3.7.tgz"],
- ["@babel/runtime", "npm:7.10.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.10.5.tgz"],
- ["create-react-context", "virtual:3edf6c5f28de9425dc8acc6598a590fa2241383598df1fae41aa7aced4929105d0fdbdc1efc064936982064228d600f97c6ec4468783d71cc55394fd7509ffb1#npm:0.3.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcreate-react-context%2Fdownload%2Fcreate-react-context-0.3.0.tgz"],
- ["deep-equal", "npm:1.1.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeep-equal%2Fdownload%2Fdeep-equal-1.1.1.tgz"],
- ["popper.js", "npm:1.16.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fpopper.js%2Fdownload%2Fpopper.js-1.16.1.tgz"],
- ["prop-types", "npm:15.7.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fprop-types%2Fdownload%2Fprop-types-15.7.2.tgz"],
- ["react", "npm:16.13.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact%2Fdownload%2Freact-16.13.1.tgz"],
- ["typed-styles", "npm:0.0.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Ftyped-styles%2Fdownload%2Ftyped-styles-0.0.7.tgz"],
- ["warning", "npm:4.0.3::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fwarning%2Fdownload%2Fwarning-4.0.3.tgz"]
- ],
- "packagePeers": [
- "react"
- ],
- "linkType": "HARD",
- }]
- ]],
["react-responsive", [
["virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:8.1.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-responsive%2Fdownload%2Freact-responsive-8.1.0.tgz", {
"packageLocation": "./.yarn/$$virtual/react-responsive-virtual-889e4c0da2/0/cache/react-responsive-npm-8.1.0-0c4689f9df-059c460fd4.zip/node_modules/react-responsive/",
@@ -12561,43 +12477,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"react-dom"
],
"linkType": "HARD",
- }],
- ["virtual:3b2ce7b5c8060bb05f2f5c2935213be0b80cbf02d12c698b50272c06d2940bcce3e52fed2f822d06cfa7b13a6aae64654f797a522ecaeb419458c4c10e644495#npm:2.9.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-transition-group%2Fdownload%2Freact-transition-group-2.9.0.tgz", {
- "packageLocation": "./.yarn/$$virtual/react-transition-group-virtual-96734f4ac2/0/cache/react-transition-group-npm-2.9.0-67f8b00a44-eefed08c48.zip/node_modules/react-transition-group/",
- "packageDependencies": [
- ["react-transition-group", "virtual:3b2ce7b5c8060bb05f2f5c2935213be0b80cbf02d12c698b50272c06d2940bcce3e52fed2f822d06cfa7b13a6aae64654f797a522ecaeb419458c4c10e644495#npm:2.9.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-transition-group%2Fdownload%2Freact-transition-group-2.9.0.tgz"],
- ["dom-helpers", "npm:3.4.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fdom-helpers%2Fdownload%2Fdom-helpers-3.4.0.tgz"],
- ["loose-envify", "npm:1.4.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Floose-envify%2Fdownload%2Floose-envify-1.4.0.tgz"],
- ["prop-types", "npm:15.7.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fprop-types%2Fdownload%2Fprop-types-15.7.2.tgz"],
- ["react", "npm:16.13.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact%2Fdownload%2Freact-16.13.1.tgz"],
- ["react-dom", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:16.13.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-dom%2Fdownload%2Freact-dom-16.13.1.tgz"],
- ["react-lifecycles-compat", "npm:3.0.4::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-lifecycles-compat%2Fdownload%2Freact-lifecycles-compat-3.0.4.tgz"]
- ],
- "packagePeers": [
- "react",
- "react-dom"
- ],
- "linkType": "HARD",
- }]
- ]],
- ["reactstrap", [
- ["virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freactstrap%2Fdownload%2Freactstrap-8.5.1.tgz", {
- "packageLocation": "./.yarn/$$virtual/reactstrap-virtual-3b2ce7b5c8/0/cache/reactstrap-npm-8.5.1-233980b7a4-afa5cba1a9.zip/node_modules/reactstrap/",
- "packageDependencies": [
- ["reactstrap", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freactstrap%2Fdownload%2Freactstrap-8.5.1.tgz"],
- ["@babel/runtime", "npm:7.10.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.10.5.tgz"],
- ["classnames", "npm:2.2.6::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fclassnames%2Fdownload%2Fclassnames-2.2.6.tgz"],
- ["prop-types", "npm:15.7.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fprop-types%2Fdownload%2Fprop-types-15.7.2.tgz"],
- ["react", "npm:16.13.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact%2Fdownload%2Freact-16.13.1.tgz"],
- ["react-dom", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:16.13.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-dom%2Fdownload%2Freact-dom-16.13.1.tgz"],
- ["react-popper", "virtual:3b2ce7b5c8060bb05f2f5c2935213be0b80cbf02d12c698b50272c06d2940bcce3e52fed2f822d06cfa7b13a6aae64654f797a522ecaeb419458c4c10e644495#npm:1.3.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-popper%2Fdownload%2Freact-popper-1.3.7.tgz"],
- ["react-transition-group", "virtual:3b2ce7b5c8060bb05f2f5c2935213be0b80cbf02d12c698b50272c06d2940bcce3e52fed2f822d06cfa7b13a6aae64654f797a522ecaeb419458c4c10e644495#npm:2.9.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-transition-group%2Fdownload%2Freact-transition-group-2.9.0.tgz"]
- ],
- "packagePeers": [
- "react",
- "react-dom"
- ],
- "linkType": "HARD",
}]
]],
["read-pkg", [
@@ -14271,7 +14150,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@types/react-router", "npm:5.1.8::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact-router%2Fdownload%2F%40types%2Freact-router-5.1.8.tgz"],
["@types/react-router-bootstrap", "npm:0.24.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact-router-bootstrap%2Fdownload%2F%40types%2Freact-router-bootstrap-0.24.5.tgz"],
["@types/react-router-dom", "npm:5.1.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact-router-dom%2Fdownload%2F%40types%2Freact-router-dom-5.1.5.tgz"],
- ["@types/reactstrap", "npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freactstrap%2Fdownload%2F%40types%2Freactstrap-8.5.1.tgz"],
["@types/webpack-env", "npm:1.15.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fwebpack-env%2Fdownload%2F%40types%2Fwebpack-env-1.15.2.tgz"],
["@types/xregexp", "npm:4.3.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fxregexp%2Fdownload%2F%40types%2Fxregexp-4.3.0.tgz"],
["@typescript-eslint/eslint-plugin", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:3.10.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40typescript-eslint%2Feslint-plugin%2Fdownload%2F%40typescript-eslint%2Feslint-plugin-3.10.1.tgz"],
@@ -14319,7 +14197,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["react-router", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:5.2.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-router%2Fdownload%2Freact-router-5.2.0.tgz"],
["react-router-bootstrap", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:0.25.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-router-bootstrap%2Fdownload%2Freact-router-bootstrap-0.25.0.tgz"],
["react-router-dom", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:5.2.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-router-dom%2Fdownload%2Freact-router-dom-5.2.0.tgz"],
- ["reactstrap", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freactstrap%2Fdownload%2Freactstrap-8.5.1.tgz"],
["regenerator-runtime", "npm:0.13.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.7.tgz"],
["rxjs", "npm:6.6.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Frxjs%2Fdownload%2Frxjs-6.6.2.tgz"],
["sass", "npm:1.26.10::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fsass%2Fdownload%2Fsass-1.26.10.tgz"],
@@ -14610,15 +14487,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
- ["typed-styles", [
- ["npm:0.0.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Ftyped-styles%2Fdownload%2Ftyped-styles-0.0.7.tgz", {
- "packageLocation": "./.yarn/cache/typed-styles-npm-0.0.7-ef2e89d04b-4988d78daf.zip/node_modules/typed-styles/",
- "packageDependencies": [
- ["typed-styles", "npm:0.0.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Ftyped-styles%2Fdownload%2Ftyped-styles-0.0.7.tgz"]
- ],
- "linkType": "HARD",
- }]
- ]],
["typedarray", [
["npm:0.0.6::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Ftypedarray%2Fdownload%2Ftypedarray-0.0.6.tgz", {
"packageLocation": "./.yarn/cache/typedarray-npm-0.0.6-9f6b6bcac0-c9ef0176aa.zip/node_modules/typedarray/",
diff --git a/Timeline/ClientApp/package.json b/Timeline/ClientApp/package.json
index 81232c71..5ae6a608 100644
--- a/Timeline/ClientApp/package.json
+++ b/Timeline/ClientApp/package.json
@@ -27,7 +27,6 @@
"react-router": "^5.2.0",
"react-router-bootstrap": "^0.25.0",
"react-router-dom": "^5.2.0",
- "reactstrap": "^8.5.1",
"regenerator-runtime": "^0.13.7",
"rxjs": "^6.6.2",
"workbox-precaching": "^5.1.3",
@@ -75,7 +74,6 @@
"@types/react-router": "^5.1.8",
"@types/react-router-bootstrap": "^0.24.5",
"@types/react-router-dom": "^5.1.5",
- "@types/reactstrap": "^8.5.1",
"@types/webpack-env": "^1.15.2",
"@types/xregexp": "^4.3.0",
"@typescript-eslint/eslint-plugin": "^3.10.1",
diff --git a/Timeline/ClientApp/src/app/service-worker.tsx b/Timeline/ClientApp/src/app/service-worker.tsx
index e629995a..3be54bc1 100644
--- a/Timeline/ClientApp/src/app/service-worker.tsx
+++ b/Timeline/ClientApp/src/app/service-worker.tsx
@@ -1,6 +1,6 @@
import React from "react";
-import { Button } from "reactstrap";
import { useTranslation } from "react-i18next";
+import { Button } from "react-bootstrap";
import { pushAlert } from "./services/alert";
@@ -39,7 +39,11 @@ if ("serviceWorker" in navigator) {
return (
<>
{t("serviceWorker.externalActivatedPrompt")}
- <Button color="success" size="sm" onClick={upgradeReload} outline>
+ <Button
+ variant="outline-success"
+ size="sm"
+ onClick={upgradeReload}
+ >
{t("serviceWorker.reloadNow")}
</Button>
</>
@@ -83,7 +87,7 @@ if ("serviceWorker" in navigator) {
return (
<>
{t("serviceWorker.upgradePrompt")}
- <Button color="success" size="sm" onClick={upgrade} outline>
+ <Button variant="outline-success" size="sm" onClick={upgrade}>
{t("serviceWorker.upgradeNow")}
</Button>
</>
diff --git a/Timeline/ClientApp/src/app/views/about/index.tsx b/Timeline/ClientApp/src/app/views/about/index.tsx
index 21c487da..78cffb5f 100644
--- a/Timeline/ClientApp/src/app/views/about/index.tsx
+++ b/Timeline/ClientApp/src/app/views/about/index.tsx
@@ -23,8 +23,8 @@ const frontendCredits: {
url: "https://getbootstrap.com",
},
{
- name: "reactstrap",
- url: "https://reactstrap.github.io",
+ name: "react-bootstrap",
+ url: "https://react-bootstrap.github.io",
},
{
name: "babeljs",
diff --git a/Timeline/ClientApp/src/app/views/admin/Admin.tsx b/Timeline/ClientApp/src/app/views/admin/Admin.tsx
index 51dc5a3c..e0f59b0f 100644
--- a/Timeline/ClientApp/src/app/views/admin/Admin.tsx
+++ b/Timeline/ClientApp/src/app/views/admin/Admin.tsx
@@ -1,5 +1,4 @@
import React, { Fragment } from "react";
-import { Nav, NavItem, NavLink } from "reactstrap";
import {
Redirect,
Route,
@@ -7,7 +6,7 @@ import {
useRouteMatch,
useHistory,
} from "react-router";
-import classnames from "classnames";
+import { Nav } from "react-bootstrap";
import AppBar from "../common/AppBar";
import { UserWithToken } from "@/services/user";
@@ -37,27 +36,27 @@ const Admin: React.FC<AdminProps> = (props) => {
<Route path={`${match.path}/${name}`}>
<AppBar />
<div style={{ height: 56 }} className="flex-fix-length" />
- <Nav tabs>
- <NavItem>
- <NavLink
- className={classnames({ active: tabName === "users" })}
+ <Nav variant="tabs">
+ <Nav.Item>
+ <Nav.Link
+ active={tabName === "users"}
onClick={() => {
toggle("users");
}}
>
Users
- </NavLink>
- </NavItem>
- <NavItem>
- <NavLink
- className={classnames({ active: tabName === "more" })}
+ </Nav.Link>
+ </Nav.Item>
+ <Nav.Item>
+ <Nav.Link
+ active={tabName === "more"}
onClick={() => {
toggle("more");
}}
>
More
- </NavLink>
- </NavItem>
+ </Nav.Link>
+ </Nav.Item>
</Nav>
{body}
</Route>
diff --git a/Timeline/ClientApp/src/app/views/admin/UserAdmin.tsx b/Timeline/ClientApp/src/app/views/admin/UserAdmin.tsx
index bde6b3af..18b77ca8 100644
--- a/Timeline/ClientApp/src/app/views/admin/UserAdmin.tsx
+++ b/Timeline/ClientApp/src/app/views/admin/UserAdmin.tsx
@@ -1,16 +1,13 @@
import React, { useState, useEffect } from "react";
+import axios from "axios";
import {
- ListGroupItem,
+ ListGroup,
Row,
Col,
- UncontrolledDropdown,
- DropdownToggle,
- DropdownMenu,
- DropdownItem,
+ Dropdown,
Spinner,
Button,
-} from "reactstrap";
-import axios from "axios";
+} from "react-bootstrap";
import OperationDialog from "../common/OperationDialog";
import { User, UserWithToken } from "@/services/user";
@@ -101,7 +98,7 @@ const UserItem: React.FC<UserCardProps> = (props) => {
};
return (
- <ListGroupItem className="container">
+ <ListGroup.Item className="container">
<Row className="align-items-center">
<Col>
<p className="mb-0 text-primary">{user.username}</p>
@@ -112,31 +109,31 @@ const UserItem: React.FC<UserCardProps> = (props) => {
</small>
</Col>
<Col className="col-auto">
- <UncontrolledDropdown>
- <DropdownToggle color="warning" className="text-light" caret>
+ <Dropdown>
+ <Dropdown.Toggle variant="warning" className="text-light">
Manage
- </DropdownToggle>
- <DropdownMenu>
- <DropdownItem onClick={createClickCallback(kChangeUsername)}>
+ </Dropdown.Toggle>
+ <Dropdown.Menu>
+ <Dropdown.Item onClick={createClickCallback(kChangeUsername)}>
Change Username
- </DropdownItem>
- <DropdownItem onClick={createClickCallback(kChangePassword)}>
+ </Dropdown.Item>
+ <Dropdown.Item onClick={createClickCallback(kChangePassword)}>
Change Password
- </DropdownItem>
- <DropdownItem onClick={createClickCallback(kChangePermission)}>
+ </Dropdown.Item>
+ <Dropdown.Item onClick={createClickCallback(kChangePermission)}>
Change Permission
- </DropdownItem>
- <DropdownItem
+ </Dropdown.Item>
+ <Dropdown.Item
className="text-danger"
onClick={createClickCallback(kDelete)}
>
Delete
- </DropdownItem>
- </DropdownMenu>
- </UncontrolledDropdown>
+ </Dropdown.Item>
+ </Dropdown.Menu>
+ </Dropdown>
</Col>
</Row>
- </ListGroupItem>
+ </ListGroup.Item>
);
};
@@ -441,7 +438,7 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
return (
<>
<Button
- color="success"
+ variant="success"
onClick={() =>
setDialog({
type: "create",
@@ -456,7 +453,7 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
</>
);
} else {
- return <Spinner />;
+ return <Spinner animation="border" />;
}
};
diff --git a/Timeline/ClientApp/src/app/views/common/AppBar.tsx b/Timeline/ClientApp/src/app/views/common/AppBar.tsx
index 464747c0..ee4ead8f 100644
--- a/Timeline/ClientApp/src/app/views/common/AppBar.tsx
+++ b/Timeline/ClientApp/src/app/views/common/AppBar.tsx
@@ -17,7 +17,7 @@ const AppBar: React.FC = (_) => {
const isAdministrator = user && user.administrator;
return (
- <Navbar bg="primary" variant="dark" expand="md">
+ <Navbar bg="primary" variant="dark" expand="md" sticky="top">
<LinkContainer to="/">
<Navbar.Brand className="d-flex align-items-center">
<TimelineLogo style={{ height: "1em" }} />
diff --git a/Timeline/ClientApp/src/app/views/common/FileInput.tsx b/Timeline/ClientApp/src/app/views/common/FileInput.tsx
deleted file mode 100644
index 7b053d5c..00000000
--- a/Timeline/ClientApp/src/app/views/common/FileInput.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from "react";
-import clsx from "clsx";
-
-export interface FileInputProps
- extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "id"> {
- inputId?: string;
- labelText: string;
- color?: string;
- className?: string;
-}
-
-const FileInput: React.FC<FileInputProps> = (props) => {
- const { inputId, labelText, color, className, ...otherProps } = props;
-
- const realInputId = React.useMemo<string>(() => {
- if (inputId != null) return inputId;
- return (
- "file-input-" +
- (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
- );
- }, [inputId]);
-
- return (
- <>
- <input className="d-none" type="file" id={realInputId} {...otherProps} />
- <label
- htmlFor={realInputId}
- className={clsx("btn", "btn-" + (color ?? "primary"), className)}
- >
- {labelText}
- </label>
- </>
- );
-};
-
-export default FileInput;
diff --git a/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx b/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx
index 402ffbec..6f97eb15 100644
--- a/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx
+++ b/Timeline/ClientApp/src/app/views/common/OperationDialog.tsx
@@ -1,26 +1,13 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
-import {
- Spinner,
- Container,
- ModalBody,
- Label,
- Input,
- FormGroup,
- FormFeedback,
- ModalFooter,
- Button,
- Modal,
- ModalHeader,
- FormText,
-} from "reactstrap";
+import { Spinner, Container, Form, Button, Modal } from "react-bootstrap";
import { UiLogicError } from "@/common";
const DefaultProcessPrompt: React.FC = (_) => {
return (
<Container className="justify-content-center align-items-center">
- <Spinner />
+ <Spinner animation="border" variant="success" />
</Container>
);
};
@@ -233,7 +220,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
body = (
<>
- <ModalBody>
+ <Modal.Body>
{inputPrompt}
{inputScheme.map((item, index) => {
const value = values[index];
@@ -242,9 +229,9 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
if (item.type === "text") {
return (
- <FormGroup key={index}>
- {item.label && <Label>{t(item.label)}</Label>}
- <Input
+ <Form.Group key={index}>
+ {item.label && <Form.Label>{t(item.label)}</Form.Label>}
+ <Form.Control
type={item.password === true ? "password" : "text"}
value={value as string}
onChange={(e) => {
@@ -258,35 +245,35 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
)
);
}}
- invalid={error != null}
- {...item.textFieldProps}
+ isInvalid={error != null}
/>
- {error != null && <FormFeedback>{error}</FormFeedback>}
- {item.helperText && <FormText>{t(item.helperText)}</FormText>}
- </FormGroup>
+ {error != null && (
+ <Form.Control.Feedback>{error}</Form.Control.Feedback>
+ )}
+ {item.helperText && (
+ <Form.Text>{t(item.helperText)}</Form.Text>
+ )}
+ </Form.Group>
);
} else if (item.type === "bool") {
return (
- <FormGroup check key={index}>
- <Input
+ <Form.Group key={index}>
+ <Form.Check<"input">
type="checkbox"
- value={value as string}
- onChange={(e) => {
- updateValue(
- index,
- (e.target as HTMLInputElement).checked
- );
+ checked={value as boolean}
+ onChange={(event) => {
+ updateValue(index, event.currentTarget.checked);
}}
+ label={t(item.label)}
/>
- <Label check>{t(item.label)}</Label>
- </FormGroup>
+ </Form.Group>
);
} else if (item.type === "select") {
return (
- <FormGroup key={index}>
- <Label>{t(item.label)}</Label>
- <Input
- type="select"
+ <Form.Group key={index}>
+ <Form.Label>{t(item.label)}</Form.Label>
+ <Form.Control
+ as="select"
value={value as string}
onChange={(event) => {
updateValue(index, event.target.value);
@@ -300,18 +287,18 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
</option>
);
})}
- </Input>
- </FormGroup>
+ </Form.Control>
+ </Form.Group>
);
}
})}
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={close}>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={close}>
{t("operationDialog.cancel")}
</Button>
<Button
- color="primary"
+ variant="primary"
disabled={testErrorInfo(inputError)}
onClick={() => {
if (validateAll()) {
@@ -321,14 +308,14 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
>
{t("operationDialog.confirm")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
} else if (step === "process") {
body = (
- <ModalBody>
+ <Modal.Body>
{props.processPrompt?.() ?? <DefaultProcessPrompt />}
- </ModalBody>
+ </Modal.Body>
);
} else {
let content: React.ReactNode;
@@ -345,12 +332,12 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
}
body = (
<>
- <ModalBody>{content}</ModalBody>
- <ModalFooter>
- <Button color="primary" onClick={close}>
+ <Modal.Body>{content}</Modal.Body>
+ <Modal.Footer>
+ <Button variant="primary" onClick={close}>
{t("operationDialog.ok")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
}
@@ -359,7 +346,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
return (
<Modal isOpen={props.open} toggle={close}>
- <ModalHeader
+ <Modal.Header
className={
props.titleColor != null
? "text-" +
@@ -372,7 +359,7 @@ const OperationDialog: React.FC<OperationDialogProps> = (props) => {
}
>
{title}
- </ModalHeader>
+ </Modal.Header>
{body}
</Modal>
);
diff --git a/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx b/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx
index 31c0fb86..c74f18e2 100644
--- a/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx
+++ b/Timeline/ClientApp/src/app/views/common/alert/AlertHost.tsx
@@ -1,8 +1,8 @@
import React, { useCallback } from "react";
-import { Alert } from "reactstrap";
import without from "lodash/without";
import concat from "lodash/concat";
import { useTranslation } from "react-i18next";
+import { Alert } from "react-bootstrap";
import {
alertService,
@@ -37,7 +37,12 @@ export const AutoCloseAlert: React.FC<AutoCloseAlertProps> = (props) => {
}, [dismissTime, props.close]);
return (
- <Alert className="m-3" color={alert.type ?? "primary"} toggle={props.close}>
+ <Alert
+ className="m-3"
+ variant={alert.type ?? "primary"}
+ onClose={props.close}
+ dismissible
+ >
{(() => {
const { message } = alert;
if (typeof message === "function") {
diff --git a/Timeline/ClientApp/src/app/views/login/index.tsx b/Timeline/ClientApp/src/app/views/login/index.tsx
index e53d0002..5d1e8f06 100644
--- a/Timeline/ClientApp/src/app/views/login/index.tsx
+++ b/Timeline/ClientApp/src/app/views/login/index.tsx
@@ -1,15 +1,7 @@
import React, { Fragment, useState, useEffect } from "react";
import { useHistory } from "react-router";
import { useTranslation } from "react-i18next";
-import {
- Label,
- FormGroup,
- Input,
- Form,
- FormFeedback,
- Spinner,
- Button,
-} from "reactstrap";
+import { Form, Spinner, Button } from "react-bootstrap";
import { useUser, userService } from "@/services/user";
@@ -84,9 +76,9 @@ const LoginPage: React.FC = (_) => {
<div className="container login-container mt-appbar">
<h1>{t("welcome")}</h1>
<Form>
- <FormGroup>
- <Label for="username">{t("user.username")}</Label>
- <Input
+ <Form.Group>
+ <Form.Label htmlFor="username">{t("user.username")}</Form.Label>
+ <Form.Control
id="username"
disabled={process}
onChange={(e) => {
@@ -94,15 +86,17 @@ const LoginPage: React.FC = (_) => {
setUsernameDirty(true);
}}
value={username}
- invalid={usernameDirty && username === ""}
+ isInvalid={usernameDirty && username === ""}
/>
{usernameDirty && username === "" && (
- <FormFeedback>{t("login.emptyUsername")}</FormFeedback>
+ <Form.Control.Feedback>
+ {t("login.emptyUsername")}
+ </Form.Control.Feedback>
)}
- </FormGroup>
- <FormGroup>
- <Label for="password">{t("user.password")}</Label>
- <Input
+ </Form.Group>
+ <Form.Group>
+ <Form.Label htmlFor="password">{t("user.password")}</Form.Label>
+ <Form.Control
id="password"
type="password"
disabled={process}
@@ -111,30 +105,31 @@ const LoginPage: React.FC = (_) => {
setPasswordDirty(true);
}}
value={password}
- invalid={passwordDirty && password === ""}
+ isInvalid={passwordDirty && password === ""}
/>
{passwordDirty && password === "" && (
- <FormFeedback>{t("login.emptyPassword")}</FormFeedback>
+ <Form.Control.Feedback>
+ {t("login.emptyPassword")}
+ </Form.Control.Feedback>
)}
- </FormGroup>
- <FormGroup check>
- <Input
+ </Form.Group>
+ <Form.Group>
+ <Form.Check<"input">
id="remember-me"
type="checkbox"
checked={rememberMe}
onChange={(e) => {
- const v = (e.target as HTMLInputElement).checked;
- setRememberMe(v);
+ setRememberMe(e.target.checked);
}}
+ label={t("user.rememberMe")}
/>
- <Label for="remember-me">{t("user.rememberMe")}</Label>
- </FormGroup>
+ </Form.Group>
{error ? <p className="text-error">{t(error)}</p> : null}
<div>
{process ? (
- <Spinner />
+ <Spinner animation="border" />
) : (
- <Button color="primary" onClick={onSubmit}>
+ <Button variant="primary" onClick={onSubmit}>
{t("user.login")}
</Button>
)}
diff --git a/Timeline/ClientApp/src/app/views/timeline-common/TimelineItem.tsx b/Timeline/ClientApp/src/app/views/timeline-common/TimelineItem.tsx
index f2441612..ce371015 100644
--- a/Timeline/ClientApp/src/app/views/timeline-common/TimelineItem.tsx
+++ b/Timeline/ClientApp/src/app/views/timeline-common/TimelineItem.tsx
@@ -1,19 +1,11 @@
import React from "react";
import clsx from "clsx";
-import {
- Row,
- Col,
- Modal,
- ModalHeader,
- ModalBody,
- ModalFooter,
- Button,
-} from "reactstrap";
import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
import Svg from "react-inlinesvg";
import chevronDownIcon from "bootstrap-icons/icons/chevron-down.svg";
import trashIcon from "bootstrap-icons/icons/trash.svg";
+import { Row, Col, Modal, Button } from "react-bootstrap";
import { useAvatar } from "@/services/user";
import { TimelinePostInfo } from "@/services/timeline";
@@ -28,16 +20,18 @@ const TimelinePostDeleteConfirmDialog: React.FC<{
return (
<Modal toggle={toggle} isOpen centered>
- <ModalHeader className="text-danger">
- {t("timeline.post.deleteDialog.title")}
- </ModalHeader>
- <ModalBody>{t("timeline.post.deleteDialog.prompt")}</ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
+ <Modal.Header>
+ <Modal.Title className="text-danger">
+ {t("timeline.post.deleteDialog.title")}
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>{t("timeline.post.deleteDialog.prompt")}</Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={toggle}>
{t("operationDialog.cancel")}
</Button>
<Button
- color="danger"
+ variant="danger"
onClick={() => {
onConfirm();
toggle();
@@ -45,7 +39,7 @@ const TimelinePostDeleteConfirmDialog: React.FC<{
>
{t("operationDialog.confirm")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</Modal>
);
};
diff --git a/Timeline/ClientApp/src/app/views/timeline-common/TimelineMember.tsx b/Timeline/ClientApp/src/app/views/timeline-common/TimelineMember.tsx
index 99605922..67a8543a 100644
--- a/Timeline/ClientApp/src/app/views/timeline-common/TimelineMember.tsx
+++ b/Timeline/ClientApp/src/app/views/timeline-common/TimelineMember.tsx
@@ -1,14 +1,6 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
-import {
- Container,
- ListGroup,
- ListGroupItem,
- Modal,
- Row,
- Col,
- Button,
-} from "reactstrap";
+import { Container, ListGroup, Modal, Row, Col, Button } from "react-bootstrap";
import { User, useAvatar } from "@/services/user";
@@ -25,9 +17,9 @@ const TimelineMemberItem: React.FC<{
const avatar = useAvatar(user.username);
return (
- <ListGroupItem className="container">
+ <ListGroup.Item className="container">
<Row>
- <Col className="col-auto">
+ <Col xs="auto">
<BlobImage blob={avatar} className="avatar small" />
</Col>
<Col>
@@ -46,7 +38,7 @@ const TimelineMemberItem: React.FC<{
return (
<Button
className="align-self-center"
- color="danger"
+ variant="danger"
onClick={() => {
onRemove(user.username);
}}
@@ -56,7 +48,7 @@ const TimelineMemberItem: React.FC<{
);
})()}
</Row>
- </ListGroupItem>
+ </ListGroup.Item>
);
};
@@ -169,7 +161,7 @@ const TimelineMember: React.FC<TimelineMemberProps> = (props) => {
</Row>
</Col>
<Button
- color="primary"
+ variant="primary"
className="align-self-center"
disabled={!addable}
onClick={() => {
@@ -212,7 +204,7 @@ export const TimelineMemberDialog: React.FC<TimelineMemberDialogProps> = (
props
) => {
return (
- <Modal isOpen={props.open} toggle={props.onClose}>
+ <Modal show centered onHide={props.onClose}>
<TimelineMember {...props} />
</Modal>
);
diff --git a/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplate.tsx b/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplate.tsx
index 1b03d5c7..d5c91622 100644
--- a/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplate.tsx
+++ b/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplate.tsx
@@ -160,10 +160,6 @@ export default function TimelinePageTemplate<TManageItem>(
[onManageProp]
);
- const onMember = React.useCallback(() => {
- setDialog("member");
- }, []);
-
return (
<>
<UiComponent
@@ -181,7 +177,7 @@ export default function TimelinePageTemplate<TManageItem>(
? onManage
: undefined
}
- onMember={onMember}
+ onMember={() => setDialog("member")}
/>
{dialogElement}
</>
diff --git a/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx b/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
index 7af11efa..e25ed962 100644
--- a/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
+++ b/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
@@ -1,9 +1,9 @@
import React, { CSSProperties } from "react";
-import { Spinner } from "reactstrap";
+import clsx from "clsx";
import { useTranslation } from "react-i18next";
import { fromEvent } from "rxjs";
import Svg from "react-inlinesvg";
-import clsx from "clsx";
+import { Spinner } from "react-bootstrap";
import arrowsAngleContractIcon from "bootstrap-icons/icons/arrows-angle-contract.svg";
import arrowsAngleExpandIcon from "bootstrap-icons/icons/arrows-angle-expand.svg";
@@ -262,7 +262,7 @@ export default function TimelinePageTemplateUI<TManageItems>(
} else {
timelineBody = (
<div className="full-viewport-center-child">
- <Spinner color="primary" type="grow" />
+ <Spinner variant="primary" animation="grow" />
</div>
);
}
@@ -271,7 +271,7 @@ export default function TimelinePageTemplateUI<TManageItems>(
body = (
<>
<div
- className="fixed-top mt-appbar info-card-container"
+ className="info-card-container"
data-collapse={infoCardCollapse ? "true" : "false"}
>
<Svg
@@ -304,7 +304,7 @@ export default function TimelinePageTemplateUI<TManageItems>(
} else {
body = (
<div className="full-viewport-center-child">
- <Spinner color="primary" type="grow" />
+ <Spinner variant="primary" animation="grow" />
</div>
);
}
@@ -313,13 +313,7 @@ export default function TimelinePageTemplateUI<TManageItems>(
return (
<>
<AppBar />
- <div>
- <div
- style={{ height: 56 + cardHeight }}
- className="timeline-page-top-space flex-fix-length"
- />
- {body}
- </div>
+ {body}
</>
);
}
diff --git a/Timeline/ClientApp/src/app/views/timeline-common/TimelinePostEdit.tsx b/Timeline/ClientApp/src/app/views/timeline-common/TimelinePostEdit.tsx
index 6a8bb000..42f83b52 100644
--- a/Timeline/ClientApp/src/app/views/timeline-common/TimelinePostEdit.tsx
+++ b/Timeline/ClientApp/src/app/views/timeline-common/TimelinePostEdit.tsx
@@ -1,7 +1,7 @@
import React from "react";
-import { Button, Spinner, Row, Col } from "reactstrap";
import { useTranslation } from "react-i18next";
import Svg from "react-inlinesvg";
+import { Button, Spinner, Row, Col, Form } from "react-bootstrap";
import textIcon from "bootstrap-icons/icons/card-text.svg";
import imageIcon from "bootstrap-icons/icons/image.svg";
@@ -10,8 +10,6 @@ import { UiLogicError } from "@/common";
import { pushAlert } from "@/services/alert";
import { TimelineCreatePostRequest } from "@/services/timeline";
-import FileInput from "../common/FileInput";
-
interface TimelinePostEditImageProps {
onSelect: (blob: Blob | null) => void;
}
@@ -59,11 +57,11 @@ const TimelinePostEditImage: React.FC<TimelinePostEditImageProps> = (props) => {
return (
<>
- <FileInput
- labelText={t("chooseImage")}
+ <Form.File
+ label={t("chooseImage")}
onChange={onInputChange}
accept="image/*"
- className="mx-3 my-1"
+ className="mx-3 my-1 d-inline-block"
/>
{fileUrl && error == null && (
<img
@@ -189,7 +187,8 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
<Row>
<Col className="px-1 py-1">
{kind === "text" ? (
- <textarea
+ <Form.Control
+ as="textarea"
className="w-100 h-100 timeline-post-edit"
value={text}
disabled={state === "process"}
@@ -203,7 +202,7 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
<TimelinePostEditImage onSelect={onImageSelect} />
)}
</Col>
- <Col sm="col-auto align-self-end m-1">
+ <Col xs="auto" className="align-self-end m-1">
{(() => {
if (state === "input") {
return (
@@ -216,13 +215,17 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
onClick={toggleKind}
/>
</div>
- <Button color="primary" onClick={onSend} disabled={!canSend}>
+ <Button
+ variant="primary"
+ onClick={onSend}
+ disabled={!canSend}
+ >
{t("timeline.send")}
</Button>
</>
);
} else {
- return <Spinner />;
+ return <Spinner variant="primary" animation="border" />;
}
})()}
</Col>
diff --git a/Timeline/ClientApp/src/app/views/timeline-common/timeline-common.sass b/Timeline/ClientApp/src/app/views/timeline-common/timeline-common.sass
index 960c992d..1862de02 100644
--- a/Timeline/ClientApp/src/app/views/timeline-common/timeline-common.sass
+++ b/Timeline/ClientApp/src/app/views/timeline-common/timeline-common.sass
@@ -119,14 +119,6 @@ $timeline-line-color-current: #36c2e6
background: change-color($color: white, $alpha: 0.8)
z-index: 100
-textarea.timeline-post-edit
- @extend .border-primary
- @extend .rounded
-
- &:focus
- outline: none
- box-shadow: 0 0 5px 0 $primary
-
.timeline-page-top-space
transition: height 0.5s
@@ -147,3 +139,20 @@ textarea.timeline-post-edit
border-radius: 50%
vertical-align: middle
margin-right: 0.6em
+
+.info-card-container
+ position: sticky
+ z-index: 1
+
+ .info-card-collapse-button
+ z-index: 1
+ position: relative
+
+ .info-card-content
+ width: 100%
+ transform-origin: right top
+ transition: transform 0.5s
+
+ &[data-collapse='true']
+ .info-card-content
+ transform: scale(0)
diff --git a/Timeline/ClientApp/src/app/views/timeline/TimelineInfoCard.tsx b/Timeline/ClientApp/src/app/views/timeline/TimelineInfoCard.tsx
index e3e89057..bf5c3105 100644
--- a/Timeline/ClientApp/src/app/views/timeline/TimelineInfoCard.tsx
+++ b/Timeline/ClientApp/src/app/views/timeline/TimelineInfoCard.tsx
@@ -1,14 +1,8 @@
import React from "react";
import clsx from "clsx";
-import {
- Dropdown,
- DropdownToggle,
- DropdownMenu,
- DropdownItem,
- Button,
-} from "reactstrap";
import { useTranslation } from "react-i18next";
import { fromEvent } from "rxjs";
+import { Dropdown, Button } from "react-bootstrap";
import { useAvatar } from "@/services/user";
import { timelineVisibilityTooltipTranslationMap } from "@/services/timeline";
@@ -23,7 +17,7 @@ export type TimelineInfoCardProps = TimelineCardComponentProps<
>;
const TimelineInfoCard: React.FC<TimelineInfoCardProps> = (props) => {
- const { onHeight, onManage } = props;
+ const { onHeight, onMember, onManage } = props;
const { t } = useTranslation();
@@ -43,18 +37,10 @@ const TimelineInfoCard: React.FC<TimelineInfoCardProps> = (props) => {
return () => subscription.unsubscribe();
});
- const [manageDropdownOpen, setManageDropdownOpen] = React.useState<boolean>(
- false
- );
- const toggleManageDropdown = React.useCallback(
- (): void => setManageDropdownOpen((old) => !old),
- []
- );
-
return (
<div
ref={containerRef}
- className={clsx("rounded border p-2 bg-light", props.className)}
+ className={clsx("rounded border p-2 bg-light clearfix", props.className)}
onTransitionEnd={notifyHeight}
>
<h3 className="text-primary mx-3 d-inline-block align-middle">
@@ -77,28 +63,28 @@ const TimelineInfoCard: React.FC<TimelineInfoCardProps> = (props) => {
</small>
<div className="text-right mt-2">
{onManage != null ? (
- <Dropdown isOpen={manageDropdownOpen} toggle={toggleManageDropdown}>
- <DropdownToggle outline color="primary">
+ <Dropdown>
+ <Dropdown.Toggle variant="outline-primary">
{t("timeline.manage")}
- </DropdownToggle>
- <DropdownMenu>
- <DropdownItem onClick={() => onManage("property")}>
+ </Dropdown.Toggle>
+ <Dropdown.Menu>
+ <Dropdown.Item onClick={() => onManage("property")}>
{t("timeline.manageItem.property")}
- </DropdownItem>
- <DropdownItem onClick={props.onMember}>
+ </Dropdown.Item>
+ <Dropdown.Item onClick={onMember}>
{t("timeline.manageItem.member")}
- </DropdownItem>
- <DropdownItem divider />
- <DropdownItem
+ </Dropdown.Item>
+ <Dropdown.Divider />
+ <Dropdown.Item
className="text-danger"
onClick={() => onManage("delete")}
>
{t("timeline.manageItem.delete")}
- </DropdownItem>
- </DropdownMenu>
+ </Dropdown.Item>
+ </Dropdown.Menu>
</Dropdown>
) : (
- <Button color="primary" outline onClick={props.onMember}>
+ <Button variant="outline-primary" onClick={onMember}>
{t("timeline.memberButton")}
</Button>
)}
diff --git a/Timeline/ClientApp/src/app/views/timeline/timeline.sass b/Timeline/ClientApp/src/app/views/timeline/timeline.sass
index 0eeec73a..e69de29b 100644
--- a/Timeline/ClientApp/src/app/views/timeline/timeline.sass
+++ b/Timeline/ClientApp/src/app/views/timeline/timeline.sass
@@ -1,14 +0,0 @@
-.info-card-container
- .info-card-collapse-button
- z-index: 1
- position: relative
-
- .info-card-content
- width: 100%
- position: absolute
- transform-origin: right top
- transition: transform 0.5s
-
- &[data-collapse='true']
- .info-card-content
- transform: scale(0)
diff --git a/Timeline/ClientApp/src/app/views/user/ChangeAvatarDialog.tsx b/Timeline/ClientApp/src/app/views/user/ChangeAvatarDialog.tsx
index 1dd2ee8b..ffa2218b 100644
--- a/Timeline/ClientApp/src/app/views/user/ChangeAvatarDialog.tsx
+++ b/Timeline/ClientApp/src/app/views/user/ChangeAvatarDialog.tsx
@@ -1,14 +1,7 @@
import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
-import {
- Modal,
- ModalHeader,
- Row,
- Button,
- ModalBody,
- ModalFooter,
-} from "reactstrap";
import { AxiosError } from "axios";
+import { Modal, Row, Button } from "react-bootstrap";
import { UiLogicError } from "@/common";
@@ -56,7 +49,7 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
const closeDialog = props.close;
- const toggle = React.useCallback((): void => {
+ const close = React.useCallback((): void => {
if (!(state === "uploading")) {
closeDialog();
}
@@ -163,23 +156,25 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
};
return (
- <Modal isOpen={props.open} toggle={toggle}>
- <ModalHeader> {t("userPage.dialogChangeAvatar.title")}</ModalHeader>
+ <Modal show={props.open} onHide={close}>
+ <Modal.Header>
+ <Modal.Title> {t("userPage.dialogChangeAvatar.title")}</Modal.Title>
+ </Modal.Header>
{(() => {
if (state === "select") {
return (
<>
- <ModalBody className="container">
+ <Modal.Body className="container">
<Row>{t("userPage.dialogChangeAvatar.prompt.select")}</Row>
<Row>
<input type="file" accept="image/*" onChange={onSelectFile} />
</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={close}>
{t("operationDialog.cancel")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
} else if (state === "crop") {
@@ -188,7 +183,7 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
}
return (
<>
- <ModalBody className="container">
+ <Modal.Body className="container">
<Row className="justify-content-center">
<ImageCropper
clip={clip}
@@ -198,12 +193,12 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
/>
</Row>
<Row>{t("userPage.dialogChangeAvatar.prompt.crop")}</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={close}>
{t("operationDialog.cancel")}
</Button>
- <Button color="secondary" onClick={onCropPrevious}>
+ <Button variant="secondary" onClick={onCropPrevious}>
{t("operationDialog.previousStep")}
</Button>
<Button
@@ -215,87 +210,87 @@ const ChangeAvatarDialog: React.FC<ChangeAvatarDialogProps> = (props) => {
>
{t("operationDialog.nextStep")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
} else if (state === "processcrop") {
return (
<>
- <ModalBody className="container">
+ <Modal.Body className="container">
<Row>
{t("userPage.dialogChangeAvatar.prompt.processingCrop")}
</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={close}>
{t("operationDialog.cancel")}
</Button>
- <Button color="secondary" onClick={onPreviewPrevious}>
+ <Button variant="secondary" onClick={onPreviewPrevious}>
{t("operationDialog.previousStep")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
} else if (state === "preview") {
return (
<>
- <ModalBody className="container">
+ <Modal.Body className="container">
{createPreviewRow()}
<Row>{t("userPage.dialogChangeAvatar.prompt.preview")}</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={close}>
{t("operationDialog.cancel")}
</Button>
- <Button color="secondary" onClick={onPreviewPrevious}>
+ <Button variant="secondary" onClick={onPreviewPrevious}>
{t("operationDialog.previousStep")}
</Button>
- <Button color="primary" onClick={upload}>
+ <Button variant="primary" onClick={upload}>
{t("userPage.dialogChangeAvatar.upload")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
} else if (state === "uploading") {
return (
<>
- <ModalBody className="container">
+ <Modal.Body className="container">
{createPreviewRow()}
<Row>{t("userPage.dialogChangeAvatar.prompt.uploading")}</Row>
- </ModalBody>
- <ModalFooter></ModalFooter>
+ </Modal.Body>
+ <Modal.Footer></Modal.Footer>
</>
);
} else if (state === "success") {
return (
<>
- <ModalBody className="container">
+ <Modal.Body className="container">
<Row className="p-4 text-success">
{t("operationDialog.success")}
</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="success" onClick={toggle}>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="success" onClick={close}>
{t("operationDialog.ok")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
} else {
return (
<>
- <ModalBody className="container">
+ <Modal.Body className="container">
{createPreviewRow()}
<Row className="text-danger">{trueMessage}</Row>
- </ModalBody>
- <ModalFooter>
- <Button color="secondary" onClick={toggle}>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={close}>
{t("operationDialog.cancel")}
</Button>
- <Button color="primary" onClick={upload}>
+ <Button variant="primary" onClick={upload}>
{t("operationDialog.retry")}
</Button>
- </ModalFooter>
+ </Modal.Footer>
</>
);
}
diff --git a/Timeline/ClientApp/src/app/views/user/UserInfoCard.tsx b/Timeline/ClientApp/src/app/views/user/UserInfoCard.tsx
index 1a111877..f1878b5c 100644
--- a/Timeline/ClientApp/src/app/views/user/UserInfoCard.tsx
+++ b/Timeline/ClientApp/src/app/views/user/UserInfoCard.tsx
@@ -1,14 +1,8 @@
import React from "react";
import clsx from "clsx";
-import {
- Dropdown,
- DropdownToggle,
- DropdownMenu,
- DropdownItem,
- Button,
-} from "reactstrap";
import { useTranslation } from "react-i18next";
import { fromEvent } from "rxjs";
+import { Dropdown, Button } from "react-bootstrap";
import { timelineVisibilityTooltipTranslationMap } from "@/services/timeline";
import { useAvatar } from "@/services/user";
@@ -42,24 +36,16 @@ const UserInfoCard: React.FC<UserInfoCardProps> = (props) => {
return () => subscription.unsubscribe();
});
- const [manageDropdownOpen, setManageDropdownOpen] = React.useState<boolean>(
- false
- );
- const toggleManageDropdown = React.useCallback(
- (): void => setManageDropdownOpen((old) => !old),
- []
- );
-
return (
<div
ref={containerRef}
- className={clsx("rounded border bg-light p-2", props.className)}
+ className={clsx("rounded border bg-light p-2 clearfix", props.className)}
onTransitionEnd={notifyHeight}
>
<BlobImage
blob={avatar}
onLoad={notifyHeight}
- className="avatar large mr-2 mb-2 rounded-circle float-left"
+ className="avatar large mr-2 rounded-circle float-left"
/>
<div>
{props.timeline.owner.nickname}
@@ -73,27 +59,27 @@ const UserInfoCard: React.FC<UserInfoCardProps> = (props) => {
</small>
<div className="text-right mt-2">
{onManage != null ? (
- <Dropdown isOpen={manageDropdownOpen} toggle={toggleManageDropdown}>
- <DropdownToggle outline color="primary">
+ <Dropdown>
+ <Dropdown.Toggle variant="outline-primary">
{t("timeline.manage")}
- </DropdownToggle>
- <DropdownMenu>
- <DropdownItem onClick={() => onManage("nickname")}>
+ </Dropdown.Toggle>
+ <Dropdown.Menu>
+ <Dropdown.Item onClick={() => onManage("nickname")}>
{t("timeline.manageItem.nickname")}
- </DropdownItem>
- <DropdownItem onClick={() => onManage("avatar")}>
+ </Dropdown.Item>
+ <Dropdown.Item onClick={() => onManage("avatar")}>
{t("timeline.manageItem.avatar")}
- </DropdownItem>
- <DropdownItem onClick={() => onManage("property")}>
+ </Dropdown.Item>
+ <Dropdown.Item onClick={() => onManage("property")}>
{t("timeline.manageItem.property")}
- </DropdownItem>
- <DropdownItem onClick={props.onMember}>
+ </Dropdown.Item>
+ <Dropdown.Item onClick={props.onMember}>
{t("timeline.manageItem.member")}
- </DropdownItem>
- </DropdownMenu>
+ </Dropdown.Item>
+ </Dropdown.Menu>
</Dropdown>
) : (
- <Button color="primary" outline onClick={props.onMember}>
+ <Button variant="outline-primary" onClick={props.onMember}>
{t("timeline.memberButton")}
</Button>
)}
diff --git a/Timeline/ClientApp/yarn.lock b/Timeline/ClientApp/yarn.lock
index b60c6fef..8ca54343 100644
--- a/Timeline/ClientApp/yarn.lock
+++ b/Timeline/ClientApp/yarn.lock
@@ -1488,7 +1488,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4":
+"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4":
version: 7.10.5
resolution: "@babel/runtime@npm:7.10.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.10.5.tgz"
dependencies:
@@ -2015,16 +2015,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/reactstrap@npm:^8.5.1":
- version: 8.5.1
- resolution: "@types/reactstrap@npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freactstrap%2Fdownload%2F%40types%2Freactstrap-8.5.1.tgz"
- dependencies:
- "@types/react": "*"
- popper.js: ^1.14.1
- checksum: 87b383af721243214a3ae8bf4867f932ed0fcd56489337290ce090a264e3db6419ee266d57dcdc406bdbf9185c5cf2c742402e870c396c6735f8ebc00c06af09
- languageName: node
- linkType: hard
-
"@types/resolve@npm:0.0.8":
version: 0.0.8
resolution: "@types/resolve@npm:0.0.8::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fresolve%2Fdownload%2F%40types%2Fresolve-0.0.8.tgz"
@@ -3847,7 +3837,7 @@ __metadata:
languageName: node
linkType: hard
-"classnames@npm:^2.2.3, classnames@npm:^2.2.6":
+"classnames@npm:^2.2.6":
version: 2.2.6
resolution: "classnames@npm:2.2.6::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fclassnames%2Fdownload%2Fclassnames-2.2.6.tgz"
checksum: 490eaeca5931846737ffd33e472a701d268d5b8bc5717dd4cf108a127b06e86e05350e06799abbbe763a0e4c945b4217f6700b7ae00ddc703505682c370e5cf2
@@ -4288,19 +4278,6 @@ __metadata:
languageName: node
linkType: hard
-"create-react-context@npm:^0.3.0":
- version: 0.3.0
- resolution: "create-react-context@npm:0.3.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcreate-react-context%2Fdownload%2Fcreate-react-context-0.3.0.tgz"
- dependencies:
- gud: ^1.0.0
- warning: ^4.0.3
- peerDependencies:
- prop-types: ^15.0.0
- react: ^0.14.0 || ^15.0.0 || ^16.0.0
- checksum: dfb153bbcfe44fb0b5d74e097f41fef382c9ea513084f604fea1759aea6683da0eef13b02ede2f0672c4eeacdd8efce0023935ca02909fcb2ae8be28b9aa63f5
- languageName: node
- linkType: hard
-
"cross-spawn@npm:7.0.3, cross-spawn@npm:^7.0.2":
version: 7.0.3
resolution: "cross-spawn@npm:7.0.3::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-spawn%2Fdownload%2Fcross-spawn-7.0.3.tgz"
@@ -4559,7 +4536,7 @@ __metadata:
languageName: node
linkType: hard
-"deep-equal@npm:^1.0.1, deep-equal@npm:^1.1.1":
+"deep-equal@npm:^1.0.1":
version: 1.1.1
resolution: "deep-equal@npm:1.1.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeep-equal%2Fdownload%2Fdeep-equal-1.1.1.tgz"
dependencies:
@@ -4798,15 +4775,6 @@ __metadata:
languageName: node
linkType: hard
-"dom-helpers@npm:^3.4.0":
- version: 3.4.0
- resolution: "dom-helpers@npm:3.4.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fdom-helpers%2Fdownload%2Fdom-helpers-3.4.0.tgz"
- dependencies:
- "@babel/runtime": ^7.1.2
- checksum: 7625598dbfef65a50801e194b88f277ab398dd92c27398280fd8d69294326f05d9b0588922560ba50e10d9fe5ee8096f90995d679b7db2b776afd579d495b962
- languageName: node
- linkType: hard
-
"dom-helpers@npm:^5.0.1, dom-helpers@npm:^5.1.0, dom-helpers@npm:^5.1.2":
version: 5.2.0
resolution: "dom-helpers@npm:5.2.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fdom-helpers%2Fdownload%2Fdom-helpers-5.2.0.tgz"
@@ -6248,13 +6216,6 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
-"gud@npm:^1.0.0":
- version: 1.0.0
- resolution: "gud@npm:1.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fgud%2Fdownload%2Fgud-1.0.0.tgz"
- checksum: 08be6bf30eb713b0e115a4676418b3805b739703956fd861710f59ce355c047102954e4d79172b180912d06794e8d94f702e9367ac6843c2fae40c8c726a4907
- languageName: node
- linkType: hard
-
"handle-thing@npm:^2.0.0":
version: 2.0.1
resolution: "handle-thing@npm:2.0.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fhandle-thing%2Fdownload%2Fhandle-thing-2.0.1.tgz"
@@ -9068,13 +9029,6 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
-"popper.js@npm:^1.14.1, popper.js@npm:^1.14.4":
- version: 1.16.1
- resolution: "popper.js@npm:1.16.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fpopper.js%2Fdownload%2Fpopper.js-1.16.1.tgz"
- checksum: eb53806fb7680e31c7d1db096f95438a40a7cb869f7ee0e27100c0860f11583a0d322606c6073618e7fe8865f834ec36482901b547256d9a0cf2b22434bca75d
- languageName: node
- linkType: hard
-
"portfinder@npm:^1.0.25, portfinder@npm:^1.0.26":
version: 1.0.27
resolution: "portfinder@npm:1.0.27::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fportfinder%2Fdownload%2Fportfinder-1.0.27.tgz"
@@ -9651,7 +9605,7 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
-"prop-types@npm:^15.5.10, prop-types@npm:^15.5.8, prop-types@npm:^15.6.1, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2":
+"prop-types@npm:^15.5.10, prop-types@npm:^15.6.1, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2":
version: 15.7.2
resolution: "prop-types@npm:15.7.2::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fprop-types%2Fdownload%2Fprop-types-15.7.2.tgz"
dependencies:
@@ -9982,23 +9936,6 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
-"react-popper@npm:^1.3.6":
- version: 1.3.7
- resolution: "react-popper@npm:1.3.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-popper%2Fdownload%2Freact-popper-1.3.7.tgz"
- dependencies:
- "@babel/runtime": ^7.1.2
- create-react-context: ^0.3.0
- deep-equal: ^1.1.1
- popper.js: ^1.14.4
- prop-types: ^15.6.1
- typed-styles: ^0.0.7
- warning: ^4.0.2
- peerDependencies:
- react: 0.14.x || ^15.0.0 || ^16.0.0
- checksum: 09ef58054bd9d449283939af861cbb205aee771289884fa62e30a6927163fab53e865593c0e014364d807a8e219d9642be6d34ae58b1e4f2f0530ffc9b289e5a
- languageName: node
- linkType: hard
-
"react-responsive@npm:^8.1.0":
version: 8.1.0
resolution: "react-responsive@npm:8.1.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-responsive%2Fdownload%2Freact-responsive-8.1.0.tgz"
@@ -10062,21 +9999,6 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
-"react-transition-group@npm:^2.3.1":
- version: 2.9.0
- resolution: "react-transition-group@npm:2.9.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-transition-group%2Fdownload%2Freact-transition-group-2.9.0.tgz"
- dependencies:
- dom-helpers: ^3.4.0
- loose-envify: ^1.4.0
- prop-types: ^15.6.2
- react-lifecycles-compat: ^3.0.4
- peerDependencies:
- react: ">=15.0.0"
- react-dom: ">=15.0.0"
- checksum: eefed08c48a0d377b5fac3ac7fac54ed986d5dcdd4494f36075954c9d2d257072a9d18cc02c6d8e6698034722b1ff9419ad0c24ef068dea742edcff9f8ea4ba9
- languageName: node
- linkType: hard
-
"react-transition-group@npm:^4.4.1":
version: 4.4.1
resolution: "react-transition-group@npm:4.4.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-transition-group%2Fdownload%2Freact-transition-group-4.4.1.tgz"
@@ -10103,22 +10025,6 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
-"reactstrap@npm:^8.5.1":
- version: 8.5.1
- resolution: "reactstrap@npm:8.5.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Freactstrap%2Fdownload%2Freactstrap-8.5.1.tgz"
- dependencies:
- "@babel/runtime": ^7.2.0
- classnames: ^2.2.3
- prop-types: ^15.5.8
- react-popper: ^1.3.6
- react-transition-group: ^2.3.1
- peerDependencies:
- react: ^16.3.0
- react-dom: ^16.3.0
- checksum: afa5cba1a9ebff336ec4b7e8970bbffef2070cf7925e761a43cd499d441877866f181d46197545b9a55483809811f999efe1dd4628c3cd304754607833ba802e
- languageName: node
- linkType: hard
-
"read-pkg-up@npm:^2.0.0":
version: 2.0.0
resolution: "read-pkg-up@npm:2.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fread-pkg-up%2Fdownload%2Fread-pkg-up-2.0.0.tgz"
@@ -11657,7 +11563,6 @@ fsevents@~2.1.2:
"@types/react-router": ^5.1.8
"@types/react-router-bootstrap": ^0.24.5
"@types/react-router-dom": ^5.1.5
- "@types/reactstrap": ^8.5.1
"@types/webpack-env": ^1.15.2
"@types/xregexp": ^4.3.0
"@typescript-eslint/eslint-plugin": ^3.10.1
@@ -11705,7 +11610,6 @@ fsevents@~2.1.2:
react-router: ^5.2.0
react-router-bootstrap: ^0.25.0
react-router-dom: ^5.2.0
- reactstrap: ^8.5.1
regenerator-runtime: ^0.13.7
rxjs: ^6.6.2
sass: ^1.26.10
@@ -11948,13 +11852,6 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
-"typed-styles@npm:^0.0.7":
- version: 0.0.7
- resolution: "typed-styles@npm:0.0.7::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Ftyped-styles%2Fdownload%2Ftyped-styles-0.0.7.tgz"
- checksum: 4988d78dafc45bc0ad73393f767c7958aabe121a9310d5c864ad6e064fd8bc049ac9a16ca2b411640e94cc95f8af3a67c78771f5eab5c211fcb60ecb71fdd2b9
- languageName: node
- linkType: hard
-
"typedarray@npm:^0.0.6":
version: 0.0.6
resolution: "typedarray@npm:0.0.6::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Ftypedarray%2Fdownload%2Ftypedarray-0.0.6.tgz"
@@ -12301,7 +12198,7 @@ typescript@^4.0.2:
languageName: node
linkType: hard
-"warning@npm:^4.0.0, warning@npm:^4.0.2, warning@npm:^4.0.3":
+"warning@npm:^4.0.0, warning@npm:^4.0.3":
version: 4.0.3
resolution: "warning@npm:4.0.3::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fwarning%2Fdownload%2Fwarning-4.0.3.tgz"
dependencies: