Explorar o código

Merge branch 'dev/7.0.x' into imprv/133920-142527-replace-spinner-pulse-of-outside-app

Yuki Takei %!s(int64=2) %!d(string=hai) anos
pai
achega
2fbc6cee0b
Modificáronse 53 ficheiros con 1900 adicións e 2666 borrados
  1. 11 4
      apps/app/config/next-i18next.config.js
  2. 1 0
      apps/app/next-env.d.ts
  3. 1 1
      apps/app/next.config.js
  4. 12 14
      apps/app/package.json
  5. 0 253
      apps/app/resource/locales/en_US/sandbox-bootstrap4.md
  6. 169 0
      apps/app/resource/locales/en_US/sandbox-bootstrap5.md
  7. 7 10
      apps/app/resource/locales/en_US/sandbox-diagrams.md
  8. 110 391
      apps/app/resource/locales/en_US/sandbox.md
  9. 46 59
      apps/app/resource/locales/en_US/welcome.md
  10. 0 253
      apps/app/resource/locales/ja_JP/sandbox-bootstrap4.md
  11. 258 0
      apps/app/resource/locales/ja_JP/sandbox-bootstrap5.md
  12. 12 3
      apps/app/resource/locales/ja_JP/sandbox-diagrams.md
  13. 4 4
      apps/app/resource/locales/ja_JP/sandbox-math.md
  14. 192 329
      apps/app/resource/locales/ja_JP/sandbox.md
  15. 44 53
      apps/app/resource/locales/ja_JP/welcome.md
  16. 0 253
      apps/app/resource/locales/zh_CN/sandbox-bootstrap4.md
  17. 169 0
      apps/app/resource/locales/zh_CN/sandbox-bootstrap5.md
  18. 7 10
      apps/app/resource/locales/zh_CN/sandbox-diagrams.md
  19. 110 389
      apps/app/resource/locales/zh_CN/sandbox.md
  20. 46 59
      apps/app/resource/locales/zh_CN/welcome.md
  21. 30 9
      apps/app/src/client/services/side-effects/page-updated.ts
  22. 0 0
      apps/app/src/client/services/update-page/conflict.tsx
  23. 4 3
      apps/app/src/components/LoginForm.tsx
  24. 7 4
      apps/app/src/components/Page/DisplaySwitcher.tsx
  25. 20 8
      apps/app/src/components/PageAlert/OldRevisionAlert.tsx
  26. 48 119
      apps/app/src/components/PageEditor/PageEditor.tsx
  27. 58 0
      apps/app/src/components/PageEditor/PageEditorReadOnly.tsx
  28. 44 2
      apps/app/src/components/PageEditor/ScrollSyncHelper.tsx
  29. 135 0
      apps/app/src/components/PageEditor/conflict.tsx
  30. 37 98
      apps/app/src/components/PageStatusAlert.tsx
  31. 10 0
      apps/app/src/components/TableOfContents.module.scss
  32. 5 10
      apps/app/src/pages/_app.page.tsx
  33. 3 2
      apps/app/src/pages/_private-legacy-pages.page.tsx
  34. 7 4
      apps/app/src/pages/_search.page.tsx
  35. 3 2
      apps/app/src/pages/me/[[...path]].page.tsx
  36. 3 2
      apps/app/src/pages/tags.page.tsx
  37. 6 11
      apps/app/src/pages/trash.page.tsx
  38. 0 22
      apps/app/src/server/crowi/dev.js
  39. 1 0
      apps/app/src/server/models/vo/s2c-message.js
  40. 1 1
      apps/app/src/server/service/installer.ts
  41. 0 26
      apps/app/src/services/i18next-hmr.ts
  42. 39 0
      apps/app/src/stores/alert.tsx
  43. 0 4
      apps/app/src/stores/editor.tsx
  44. 0 5
      apps/app/src/styles/font-icons.scss
  45. 7 3
      apps/app/tsconfig.build.client.json
  46. 9 5
      packages/editor/src/components/CodeMirrorEditor/CodeMirrorEditor.tsx
  47. 39 0
      packages/editor/src/components/CodeMirrorEditorReadOnly.tsx
  48. 1 0
      packages/editor/src/components/index.ts
  49. 1 0
      packages/editor/src/consts/global-code-mirror-editor-key.ts
  50. 1 1
      packages/presentation/package.json
  51. 1 1
      packages/remark-lsx/package.json
  52. 1 1
      packages/ui/package.json
  53. 180 238
      yarn.lock

+ 11 - 4
apps/app/config/next-i18next.config.js

@@ -1,12 +1,14 @@
+const isDev = process.env.NODE_ENV === 'development';
+
 const path = require('path');
 
 const { AllLang, Lang } = require('@growi/core');
 const { isServer } = require('@growi/core/dist/utils');
-const I18nextChainedBackend = require('i18next-chained-backend').default;
-const I18NextHttpBackend = require('i18next-http-backend');
+const I18nextChainedBackend = isDev ? require('i18next-chained-backend').default : undefined;
+const I18NextHttpBackend = require('i18next-http-backend').default;
 const I18NextLocalStorageBackend = require('i18next-localstorage-backend').default;
 
-const isDev = process.env.NODE_ENV === 'development';
+const HMRPlugin = isDev ? require('i18next-hmr/plugin').HMRPlugin : undefined;
 
 module.exports = {
   defaultLang: Lang.en_US,
@@ -17,7 +19,12 @@ module.exports = {
   defaultNS: 'translation',
   localePath: path.resolve('./public/static/locales'),
   serializeConfig: false,
-  use: isServer() ? [] : [I18nextChainedBackend],
+  // eslint-disable-next-line no-nested-ternary
+  use: isDev
+    ? isServer()
+      ? [new HMRPlugin({ webpack: { server: true } })]
+      : [I18nextChainedBackend, new HMRPlugin({ webpack: { client: true } })]
+    : [],
   backend: {
     backends: isServer() ? [] : [I18NextLocalStorageBackend, I18NextHttpBackend],
     backendOptions: [

+ 1 - 0
apps/app/next-env.d.ts

@@ -1,5 +1,6 @@
 /// <reference types="next" />
 /// <reference types="next/image-types/global" />
+/// <reference types="next/navigation-types/compat/navigation" />
 
 // NOTE: This file should not be edited
 // see https://nextjs.org/docs/basic-features/typescript for more information.

+ 1 - 1
apps/app/next.config.js

@@ -120,7 +120,7 @@ module.exports = async(phase, { defaultConfig }) => {
 
       // setup i18next-hmr
       if (!options.isServer && options.dev) {
-        const { I18NextHMRPlugin } = require('i18next-hmr/plugin');
+        const { I18NextHMRPlugin } = require('i18next-hmr/webpack');
         config.plugins.push(new I18NextHMRPlugin({ localesDir: localePath }));
       }
 

+ 12 - 14
apps/app/package.json

@@ -55,8 +55,9 @@
     "@aws-skd/*": "fix version above 3.186.0 that is required by mongodb@4.16.0",
     "@keycloak/keycloak-admin-client": "19.0.0 or above exports only ESM.",
     "escape-string-regexp": "5.0.0 or above exports only ESM",
-    "string-width": "5.0.0 or above exports only ESM.",
-    "remark-wiki-link": "!!DO NOT REMOVE!! including 'mdast-util-wiki-link' and 'micromark-extension-wiki-link' required by pukiwiki-like-linker"
+    "next-themes": "0.3.0 causes a type error: https://github.com/pacocoursey/next-themes/issues/122",
+    "remark-wiki-link": "!!DO NOT REMOVE!! including 'mdast-util-wiki-link' and 'micromark-extension-wiki-link' required by pukiwiki-like-linker",
+    "string-width": "5.0.0 or above exports only ESM."
   },
   "dependencies": {
     "@akebifiky/remark-simple-plantuml": "^1.0.2",
@@ -123,10 +124,10 @@
     "hast-util-select": "^5.0.5",
     "helmet": "^4.6.0",
     "http-errors": "^2.0.0",
-    "i18next": "^22.4.10",
-    "i18next-chained-backend": "^4.0.0",
-    "i18next-http-backend": "^2.0.0",
-    "i18next-localstorage-backend": "^4.0.0",
+    "i18next": "^23.10.1",
+    "i18next-chained-backend": "^4.6.2",
+    "i18next-http-backend": "^2.5.0",
+    "i18next-localstorage-backend": "^4.2.0",
     "is-absolute-url": "^4.0.1",
     "is-iso-date": "^0.0.1",
     "ldapjs": "^3.0.2",
@@ -144,8 +145,8 @@
     "multer": "~1.4.0",
     "multer-autoreap": "^1.0.3",
     "mustache": "^4.2.0",
-    "next": "^13.3.0",
-    "next-i18next": "^13.2.1",
+    "next": "^14.1.3",
+    "next-i18next": "^15.2.0",
     "next-superjson": "^0.0.4",
     "next-themes": "^0.2.1",
     "nocache": "^3.0.1",
@@ -171,7 +172,7 @@
     "react-dnd-html5-backend": "^14.1.0",
     "react-dom": "^18.2.0",
     "react-error-boundary": "^3.1.4",
-    "react-i18next": "^12.2.0",
+    "react-i18next": "^14.1.0",
     "react-image-crop": "^8.3.0",
     "react-markdown": "^8.0.7",
     "react-multiline-clamp": "^2.0.0",
@@ -225,8 +226,7 @@
     "@growi/presentation": "link:../../packages/presentation",
     "@growi/ui": "link:../../packages/ui",
     "@handsontable/react": "=2.1.0",
-    "@icon/themify-icons": "1.0.1-alpha.3",
-    "@next/bundle-analyzer": "^13.2.3",
+    "@next/bundle-analyzer": "^14.1.3",
     "@swc-node/jest": "^1.6.2",
     "@swc/jest": "^0.2.24",
     "@testing-library/react": "^14.1.2",
@@ -249,11 +249,10 @@
     "eslint-plugin-cypress": "^2.12.1",
     "eslint-plugin-jest": "^26.5.3",
     "eslint-plugin-regex": "^1.8.0",
-    "font-awesome": "^4.7.0",
     "fslightbox-react": "^1.7.6",
     "handsontable": "=6.2.2",
     "happy-dom": "^13.2.0",
-    "i18next-hmr": "^1.11.0",
+    "i18next-hmr": "^3.0.4",
     "jest": "^29.5.0",
     "jest-date-mock": "^1.0.8",
     "jest-localstorage-mock": "^2.4.14",
@@ -273,7 +272,6 @@
     "rehype-rewrite": "^3.0.6",
     "replacestream": "^4.0.3",
     "sass": "^1.53.0",
-    "simple-line-icons": "^2.5.5",
     "simple-load-script": "^1.0.2",
     "simplebar-react": "^2.3.6",
     "socket.io-client": "^4.2.0",

+ 0 - 253
apps/app/resource/locales/en_US/sandbox-bootstrap4.md

@@ -1,253 +0,0 @@
-# Labels
-
-<span class="badge badge-primary">Primary</span>
-<span class="badge badge-secondary">Secondary</span>
-<span class="badge badge-success">Success</span>
-<span class="badge badge-info">Info</span>
-<span class="badge badge-warning">Warning</span>
-<span class="badge badge-danger">Danger</span>
-<span class="badge badge-light text-dark">Light</span>
-<span class="badge badge-dark">Dark</span>
-
-<span class="badge badge-blue">Blue</span>
-<span class="badge badge-indigo">Indigo</span>
-<span class="badge badge-purple">Purple</span>
-<span class="badge badge-pink">Pink</span>
-<span class="badge badge-red">Red</span>
-<span class="badge badge-orange">Orange</span>
-<span class="badge badge-yellow">Yellow</span>
-<span class="badge badge-green">Green</span>
-<span class="badge badge-teal">Teal</span>
-<span class="badge badge-cyan">Cyan</span>
-
-
-# Alerts
-
-<div class="alert alert-primary" role="alert">
-  This is a primary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-secondary" role="alert">
-  This is a secondary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-success" role="alert">
-  This is a success alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-danger" role="alert">
-  This is a danger alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-warning" role="alert">
-  This is a warning alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-info" role="alert">
-  This is a info alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-light text-dark" role="alert">
-  This is a light alert with <a href="#" class="alert-link text-dark">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-dark" role="alert">
-  This is a dark alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-
-# Cards
-
-<div class="d-flex">
-
-<div class="mr-3">
-<div class="card text-white bg-primary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Primary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-secondary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Secondary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-success mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Success card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-danger mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Danger card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-warning mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Warning card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-info mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Info card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card bg-light mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Light card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-dark mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Dark card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-</div>
-
-<div>
-<div class="card border-primary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-primary">
-    <h5 class="card-title">Primary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-secondary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-secondary">
-    <h5 class="card-title">Secondary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-success mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-success">
-    <h5 class="card-title">Success card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-danger mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-danger">
-    <h5 class="card-title">Danger card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-warning mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-warning">
-    <h5 class="card-title">Warning card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-info mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-info">
-    <h5 class="card-title">Info card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-light mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Light card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-dark mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-dark">
-    <h5 class="card-title">Dark card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-</div>
-
-</div>
-
-# Wells
-
-## Default well
-
-<div class="card card-body">Look, I'm in a well! </div>
-
-## Optional classes
-
-<div class="card card-body bg-primary text-light p-2">Look, I'm in a well! </div>
-
-# Typography
-
-## Lead body copy
-
-<p class="lead">Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus.</p>
-
-## Marked text
-
-You can use the mark tag to <mark>highlight</mark> text.
-
-## Small text
-
-<small>This line of text is meant to be treated as fine print.</small>
-
-## Alignment classes
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-left">Left aligned text.</p>
-    <p class="text-center">Center aligned text.</p>
-    <p class="text-right">Right aligned text.</p>
-    <p class="text-justify">Justified text.</p>
-    <p class="text-nowrap">No wrap text.</p>
-  </div>
-</div>
-
-## Transformation classes
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-lowercase">Lowercased text.</p>
-    <p class="text-uppercase">Uppercased text.</p>
-    <p class="text-capitalize">Capitalized text.</p>
-  </div>
-</div>
-
-
-# Helper classes
-
-## Contextual colors
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-muted">Fusce dapibus, tellus ac cursus commodo, tortor mauris nibh.</p>
-    <p class="text-light">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
-    <p class="text-secondary">Sed luctus venenatis tellus, in aliquam ligula scelerisque eget.</p>
-    <p class="text-dark">Ut vel lorem aliquet, rhoncus libero at, condimentum mi. Fusce pellentesque quam nec magna maximus porta.</p>
-    <p class="text-primary">Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
-    <p class="text-success">Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p>
-    <p class="text-info">Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
-    <p class="text-warning">Etiam porta sem malesuada magna mollis euismod.</p>
-    <p class="text-danger">Donec ullamcorper nulla non metus auctor fringilla.</p>
-  </div>
-</div>
-
-## Contextual backgrounds
-
-<div class="card">
-  <div class="card-body">
-    <p class="bg-light">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
-    <p class="bg-secondary text-white">Sed luctus venenatis tellus, in aliquam ligula scelerisque eget.</p>
-    <p class="bg-dark text-white">Ut vel lorem aliquet, rhoncus libero at, condimentum mi.</p>
-    <p class="bg-primary text-white">Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
-    <p class="bg-success text-white">Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p>
-    <p class="bg-info text-white">Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
-    <p class="bg-warning text-white">Etiam porta sem malesuada magna mollis euismod.</p>
-    <p class="bg-danger text-white">Donec ullamcorper nulla non metus auctor fringilla.</p>
-  </div>
-</div>

+ 169 - 0
apps/app/resource/locales/en_US/sandbox-bootstrap5.md

@@ -0,0 +1,169 @@
+# 1. Badges
+
+<span class="badge text-bg-primary">primary</span>  
+
+<span class="badge text-bg-secondary">secondary</span>  
+
+<span class="badge text-bg-success">success</span>  
+
+<span class="badge text-bg-danger">danger</span>  
+
+<span class="badge text-bg-warning">warning</span>  
+
+<span class="badge text-bg-info">info</span>  
+
+<span class="badge text-bg-light">light</span>  
+
+<span class="badge text-bg-dark">dark</span>  
+
+
+# 2. Alerts
+
+<div class="alert alert-primary" role="alert">
+  This is a primary alert.
+</div>
+
+<div class="alert alert-secondary" role="alert">
+  This is a secondary alert.
+</div>
+
+<div class="alert alert-success" role="alert">
+  This is a success alert.
+</div>
+
+<div class="alert alert-danger" role="alert">
+  This is a danger alert.
+</div>
+
+<div class="alert alert-warning" role="alert">
+  This is a warning alert.
+</div>
+
+<div class="alert alert-info" role="alert">
+  This is a info alert.
+</div>
+
+<div class="alert alert-light" role="alert">
+  This is a light alert.
+</div>
+
+<div class="alert alert-dark" role="alert">
+  This is a dark alert.
+</div>
+
+
+# 3. Cards
+
+<div class="card text-bg-primary mb-3" style="max-width: 50rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Primary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-secondary mb-3" style="max-width: 45rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Secondary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-success mb-3" style="max-width: 40rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Success card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-danger mb-3" style="max-width: 35rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Danger card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-warning mb-3" style="max-width: 30rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Warning card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-info mb-3" style="max-width: 25rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Info card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-light mb-3" style="max-width: 20rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Light card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-dark mb-3" style="max-width: 15rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Dark card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+
+# 4. Colors
+## 背景颜色
+<p class="text-primary">Look, I'm in a well!</p>
+<p class="text-warning">Look, I'm in a well!</p>
+<p class="text-danger">Look, I'm in a well!</p>
+
+## 背景情况
+<p class="text-danger bg-primary">Look, I'm in a well!</p>
+<p class="text-primary bg-warning">Look, I'm in a well!</p>
+<p class="text-warning bg-danger">Look, I'm in a well!</p>
+
+
+# 5. Collapse
+## 显示内容
+<a class="btn btn-primary text-white" data-bs-toggle="collapse" href="#collapse-1">
+  Show content
+</a>
+
+<div class="collapse" id="collapse-1">
+  <div class="card card-body">
+
+- Content you want to display
+  - Content you want to display
+      
+  </div>
+</div>
+
+## 隐藏内容
+<a class="btn btn-secondary text-white" data-bs-toggle="collapse" href="#collapse-2">
+  Hide content
+</a>
+
+<div class="collapse show" id="collapse-2">
+  <div class="card card-body">
+
+- Content you want to hide
+  - Content you want to hide
+
+  </div>
+</div>
+
+
+# 官方文件
+- [点击此处了解徽章详情](https://getbootstrap.com/docs/5.3/components/badge/)
+- [单击此处了解警报详情](https://getbootstrap.com/docs/5.3/components/alerts/)
+- [点击此处了解贺卡详情](https://getbootstrap.com/docs/5.3/components/card/)
+- [点击此处了解颜色详情](https://getbootstrap.com/docs/5.3/utilities/colors/)
+- [点击此处查看折叠详情](https://getbootstrap.com/docs/5.3/components/collapse/)

+ 7 - 10
apps/app/resource/locales/en_US/sandbox-diagrams.md

@@ -1,4 +1,4 @@
-# :pencil: diagrams.net(former Draw.io)
+# :pencil: diagrams.net(Draw.io)
 
 See [diagrams.net](https://diagrams.net)
 
@@ -15,7 +15,7 @@ See [diagrams.net](https://diagrams.net)
 ```
 
 
-## AWS diagram
+## AWS configuration diagram
 
 ``` drawio
 3Zhdb5swFIZ/TS4XYRswuUzSr0mtVqmtejkZOASvgJHtfO3Xz+YjgdJqiaa1SbnBvD7G9vv4IJsRmeeba8nK9E7EkI2wE29G5GKEMfa9wNyssq0VhFyvVhaSx422Fx74b2hEp1GXPAbVC9RCZJqXfTESRQGR7mlMSrHuhyUi6/dasgUMhIeIZUP1mcc6rdUA071+A3yRtj0jf1LX5KwNbmaiUhaLdUcilyMyl0LoupRv5pBZ91pf6nZX79TuBiah0G80eFIgf4S/rCfYyVhowFRBI+xFIi9FYZthr3WvVaqYGxZy2+xRsugFpCndPN7dmtu0LJtuMxZBaswE2Te4HR7ezXA3cqW3ravGi9IW883CrpsxWyt3nIuQ24BZwrNsLjIhq2CSJOBHkdGVluIFOjUxnYSOY2pWIDU30G7tPO+F4pqLwsSEQmuRmwCmynp1JHwDZoizerS2HWzeNRR1JnENIgcttyakafANuQ3aZnG7Ph37vk8d6pAgoBO3rl131k3TIO0smVZjjZGLXUd7mKbQ2Ng+dvD+M+6n7xatUqDVgXTJ8XQVGZLFlJqEeYtsUl2fRRb7Y+QEJCCIBhQ5ExL0OBPHOReyqsre6VKnRjM+Vu4dxtg9nnEkFgXXYgh6ThFBV6cHmgRj10XUo9jByA1c90vk8/TeJvQ107Bm2wNpe8fTZiX/uWg6GRD3psSZeadH/C+p7RNvTAhxzaedUuoFwbkgf34w4i3Lw5gdSNw/nnhWvf9nsiyimtWBH/TCjPSzgCP/FXH3SwC/YJqFTMGBsOnxsONtwXIRh0PK1q/Z5PRymzgni3qwfW86X7FsCS113KcSLeXKWnNhd7hQxFN7nNlnk1GuuO2yqo+ZSqtg9BYXPwogTHYuQzw49Lzy2AxELGUEnc28OXgxuQA93AF2SEjIzB5j1X/7EdYNfJqcuU/uB/nUnpfP1ijvo4xC52SUNzTK/yij8DkZ5Q+Nov/HKPO4/2lT1XX+fZHLPw==
@@ -27,8 +27,7 @@ See [diagrams.net](https://diagrams.net)
 
 See [PlantUML](http://plantuml.com/).
 
-## Sequence diagram
-
+## Sequence Diagram
 ``` plantuml
 @startuml
 skinparam sequenceArrowThickness 2
@@ -63,7 +62,6 @@ deactivate A
 
 
 ## Class diagram
-
 ``` plantuml
 @startuml
 
@@ -155,7 +153,7 @@ State3 --> [*] : Aborted
 
 # :pencil: Mermaid
 
-## Pie chart diagram
+## Pie graph
 
 ```mermaid
 %%{init: {"pie": {"textPosition": 0.5}, "themeVariables": {"pieOuterStrokeWidth": "5px"}} }%%
@@ -167,7 +165,7 @@ pie showData
     "Iron" :  5
 ```
 
-## Gantt diagram
+## Gantt chart
 
 ```mermaid
 gantt
@@ -181,7 +179,7 @@ gantt
     another task      : 24d
 ```
 
-## Gitgraph diagram
+## Git tree diagram
 
 ```mermaid
 %%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}} }%%
@@ -202,14 +200,13 @@ gitGraph
   commit
 ```
 
-## Mindmap diagram
+## Mind map
 
 ```mermaid
 mindmap
   root((mindmap))
     Origins
       Long history
-      ::icon(fa fa-book)
       Popularisation
         British popular psychology author Tony Buzan
     Research

+ 110 - 391
apps/app/resource/locales/en_US/sandbox.md

@@ -1,439 +1,158 @@
-# :memo: Table of Contents
+# What is Sandbox?
+- In this page, you will find tips that help you to master GROWI 
+- Feel free to enrich the content of your pages with the references under this hierarchy
 
-Add `ToC` after some `#` signs.
-`Table of Contents` or `Table-of-Contents` is also OK.
 
-```
-# ToC
-```
-
-## ToC
-
-# :memo: Block Elements
+# :closed_book:Headings & Paragraphs
+- By inserting headings and paragraphs, you can make the text on the page easier to read
 
 ## Headers
-
-Add one `#` per level at the start of the line
+- Add `#` before the heading text to create a heading 
+    - Depending on the number of `#`, the typeface size of headings would be different shown in the View screen 
+    - Check the View screen on the right side to understand the effect of headings
+- The number of `#` will decide the hierarchy level and help you to organize the contents
 
 ```
-# Header 1
-## Header 2
-### Header 3
-#### Header 4
-##### Header 5
-###### Header 6
+# First-level heading
+## Second-level heading
+### Third-level heading
+#### Forth-level heading
+##### Fifth-level heading
+###### Sixth-level heading
 ```
 
-### Header 3
+## Break
+- Insert two half-width spaces at the end of the sentence you want to break
+    - You can also change this in the Setting to break the line without half-width spaces
+        - Change the line break setting in the `Markdown Settings` sector of the admin page
 
-#### Header 4
+#### Without line break
+Paragraph 1
+Paragraph 2
 
-##### Header 5
+#### With line break
+Paragraph 1  
+Paragraph 2
 
-###### Header 6
+## Block
+- Paragraphs can be created by inserting a blank table in the text
+- Passage can be broken into sentences and make them easier to read
 
-## Block paragraph
+#### Without paragraph
+Paragraph 1  
+Paragraph 2
 
-Paragraphs are created by inserting a newline character
-A paragraph can be created by pressing Enter at the end of the previous paragraph.
+#### With paragraph
+Paragraph 1  
 
-```
-paragraph1
-(Blank line)
-paragraph2
-```
+Paragraph 2
 
-paragraph1
 
-paragraph2
+# :green_book: Styling Text
+- Various styles can be applied to enrich the textual expression of a sentence
+    - These styles also can be easily applied by selecting the toolbar icon at the bottom of the Edit screen
 
-## Br new line
+## Italic
+- Enclose the text with an asterisk `*` or an underscore `_`.
 
-Add two spaces before break.
-***This behavior can be modified in the options menu.***
+#### Examples
+- This sentence indicates emphasis with *Italic*
+- This sentence indicates emphasis with _Italic_ 
 
-```
-foo
-bar(two spaces)
-baz
-```
+## Bold
+- Enclose the text with two asterisks `*` or two underscores `_`
 
-foo
-bar
-baz
+#### Example
+- This sentence indicates emphasis with **Bold** 
+- This sentence indicates emphasis with __Bold__
 
-## Blockquotes
-
-Add one `>` per level at the start of the line
-
-```
-> quote
-> quote
->> nested quotes
-```
-
-> quote
-> quote
->> nested quotes
+## Italic & Bold
+- Enclose the text with three asterisks `*` or three underscores `_`
 
-## Code
+#### Example
+- This sentence indicates emphasis with ***Italic & Bold***
+- This sentence indicates emphasis witH ___Italic & Bold___
 
-Wrap code with three back quotes or tildes.
 
-```
-print 'foo'
-```
+# :orange_book: Insert Lists
+## Bulleted List
+- Insert a bulleted list by starting a line with a hyphen `-`, a plus `+`, or an asterisk `*`
 
-### Syntax highlight and file name
+#### Example
+- This sentence is present in the bulleted list
+    - This sentence is present in the bulleted list
+        - This sentence is present in the bulleted list
+        - This sentence is present in the bulleted list
+- This sentence is present in the bulleted list
+    - This sentence is present in the bulleted list
 
-- corresponding [highlight.js Demo](https://highlightjs.org/static/demo/) of common category
+## Numbered List
+- `Number.` at the beginning of a line to insert a numbered list
+- Numbered list and bulleted list can also be combined for use
 
+#### Example
+1. This sentence is present in the numbered list
+    1. This sentence is present in the numbered list
+    1. This sentence is present in the numbered list
+    1. This sentence is present in the numbered list
+        - This sentence is present in the bulleted list 
+1. This sentence is present in the bulleted list
+    - This sentence is present in the bulleted list
 
-~~~
-```javascript:mersenne-twister.js
-function MersenneTwister(seed) {
-  if (arguments.length == 0) {
-    seed = new Date().getTime();
-  }
+## Task List
+- Insert an unchecked checkbox list by writing `[] `
+    - Check the checkbox by writing `[x]`
 
-  this._mt = new Array(624);
-  this.setSeed(seed);
-}
-```
-~~~
+#### Example
+- [ ] Task 1
+    - [x] Task 1-1
+    - [ ] Task 1-2
+- [x] Task 2
 
-```javascript:mersenne-twister.js
-function MersenneTwister(seed) {
-  if (arguments.length == 0) {
-    seed = new Date().getTime();
-  }
 
-  this._mt = new Array(624);
-  this.setSeed(seed);
-}
-```
+# :blue_book: Others
+## Blockquotes
+- Use quoted expressions by putting `>` at the beginning of the paragraph
+    - Multiple quotations can be expressed by using a sequence of `>` characters
+- Lists and other elements can be used together within the blockquotes
 
-### Inline code
+#### Example
+> - Quotation
+> - Quotation
+>> Multiple quotations need to insert more `>`
 
-Words wrapped by `` `back quotes` `` will be formatted as inline code.
+## Code
+- It is possible to express the code by adding it in three `` ` ``
 
+#### Example
 ```
-This is `Inline Code`.
-```
-
-This is  `Inline Code`.
-
-## Pre-arranged text
+Add codes here  
+Line breaks and paragraphs can be reflected in the code
 
-Code blocks should be preceded by four spaces or one tab.
-
-```
-    class Foo
-        def foo
-            print 'foo'
-        end
-    end
+- List also can be used in code
+    - List also can be used in code
 ```
 
-    class Foo
-        def foo
-            print 'foo'
-        end
-    end
+## Inline Code
+- Enclose words in `` ` `` to make inline code
 
-## Horizontal Line
+#### Example
+Here is the `inline code` 
 
-Write three underscores `_`, or asterisks`*`.
+## Horizontal lines
+- Insert the horizontal line with three or more consecutive asterisks `*` or underscores `_`
 
-```
+#### Example
+Below is a horizontal line
 ***
-___
----
-```
 
-***
+Below is a horizontal line
 ___
----
-
-
-
-# :memo: Typography
-
-## Strong Text
-
-### Italic
-
-To italicize text, add one asterisk or underscores before and after a word or phrase.
-
-```
-This is *Italic* .
-This is _Italic_ .
-```
-
-This is *Italic* .
-This is _Italic_ .
-
-### Bold
-
-To make text bold, add two asterisks or underscores before and after a word or phrase.
-
-```
-This is **bold**.
-This is __bold__.
-```
-
-This is **bold**.
-This is __bold__.
-
-### Bold + Italic
-
-To bold and italicize text, add three asterisks or underscores before and after a word or phrase.
-
-```
-This is ***Italic & Bold***.
-This is ___Italic & Bold___.
-```
-
-This is ***Italic & Bold***.
-This is ___Italic & Bold___.
-
-# :memo: Images
-
-You can insert `<img>` tag using `![description](URL)`.
-
-```markdown
-![Minion](https://octodex.github.com/images/minion.png)
-![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")
-```
-
-![Minion](https://octodex.github.com/images/minion.png)
-![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")
-
-The size of the image can be set by using an HTML image tag
-
-```html
-<img src="https://octodex.github.com/images/dojocat.jpg" width="200px">
-```
-
-<img src="https://octodex.github.com/images/dojocat.jpg" width="200px">
-
-
-# :memo: Link
-
-## Markdown standard
-
-You can create links using `[Display text](URL)`.
-
-```
-[Google](https://www.google.co.jp/)
-```
-
-[Google](https://www.google.co.jp/)
-
-## Pukiwiki like linker
-
-This is the most flexible linker.
-Both the page description and link address can be displayed on the page.
-
-```
-[[./Bootstrap4]]
-Example of Bootstrap4 is [[here>./Bootstrap4]]
-```
-
-[[./Bootstrap4]]  
-Example of Bootstrap4 is [[here>./Bootstrap4]]
-
-# :memo: Lists
-
-## Ul Bulleted list
-
-To create an unordered list, add dashes (-), asterisks (*), or plus signs (+) in front of line items.
-Items can be nested using indentation.
-
-```
-- List1
-    - List1_1
-        - List1_1_1
-        - List1_1_2
-    - List1_2
-- List2
-- List3
-```
-
-- List1
-    - List1_1
-        - List1_1_1
-        - List1_1_2
-    - List1_2
-- List2
-- List3
-
-## Ol Numbered List
-
-To create an ordered list, add line items with numbers followed by periods.
-The numbers don’t have to be in numerical order, but the list should start with the number one.
-
-```
-1. Number list 1
-    1. Number list 1-1
-    1. Number list 1-2
-1. Number list 2
-1. Number list 3
-```
-
-1. Number list 1
-    1. Number list 1-1
-    1. Number list 1-2
-1. Number list 2
-1. Number list 3
-
-
-## Check list
-
-```
-- [ ] Task 1
-    - [x] Task 1.1
-    - [ ] Task 1.2
-- [x] Task2
-```
-
-- [ ] Task 1
-    - [x] Task 1.1
-    - [ ] Task 1.2
-- [x] Task2
-
-
-# :memo: Table
-
-## Markdown Standard
-
-```markdown
-| Left align | Right align | Center align |
-|:-----------|------------:|:------------:|
-| This       | This        | This         |
-| column     | column      | column       |
-| will       | will        | will         |
-| be         | be          | be           |
-| left       | right       | center       |
-| aligned    | aligned     | aligned      |
-
-OR
-
-Left align | Right align | Center align
-:--|--:|:-:
-This       | This        | This
-column     | column      | column
-will       | will        | will
-be         | be          | be
-left       | right       | center
-aligned    | aligned     | aligned
-```
-
-| Left align | Right align | Center align |
-|:-----------|------------:|:------------:|
-| This       | This        | This         |
-| column     | column      | column       |
-| will       | will        | will         |
-| be         | be          | be           |
-| left       | right       | center       |
-| aligned    | aligned     | aligned      |
-
-## TSV
-
-~~~
-``` tsv
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-~~~
-
-``` tsv
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-
-## TSV with header
-
-~~~
-``` tsv-h
-First Header	Second Header
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-~~~
-
-``` tsv-h
-First Header	Second Header
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-
-## CSV
-
-~~~
-``` csv
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-~~~
-
-``` csv
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-
-## CSV with header
-
-~~~
-``` csv-h
-First Header,Second Header
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-~~~
-
-``` csv-h
-First Header,Second Header
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-
-
-# :memo: Footnote
-
-You can write a reference [^1] to a footnote.
-
-Long footnotes can be written as [^longnote].
-
-[^1]: A_reference_to_the_first_footnote.
-
-[^longnote]: An_example_of_writing_a_footnote_in_multiple_blocks.
-
-    Subsequent paragraphs are indented and belong to the previous footnote.
-
-
-# :memo: Emoji
-
-:smiley: :smile: :laughing: :innocent: :drooling_face:
-
-:family: :man-boy: :man-girl: :man-girl-girl: :woman-girl-girl:
-
-:+1: :-1: :open_hands: :raised_hands: :point_right:
-
-:apple: :green_apple: :strawberry: :cake: :hamburger:
-
-:basketball: :football: :baseball: :volleyball: :8ball:
-
-:hearts: :broken_heart: :heartbeat: :heartpulse: :heart_decoration:
 
-:watch: :gear: :gem: :wrench: :email:
 
+# :ledger: More Applications
+- [Bootstrap5](/Sandbox/Bootstrap5)
 
-# :heavy_plus_sign: More..
+- [Diagrams](/Sandbox/Diagrams)
 
-- Want to attach Bootstrap4 Tags?
-    - :arrow_right: [/Sandbox/Bootstrap4]
-- Want to draw Diagrams?
-    - :arrow_right: [/Sandbox/Diagrams]
-- Want to write Math Formulas?
-    - :arrow_right: [/Sandbox/Math]
+- [Math](/Sandbox/Math)

+ 46 - 59
apps/app/resource/locales/en_US/welcome.md

@@ -1,64 +1,51 @@
-# :tada: Welcome to GROWI
+# :tada: Welcome to GROWI 
 
-[![GitHub Releases](https://img.shields.io/github/release/weseek/growi.svg)](https://github.com/weseek/growi/releases/latest)
-[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/weseek/growi/blob/master/LICENSE)
+GROWI is an internal wiki & knowledge base tool for corporations and individuals.  
+With GROWI, members can easily share and edit information in a company, university seminar, or circle.
 
-GROWI is a Wiki for Individuals and Corporations | A knowledge base tool.
-Knowledge in companies, university laboratories, and clubs can be easily shared and anyone can edit the page.
+Casually writing down the information you know and editing it together can **reduce tacit knowledge within the team**.  
+Let's increase the amount of information shared on a daily base!
 
-We can easily write what we know and edit it together, we can **simplify the tacit knowledge (knowledge which is hard to explain with words) in our team**.  
-Let's increase the information exchange everyday.
-
-### :beginner: How to create a page easily 
-
-- Start from "**Create**" button on the upper right, or the **Pencil Icon** on the lower right.
-    - The page title can be edited again later, don't worry about the title.
-        - On title input field, it's possible to create the page's hierarchy with half-width `/` (slash).
-        - (Example)Try entering `/category1/category2/page-title-we-want-to-create`.
-- We can create a bullet point by adding `-`  at the beginning of the line.
-- We can also copy and paste, drag and drop attachments such as images, PDF, Word/Excel/PowerPoint, etc.
-- Once we finished, press the "**Update**" button to publish the page.
-    - We can also save it by `Ctrl(⌘) + S`.
-
-For more information: [Create page](https://docs.growi.org/en/guide/features/create_page.html)
-
-<div class="mt-4 card border-primary">
-  <div class="card-header bg-primary text-light">
-    Tips
-  </div>
-  <div class="card-body">
-    <ul>
-      <li>Ctrl(⌘) + "/" to show quick help.</li>
-      <li>We can write HTML with <a href="https://getbootstrap.com/docs/4.6/components/">Bootstrap 4</a>.</li>
-    </ul>
-  </div>
+<div class="alert alert-primary" role="alert">
+※Feel free to edit and use this page as the top page of the wiki.
 </div>
 
-# :anchor: For administrator <small>〜After you construct the site〜</small>
-
-### :arrow_right: Do you will use a Wiki with more than one person?
-- :heavy_check_mark: Let's invite some members.
-    - [Add/invite new members to the Wiki](https://docs.growi.org/en/admin-guide/management-cookbook/user-management.html#temporary-issuance-of-a-new-user)
-### :arrow_right: Work with Slack to receive page and comment notifications.
-- :heavy_check_mark:  [Slack integration](https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/#overview)
-### :arrow_right: Are you switching from another system?
-- :heavy_check_mark: It's possible to import data from other GROWI, esa.io, Qiita:Team.
-    -  [Import Data](https://docs.growi.org/en/admin-guide/management-cookbook/import.html)
-
-For more information: [Admin Guide](https://docs.growi.org/en/admin-guide/)
-
-
-# Content List Example
-
-We can display the content list using a table and `$lsx`.
-
-| All page list (First 15 pages)      | [/Sandbox] List of subordinate pages |
-| ----------------------------------- | ------------------------------------ |
-| $lsx(/,num=15)                      | $lsx(/Sandbox)                       |
-
-# Slack
-
-<a href="https://communityinviter.com/apps/wsgrowi/invite/">join our Slack team</a>
-
-We welcome newcomers joining our slack channel to help improve GROWI.
-In addition to discussing development, we are also happy to answer your questions when you join.
+# :beginner: What can you do with GROWI?
+## 1. Knowledge Management: Create pages to store information and knowledge
+- How to create and edit pages?
+    - You can create a new page from the "Pencil Icon" in the upper left corner of the screen
+    - You can edit a page you have already created by clicking "Edit" in the upper right corner of the screen
+- How to manage pages?
+    - GROWI manages pages in a **hierarchical** structure
+        - Example: ` /page A/page B/page C ` 
+    - Apart from Hierarchy, pages can also be managed with Tags
+
+## 2. Information Retrieval: Search information in various ways
+- Keyword search
+- Search using various sidebars
+    - Search by Page Tree
+    - Search by Latest Changes
+    - Search by Tag, and more...
+
+## 3. Information Sharing: Easy to share both internally and externally
+- You can send the URL and permalink of the page to your company members
+    - User Groups can be used to manage viewing privileges among members of the company
+- GROWI also allows pages to be viewed by users outside the company who do not have an account
+    - Let's share information with users outside your company using shared links!
+
+#### :bulb: Check [Sndbox](/Sandbox) to learn more on how to edit pages!
+
+
+# :wrench: For Administrators - Once GROWI is created
+
+### :arrow_right: Wanna use GROWI with multiple people?
+- :heavy_check_mark: Invite your members!
+    - [Add or invite new members to GROWI](https://docs.growi.org/en/admin-guide/management-cookbook/user-management.html#temporary-issuance-of-a-new-user)
+
+### :arrow_right: Not satisfied with the current look of GROWI?
+- :heavy_check_mark: No worry! Let's customize the theme of GROWI!
+    - [Customizing GROWI Themes](/admin/customize)
+
+### :arrow_right: GROWI security settings are not completed?
+- :heavy_check_mark: Come to update your GROWI security settings!
+    - [Update GROWI security settings](/admin/security)

+ 0 - 253
apps/app/resource/locales/ja_JP/sandbox-bootstrap4.md

@@ -1,253 +0,0 @@
-# Labels
-
-<span class="badge badge-primary">Primary</span>
-<span class="badge badge-secondary">Secondary</span>
-<span class="badge badge-success">Success</span>
-<span class="badge badge-info">Info</span>
-<span class="badge badge-warning">Warning</span>
-<span class="badge badge-danger">Danger</span>
-<span class="badge badge-light text-dark">Light</span>
-<span class="badge badge-dark">Dark</span>
-
-<span class="badge badge-blue">Blue</span>
-<span class="badge badge-indigo">Indigo</span>
-<span class="badge badge-purple">Purple</span>
-<span class="badge badge-pink">Pink</span>
-<span class="badge badge-red">Red</span>
-<span class="badge badge-orange">Orange</span>
-<span class="badge badge-yellow">Yellow</span>
-<span class="badge badge-green">Green</span>
-<span class="badge badge-teal">Teal</span>
-<span class="badge badge-cyan">Cyan</span>
-
-
-# Alerts
-
-<div class="alert alert-primary" role="alert">
-  This is a primary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-secondary" role="alert">
-  This is a secondary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-success" role="alert">
-  This is a success alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-danger" role="alert">
-  This is a danger alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-warning" role="alert">
-  This is a warning alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-info" role="alert">
-  This is a info alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-light text-dark" role="alert">
-  This is a light alert with <a href="#" class="alert-link text-dark">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-dark" role="alert">
-  This is a dark alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-
-# Cards
-
-<div class="d-flex">
-
-<div class="mr-3">
-<div class="card text-white bg-primary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Primary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-secondary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Secondary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-success mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Success card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-danger mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Danger card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-warning mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Warning card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-info mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Info card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card bg-light mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Light card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-dark mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Dark card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-</div>
-
-<div>
-<div class="card border-primary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-primary">
-    <h5 class="card-title">Primary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-secondary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-secondary">
-    <h5 class="card-title">Secondary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-success mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-success">
-    <h5 class="card-title">Success card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-danger mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-danger">
-    <h5 class="card-title">Danger card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-warning mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-warning">
-    <h5 class="card-title">Warning card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-info mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-info">
-    <h5 class="card-title">Info card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-light mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Light card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-dark mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-dark">
-    <h5 class="card-title">Dark card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-</div>
-
-</div>
-
-# Wells
-
-## Default well
-
-<div class="card card-body">Look, I'm in a well! </div>
-
-## Optional classes
-
-<div class="card card-body bg-primary text-light p-2">Look, I'm in a well! </div>
-
-# Typography
-
-## Lead body copy
-
-<p class="lead">Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus.</p>
-
-## Marked text
-
-You can use the mark tag to <mark>highlight</mark> text.
-
-## Small text
-
-<small>This line of text is meant to be treated as fine print.</small>
-
-## Alignment classes
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-left">Left aligned text.</p>
-    <p class="text-center">Center aligned text.</p>
-    <p class="text-right">Right aligned text.</p>
-    <p class="text-justify">Justified text.</p>
-    <p class="text-nowrap">No wrap text.</p>
-  </div>
-</div>
-
-## Transformation classes
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-lowercase">Lowercased text.</p>
-    <p class="text-uppercase">Uppercased text.</p>
-    <p class="text-capitalize">Capitalized text.</p>
-  </div>
-</div>
-
-
-# Helper classes
-
-## Contextual colors
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-muted">Fusce dapibus, tellus ac cursus commodo, tortor mauris nibh.</p>
-    <p class="text-light">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
-    <p class="text-secondary">Sed luctus venenatis tellus, in aliquam ligula scelerisque eget.</p>
-    <p class="text-dark">Ut vel lorem aliquet, rhoncus libero at, condimentum mi. Fusce pellentesque quam nec magna maximus porta.</p>
-    <p class="text-primary">Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
-    <p class="text-success">Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p>
-    <p class="text-info">Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
-    <p class="text-warning">Etiam porta sem malesuada magna mollis euismod.</p>
-    <p class="text-danger">Donec ullamcorper nulla non metus auctor fringilla.</p>
-  </div>
-</div>
-
-## Contextual backgrounds
-
-<div class="card">
-  <div class="card-body">
-    <p class="bg-light">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
-    <p class="bg-secondary text-white">Sed luctus venenatis tellus, in aliquam ligula scelerisque eget.</p>
-    <p class="bg-dark text-white">Ut vel lorem aliquet, rhoncus libero at, condimentum mi.</p>
-    <p class="bg-primary text-white">Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
-    <p class="bg-success text-white">Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p>
-    <p class="bg-info text-white">Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
-    <p class="bg-warning text-white">Etiam porta sem malesuada magna mollis euismod.</p>
-    <p class="bg-danger text-white">Donec ullamcorper nulla non metus auctor fringilla.</p>
-  </div>
-</div>

+ 258 - 0
apps/app/resource/locales/ja_JP/sandbox-bootstrap5.md

@@ -0,0 +1,258 @@
+# Bootstrap について
+- GROWI では [Bootstrap](https://getbootstrap.jp/docs/5.3/getting-started/introduction/)(Bootstrap5)を活用して文章やテキストの装飾をすることが可能です
+- 以下にて紹介する代表的な Bootstrap をそのまま引用し活用していただくことが可能です
+
+# 1. バッジ(Badges)
+
+<span class="badge text-bg-primary">テキスト</span>  
+
+<span class="badge text-bg-secondary">テキスト</span>  
+
+<span class="badge text-bg-success">テキスト</span>  
+
+<span class="badge text-bg-danger">テキスト</span>  
+
+<span class="badge text-bg-warning">テキスト</span>  
+
+<span class="badge text-bg-info">テキスト</span>  
+
+<span class="badge text-bg-light">テキスト</span>  
+
+<span class="badge text-bg-dark">テキスト</span>  
+
+---
+
+#### 活用例
+
+- 入社してすぐにやることリスト
+    1. 自己紹介文を記載してください <span class="badge text-bg-danger">必須</span>  
+    2. 振込先口座情報を記載してください <span class="badge text-bg-danger">必須</span>  
+    3. SNS アカウントを記載してください <span class="badge text-bg-secondary">任意</span>  
+
+---
+
+
+
+
+# 2. アラート(Alerts)
+
+<div class="alert alert-primary" role="alert">
+  テキストが入ります
+</div>
+
+<div class="alert alert-secondary" role="alert">
+  テキストが入ります
+</div>
+
+<div class="alert alert-success" role="alert">
+  テキストが入ります
+</div>
+
+<div class="alert alert-danger" role="alert">
+  テキストが入ります
+</div>
+
+<div class="alert alert-warning" role="alert">
+  テキストが入ります
+</div>
+
+<div class="alert alert-info" role="alert">
+  テキストが入ります
+</div>
+
+<div class="alert alert-light" role="alert">
+  テキストが入ります
+</div>
+
+<div class="alert alert-dark" role="alert">
+  テキストが入ります
+</div>
+
+---
+
+#### 活用例
+
+<div class="alert alert-danger" role="alert">
+  ※こちらの情報はチーム長以上の役職のメンバー以外は編集しないでください※
+</div>
+
+---
+
+
+
+
+# 3. カード(Cards)
+
+<div class="card text-bg-primary mb-3" style="max-width: 50rem;">
+  <div class="card-header">見出しが入ります</div>
+  <div class="card-body">
+    <h5 class="card-title">小見出しが入ります</h5>
+    <p class="card-text">テキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
+  </div>
+</div>
+
+<div class="card text-bg-secondary mb-3" style="max-width: 45rem;">
+  <div class="card-header">見出しが入ります</div>
+  <div class="card-body">
+    <h5 class="card-title">小見出しが入ります</h5>
+    <p class="card-text">テキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
+  </div>
+</div>
+
+<div class="card text-bg-success mb-3" style="max-width: 40rem;">
+  <div class="card-header">見出しが入ります</div>
+  <div class="card-body">
+    <h5 class="card-title">小見出しが入ります</h5>
+    <p class="card-text">テキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
+  </div>
+</div>
+
+<div class="card text-bg-danger mb-3" style="max-width: 35rem;">
+  <div class="card-header">見出しが入ります</div>
+  <div class="card-body">
+    <h5 class="card-title">小見出しが入ります</h5>
+    <p class="card-text">テキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
+  </div>
+</div>
+
+<div class="card text-bg-warning mb-3" style="max-width: 30rem;">
+  <div class="card-header">見出しが入ります</div>
+  <div class="card-body">
+    <h5 class="card-title">小見出しが入ります</h5>
+    <p class="card-text">テキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
+  </div>
+</div>
+
+<div class="card text-bg-info mb-3" style="max-width: 25rem;">
+  <div class="card-header">見出しが入ります</div>
+  <div class="card-body">
+    <h5 class="card-title">小見出しが入ります</h5>
+    <p class="card-text">テキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
+  </div>
+</div>
+
+<div class="card text-bg-light mb-3" style="max-width: 20rem;">
+  <div class="card-header">見出しが入ります</div>
+  <div class="card-body">
+    <h5 class="card-title">小見出しが入ります</h5>
+    <p class="card-text">テキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
+  </div>
+</div>
+
+<div class="card text-bg-dark mb-3" style="max-width: 15rem;">
+  <div class="card-header">見出しが入ります</div>
+  <div class="card-body">
+    <h5 class="card-title">小見出しが入ります</h5>
+    <p class="card-text">テキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
+  </div>
+</div>
+
+---
+
+#### 活用例
+
+<div class="card text-bg-warning mb-3" style="max-width: 40rem;">
+  <div class="card-header">一口コラム</div>
+  <div class="card-body">
+    <h5 class="card-title">日本で最初のカレーライスのレシピとは?</h5>
+    <p class="card-text">日本で初めてカレーライスの調理法が紹介されたのは、1872年(明治5年)に出版された「西洋料理指南」という本でした。</p>
+    <p class="card-text">使用する食材として「ネギ・ショウガ・ニンニク・バター・エビ・タイ・鶏・小麦粉・カレー粉」などが挙げられています。</p>
+  </div>
+</div>
+
+---
+
+
+
+
+# 4. カラー(Colors)
+## テキストカラー
+<p class="text-primary">テキストはこちら</p>
+<p class="text-warning">テキストはこちら</p>
+<p class="text-danger">テキストはこちら</p>
+
+## 背景カラー
+<p class="bg-primary">テキストはこちら</p>
+<p class="bg-warning">テキストはこちら</p>
+<p class="bg-danger">テキストはこちら</p>
+
+## テキスト&背景カラー
+<p class="text-danger bg-primary">テキストはこちら</p>
+<p class="text-primary bg-warning">テキストはこちら</p>
+<p class="text-warning bg-danger">テキストはこちら</p>
+
+---
+
+#### 活用例
+
+- <p class="text-danger">プロジェクトにアサインされる場合はスタートアップを完了させておきましょう</p>
+- <p class="bg-warning">分からないことがあればまとめて質問しましょう</p>
+
+---
+
+
+
+
+# 5. コラプス(Collapse)
+- コラプスはコンテンツの 表示 / 非表示 の切り替えの際に活用できます
+
+## コンテンツの表示
+<a class="btn btn-primary text-white" data-bs-toggle="collapse" href="#collapse-1">
+  コンテンツを表示する
+</a>
+
+<div class="collapse" id="collapse-1">
+  <div class="card card-body">
+
+- 表示させたいコンテンツの内容が入ります
+  - 表示させたいコンテンツの内容が入ります
+      
+  </div>
+</div>
+
+
+## コンテンツの非表示
+<a class="btn btn-secondary text-white" data-bs-toggle="collapse" href="#collapse-2">
+  コンテンツを非表示にする
+</a>
+
+<div class="collapse show" id="collapse-2">
+  <div class="card card-body">
+
+- 非表示にさせたいコンテンツの内容が入ります
+  - 非表示にさせたいコンテンツの内容が入ります
+
+  </div>
+</div>
+
+
+#### 活用例
+<a class="btn btn-warning text-white" data-bs-toggle="collapse" href="#collapse-3">
+  最終順位を確認する!
+</a>
+
+<div class="collapse" id="collapse-3">
+  <div class="card card-body">
+
+##### 優勝者は **Bさん** です!!
+
+| 対象者 | 点数 | 順位 |
+| ------ | ---- | ---- |
+| Aさん  | 80pt | 2位  |
+| Bさん  | 95pt | 1位  |
+| Cさん  | 70pt | 3位  |
+      
+  </div>
+</div>
+
+
+
+
+
+
+# 公式ドキュメント
+- [バッジの詳細はこちら](https://getbootstrap.jp/docs/5.3/components/badge/)
+- [アラートの詳細はこちら](https://getbootstrap.jp/docs/5.3/components/alerts/)
+- [カード詳細はこちら](https://getbootstrap.jp/docs/5.3/components/card/)
+- [カラーの詳細はこちら](https://getbootstrap.jp/docs/5.3/utilities/colors/)
+- [コラプスの詳細はこちら](https://getbootstrap.jp/docs/5.3/components/collapse/)

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 12 - 3
apps/app/resource/locales/ja_JP/sandbox-diagrams.md


+ 4 - 4
apps/app/resource/locales/ja_JP/sandbox-math.md

@@ -1,10 +1,10 @@
-# :pencil: Math
-
-See [KaTeX](https://katex.org/).
+# Math について
+- GROWI では  [MathJax](https://www.mathjax.org/) を活用して文章内に数式を挿入することが可能です
+- 以下にて紹介する代表的な MathJax の記法をそのまま引用し活用することが可能です
 
 ## Inline Formula
 
-When $a \ne 0$, there are two solutions to $ax^2 + bx + c = 0$ and they are
+When $a \ne 0$, there are two solutions to $ax^2 + bx + c = 0$ and they are  
   $$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$
 
 ## The Lorenz Equations

+ 192 - 329
apps/app/resource/locales/ja_JP/sandbox.md

@@ -1,19 +1,16 @@
-# :memo: 目次
+# Sandbox(サンドボックス)とは
+- この階層下では、GROWI をより便利に活用するための活用術や活用ヒントを掲載しています
+- この階層下のページ内容を組織内で自由に書き換えて GROWI の理解度を深めるために活用しましょう!
 
-いくつかの `#` 記号に続けて `ToC` という文字列を記述します。  
-`Table of Contents` または `Table-of-Contents` でも構いません。
 
-```
-# ToC
-```
-
-## ToC
+# :memo:見出しや段落
+- 見出しや段落を挿入することで、ページ内の文章にメリハリがつき読みやすい文章を作成することが可能です
 
-# :memo: Block Elements
-
-## Headers 見出し
-
-先頭に`#`をレベルの数だけ記述します。
+## 見出し(Headers)
+- 行頭に `#` をレベルの数だけ記述することで見出しを作成することが可能です
+    - 各見出しに応じて View 画面に表示される際のデザインも異なります
+    - 各見出しに応じて View 画面右側に表示される目次が生成されます
+- このページ内にもたくさんの見出しが活用されており、`#` の数に応じて内容をグルーピングすることで可能です
 
 ```
 # 見出し1
@@ -24,382 +21,253 @@
 ###### 見出し6
 ```
 
-### 見出し3
-
-#### 見出し4
-
-##### 見出し5
-
-###### 見出し6
+## 改行(Br)
+- 改行したい文章の行末に半角スペースを2つ挿入することで改行をすることができます
+    - こちらの挙動は、設定画面から半角スペースなしで改行が反映されるように設定を変更することが可能です
+        - 「マークダウン設定_Line Break設定(/admin/markdown)」から変更が可能です
 
-## Block 段落
+#### 改行がない場合
+文章 1 の内容が入ります
+文章 2 の内容が入ります
 
-空白行を挟むことで段落となります。
+#### 改行がある場合
+文章 1 の内容が入ります  
+文章 2 の内容が入ります
 
-```
-段落1
-(空行)
-段落2
-```
+## 段落(Block)
+- 文章内で空白表を挿入することで段落を作成することが可能です
+- 段落を作成することで文章の節目を作成し読みやすい文章を作成することができます
 
-段落1
+#### 段落がない場合
+文章 1 の内容が入ります  
+文章 2 の内容が入ります
 
-段落2
+#### 段落がある場合
+文章 1 の内容が入ります  
 
-## Br 改行
+文章 2 の内容が入ります
 
-改行の前に半角スペース``を2つ記述します。
-***この挙動は、オプションで変更可能です***
 
-```
-hoge
-fuga(スペース2つ)
-piyo
-```
+# :memo:文字の強調
+- 各種記述方法を適用させることで文内の文字の表現を豊かにすることが可能です
+    - これらの表現は Edit 画面下部のツールバーから該当のアイコンを選択することで簡単に適用させることも可能です
 
-hoge
-fuga
-piyo
+## 斜体(Italic)
+- アスタリスク `*` もしくはアンダースコア `_` 1つで該当の文字列を囲みます
 
-## Blockquotes 引用
+#### 活用例
+- この文章は *斜体が適用* されます  
+- この文章は _斜体が適用_ されます
 
-先頭に`>`を記述します。ネストは`>`を多重に記述します。
+## 太字(Bold)
+- アスタリスク `*` もしくはアンダースコア `_` 2つで該当の文字列を囲みます
 
-```
-> 引用
-> 引用
->> 多重引用
-```
+#### 活用例
+- この文章は **強調が適用** されます  
+- この文章は __強調が適用__ されます
 
-> 引用
-> 引用
->> 多重引用
+## 斜体 & 太字(Italic & Bold)
+- アスタリスク `*` もしくはアンダースコア `_` 3つで該当の文字列を囲みます
 
-## Code コード
+#### 活用例
+- この文章は ***斜体 & 太字が適用*** されます  
+- この文章は ___斜体 & 太字が適用___ されます
 
-`` `バッククオート` `` 3つ、あるいはチルダ`~`3つで囲みます。
 
-```
-print 'hoge'
-```
+# :memo:リストの挿入
+## 箇条書きリスト
+- ハイフン `-`、プラス `+`、アスタリスク `*` を行頭に記述することで、箇条書きのリストを挿入することでができます
+    - タブを活用することで前の行のリストに紐づくリストを挿入することも可能です
 
-### シンタックスハイライトとファイル名
-
-- [highlight.js Demo](https://highlightjs.org/static/demo/) の common カテゴリ内の言語に対応しています
+#### 活用例
+- この文章は箇条書きリストで表現しています
+    - この文章は箇条書きリストで表現しています
+        - この文章は箇条書きリストで表現しています
+        - この文章は箇条書きリストで表現しています
+- この文章は箇条書きリストで表現しています
+    - この文章は箇条書きリストで表現しています
 
+## 番号付きリスト
+- `番号.` を行頭に記述することで、番号付きのリストを挿入することができます
+    - タブを活用することで前の行のリストに紐づくリストを挿入することも可能です
+- 番号付きリストと箇条書きリストを組み合わせて活用することも可能です
 
-~~~
-```javascript:mersenne-twister.js
-function MersenneTwister(seed) {
-  if (arguments.length == 0) {
-    seed = new Date().getTime();
-  }
-
-  this._mt = new Array(624);
-  this.setSeed(seed);
-}
-```
-~~~
-
-```javascript:mersenne-twister.js
-function MersenneTwister(seed) {
-  if (arguments.length == 0) {
-    seed = new Date().getTime();
-  }
-
-  this._mt = new Array(624);
-  this.setSeed(seed);
-}
-```
+#### 活用例
+1. この文章は番号付きリストで表現しています
+    1. この文章は番号付きリストで表現しています
+    1. この文章は番号付きリストで表現しています
+    1. この文章は番号付きリストで表現しています
+        - この文章は箇条書きリストで表現しています 
+1. この文章は箇条書きリストで表現しています
+    - この文章は箇条書きリストで表現しています  
 
-### インラインコード
-
-`` `バッククオート` `` で単語を囲むとインラインコードになります。
-
-```
-これは `インラインコード`です。
-```
-
-これは `インラインコード`です。
-
-## pre 整形済みテキスト
-
-半角スペース4個もしくはタブで、コードブロックをpre表示できます
-
-```
-    class Hoge
-        def hoge
-            print 'hoge'
-        end
-    end
-```
-
-    class Hoge
-        def hoge
-            print 'hoge'
-        end
-    end
-
-## Hr 水平線
-
-アンダースコア`_` 、アスタリスク`*`を3つ以上連続して記述します。
-
-```
-***
-___
----
-```
-
-***
-___
----
-
-
-
-# :memo: Typography
-
-## 強調
-
-### em
-
-アスタリスク`*`もしくはアンダースコア`_`1個で文字列を囲みます。
+## タスクリスト
+- `[] ` を記述することでリストに対して未チェックのチェックボックスを挿入することができます
+    - `[x] ` を記述することでチェック済みのチェックボックスを挿入することができます
 
-```
-これは *イタリック* です
-これは _イタリック_ です
-```
+#### 活用例
+- [ ] タスク 1
+    - [x] タスク 1-1
+    - [ ] タスク 1-2
+- [x] タスク2
 
-これは *イタリック* です
-これは _イタリック_ です
 
-### strong
+# :memo:表の挿入
+## Markdown 標準
+- Markdown で記載できる標準的な形式の表です
 
-アスタリスク`*`もしくはアンダースコア`_`2個で文字列を囲みます。
+#### 活用例
+| 左揃え               |               右揃え |        中央揃え        |
+| :------------------- | -------------------: | :--------------------: |
+| この列は             |             この列は |        この列は        |
+| 左揃えで表示されます | 右揃えで表示されます | 中央揃えで表示されます |
 
+## TSV
+#### 活用例
+``` tsv
+10:00	集合
+10:20	移動
 ```
-これは **ボールド** です
-これは __ボールド__ です
-```
-
-これは **ボールド** です
-これは __ボールド__ です
 
-### em + strong
-
-アスタリスク`*`もしくはアンダースコア`_`3個で文字列を囲みます。
-
-```
-これは ***イタリック&ボールド*** です
-これは ___イタリック&ボールド___ です
+## TSV(ヘッダー付き)
+#### 活用例
+``` tsv-h
+時間	行動
+10:00	集合
+10:20	移動
 ```
 
-これは ***イタリック&ボールド*** です
-これは ___イタリック&ボールド___ です
-
-# :memo: Images
-
-`![Alt文字列](URL)` で`<img>`タグを挿入できます。
-
-```markdown
-![Minion](https://octodex.github.com/images/minion.png)
-![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")
+## CSV
+#### 活用例
+``` csv
+11:00,MTG
+12:00,昼食
 ```
 
-![Minion](https://octodex.github.com/images/minion.png)
-![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")
-
-画像の大きさなどの指定をする場合はimgタグを使用します。
-
-```html
-<img src="https://octodex.github.com/images/dojocat.jpg" width="200px">
+## CSV(ヘッダー付き)
+#### 活用例
+``` csv-h
+時間,行動
+11:00,MTG
+12:00,昼食
 ```
 
-<img src="https://octodex.github.com/images/dojocat.jpg" width="200px">
-
-
-# :memo: Link
 
+# :memo:リンクの挿入
 ## Markdown 標準
+- Markdown で記載できる標準的な形式のリンクです
+- `[表示されるテキスト](リンク先のURL)`でリンクに変換されます
 
-`[表示テキスト](URL)`でリンクに変換されます。
-
-```
-[Google](https://www.google.co.jp/)
-```
-
+#### 活用例
 [Google](https://www.google.co.jp/)
 
 ## Pukiwiki like linker
+- もっとも柔軟なリンクの形式です
+- 記述中のページを基点とした相対リンクと、表示テキストに対するリンクを同時に実現できます
 
-最も柔軟な Linker です。
-記述中のページを基点とした相対リンクと、表示テキストに対するリンクを同時に実現できます。
+#### 活用例
+Bootstrap によるページの装飾方法の記述方法は [[こちらをご確認ください>./1. ページの装飾方法(Bootstrap)]]
 
-```
-[[./Bootstrap4]]
-Bootstrap4のExampleは[[こちら>./Bootstrap4]]
-```
 
-[[./Bootstrap4]]  
-Bootstrap4のExampleは[[こちら>./Bootstrap4]]
+# :memo:画像の挿入
+## 画像(Images)の挿入
+- `![Alt文字列](URL)` で`<img>`タグを挿入できます
 
-# :memo: Lists
+#### 活用例
+![Minion](https://octodex.github.com/images/minion.png)
 
-## Ul 箇条書きリスト
+## 画像のサイズ指定
+- 画像の大きさなどを指定する場合はimgタグを使用します
 
-ハイフン`-`、プラス`+`、アスタリスク`*`のいずれかを先頭に記述します。
-ネストはタブで表現します。
+#### 活用例
+<img src="https://octodex.github.com/images/dojocat.jpg" width="500px">
 
-```
-- リスト1
-    - リスト1_1
-        - リスト1_1_1
-        - リスト1_1_2
-    - リスト1_2
-- リスト2
-- リスト3
-```
 
-- リスト1
-    - リスト1_1
-        - リスト1_1_1
-        - リスト1_1_2
-    - リスト1_2
-- リスト2
-- リスト3
+# :memo:コンテンツやページの表示
+## 目次(ToC)
+- いくつかの `#` 記号に続けて `ToC` を記述することでページ内に目次を生成することができます
+    - `ToC` は `Table of Contents` または `Table-of-Contents` でも適用されます
+- 生成される目次は、ページ内で `ToC` を記述した以降の部分の目次となります
 
-## Ol 番号付きリスト
+#### 活用例
+##### ToC
 
-`番号.`を先頭に記述します。ネストはタブで表現します。
-番号は自動的に採番されるため、すべての行を1.と記述するのがお勧めです。
+## 配下ページの表示(lsx)
+- ページ内に `$lsx()` を記述することで配下に作成されているページを表示することができます
+- 各種オプションを指定することで表示される配下ページを操作することができます
+    - lsx の詳細は [GROWI 公式ドキュメント](https://docs.growi.org/ja/guide/features/lsx.html) をご確認ください
 
-```
-1. 番号付きリスト1
-    1. 番号付きリスト1-1
-    1. 番号付きリスト1-2
-1. 番号付きリスト2
-1. 番号付きリスト3
-```
+#### 活用例
+$lsx()
 
-1. 番号付きリスト1
-    1. 番号付きリスト1-1
-    1. 番号付きリスト1-2
-1. 番号付きリスト2
-1. 番号付きリスト3
+# :memo:その他の基本的な表現
+## 引用(Blockquotes)
+- 行頭に `>` を記述することで引用表現をすることが可能です
+    - 多重引用の際は `>` を複数個連続で記述することで表現が可能です
+- 引用内でリストなどの要素を併用することも可能です
 
+#### 活用例
+> - 引用する文章が入ります
+> - 引用する文章が入ります
+>> 多重引用したい文章の場合は複数個の挿入が必要です
 
-## タスクリスト
+## コード(Code)
+- `` ` `` 3つで囲むことでコードの表現をすることが可能です
 
+#### 活用例
 ```
-- [ ] タスク 1
-    - [x] タスク 1.1
-    - [ ] タスク 1.2
-- [x] タスク2
-```
-
-- [ ] タスク 1
-    - [x] タスク 1.1
-    - [ ] タスク 1.2
-- [x] タスク2
-
-
-# :memo: Table
+コードが入ります  
+改行や段落をコード内で反映させることが可能です
 
-## Markdown 標準
-
-```markdown
-| Left align | Right align | Center align |
-|:-----------|------------:|:------------:|
-| This       | This        | This         |
-| column     | column      | column       |
-| will       | will        | will         |
-| be         | be          | be           |
-| left       | right       | center       |
-| aligned    | aligned     | aligned      |
-
-OR
-
-Left align | Right align | Center align
-:--|--:|:-:
-This       | This        | This
-column     | column      | column
-will       | will        | will
-be         | be          | be
-left       | right       | center
-aligned    | aligned     | aligned
+- リストもコード内での表現が可能です
+    - リストもコード内での表現が可能です
 ```
 
-| Left align | Right align | Center align |
-|:-----------|------------:|:------------:|
-| This       | This        | This         |
-| column     | column      | column       |
-| will       | will        | will         |
-| be         | be          | be           |
-| left       | right       | center       |
-| aligned    | aligned     | aligned      |
-
-## TSV
+## インラインコード
+- `` ` `` で単語を囲むとインラインコードになります
 
-~~~
-``` tsv
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-~~~
+#### 活用例
+こちらは `インラインコード` です
 
-``` tsv
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-
-## TSV (ヘッダー付き)
-
-~~~
-``` tsv-h
-First Header	Second Header
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-~~~
-
-``` tsv-h
-First Header	Second Header
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
+## シンタックスハイライトとファイル名
+- [highlight.js Demo](https://highlightjs.org/static/demo/) の common カテゴリ内の言語に対応しています
 
-## CSV
+#### 活用例 
+```javascript:mersenne-twister.js
+function MersenneTwister(seed) {
+  if (arguments.length == 0) {
+    seed = new Date().getTime();
+  }
 
-~~~
-``` csv
-Content Cell,Content Cell
-Content Cell,Content Cell
+  this._mt = new Array(624);
+  this.setSeed(seed);
+}
 ```
-~~~
 
-``` csv
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
+## pre 整形済みテキスト
+- 半角スペース4個もしくはタブで、コードブロックを pre 表示できます
 
-## CSV (ヘッダー付き)
+#### 活用例
+    class Hoge
+        def hoge
+            print 'hoge'
+        end
+    end
 
-~~~
-``` csv-h
-First Header,Second Header
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-~~~
+## 水平線(Hr)
+- アスタリスク `*` もしくはアンダースコア `_` を3つ以上連続して記述することで水平線を挿入できます
 
-``` csv-h
-First Header,Second Header
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
+#### 活用例
+以下に水平線が挿入されます
+***
 
+以下に水平線が挿入されます
+___
 
-# :memo: Footnote
+## 脚注(Footnote)
+- 脚注 `[^1]` と脚注への参照 `[^1]:` を作成することができます
 
+#### 活用例
 脚注への参照[^1]を書くことができます。
 
 長い脚注は[^longnote]のように書くことができます。
@@ -410,9 +278,7 @@ Content Cell,Content Cell
 
     後続の段落はインデントされて、前の脚注に属します。
 
-
-# :memo: Emoji
-
+## 絵文字(Emoji)
 :smiley: :smile: :laughing: :innocent: :drooling_face:
 
 :family: :man-boy: :man-girl: :man-girl-girl: :woman-girl-girl:
@@ -428,12 +294,9 @@ Content Cell,Content Cell
 :watch: :gear: :gem: :wrench: :email:
 
 
+# :memo:さらに応用的な表現
+- [ページの装飾方法(Bootstrap5)](/Sandbox/Bootstrap5)
 
-# :heavy_plus_sign: 更に…
+- [図形の表現方法(Daigrams)](/Sandbox/Daigrams)
 
-- Bootstrap4 のタグを使う
-    - :arrow_right: [/Sandbox/Bootstrap4]
-- 図表を書く
-    - :arrow_right: [/Sandbox/Diagrams]
-- 数式を書く
-    - :arrow_right: [/Sandbox/Math]
+- [数式の表現方法(Math)](/Sandbox/Math)

+ 44 - 53
apps/app/resource/locales/ja_JP/welcome.md

@@ -1,60 +1,51 @@
 # :tada: GROWI へようこそ
-[![GitHub Releases](https://img.shields.io/github/release/weseek/growi.svg)](https://github.com/weseek/growi/releases/latest)
-[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/weseek/growi/blob/master/LICENSE)
 
-GROWI は個人・法人向けの Wiki | ナレッジベースツールです。  
+GROWI は法人・個人向けの wiki | ナレッジベースツールです。  
 会社や大学の研究室、サークルでのナレッジ情報を簡単に共有でき、作られたページは誰でも編集が可能です。
 
 知っている情報をカジュアルに書き出しみんなで編集することで、**チーム内での暗黙知を減らす**ことができます。  
-当たり前に共有される情報を日々増やしていきましょう。
-
-### :beginner: 簡単なページの作り方
-
-- 右上の "**作成**"ボタンまたは右下の**鉛筆アイコン**のボタンからページを書き始めることができます
-    - ページタイトルは後から変更できますので、適当に入力しても大丈夫です
-        - タイトル入力欄では、半角の `/` (スラッシュ) でページ階層を作れます
-        - (例)`/カテゴリ1/カテゴリ2/作りたいページタイトル` のように入力してみてください
-- `- ` を行頭につけると、この文章のような箇条書きを書くことができます
-- 画像やPDF、Word/Excel/PowerPointなどの添付ファイルも、コピー&ペースト、ドラッグ&ドロップで貼ることができます
-- 書けたら "**更新**" ボタンを押してページを公開しましょう
-    - `Ctrl(⌘) + S` でも保存できます
-
-さらに詳しくはこちら: [ページを作成する](https://docs.growi.org/ja/guide/features/create_page.html)
-
-<div class="mt-4 card border-primary">
-  <div class="card-header bg-primary text-light">Tips</div>
-  <div class="card-body"><ul>
-    <li>Ctrl(⌘) + "/" でショートカットヘルプを表示します</li>
-    <li>HTML/CSS の記述には、<a href="https://getbootstrap.com/docs/4.6/components/">Bootstrap 4</a> を利用できます</li>
-  </ul></div>
-</div>
-
-
-# :anchor: 管理者の方へ <small>〜Wikiを作ったら〜</small>
-
-### :arrow_right: 複数人でWikiを使いますか?
-- :heavy_check_mark: メンバーを招待しましょう
-    - [Wikiに新しいメンバーを追加・招待する](https://docs.growi.org/ja/admin-guide/management-cookbook/user-management.html#%E6%96%B0%E8%A6%8F%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E4%BB%AE%E7%99%BA%E8%A1%8C)
-### :arrow_right: Slackと連携してページやコメントの通知を受け取りましょう
-- :heavy_check_mark:  [Slack連携](https://docs.growi.org/ja/admin-guide/management-cookbook/slack-integration/#%E6%A6%82%E8%A6%81)
-### :arrow_right: 他のシステムからの乗り換えですか?
-- :heavy_check_mark: 他の GROWI、esa. io、Qiita:Team のデータをインポートすることが出来ます
-    -  [データのインポート](https://docs.growi.org/ja/admin-guide/management-cookbook/import.html)
-
-さらに詳しくはこちら: [管理者ガイド](https://docs.growi.org/ja/admin-guide/)
-
+当たり前に共有される情報を日々増やしていきましょう!
 
-# コンテンツリストアップ例
-
-テーブルと `$lsx` を使ってコンテンツリストを表示できます。
-
-| 全てのページリスト (First 15 pages) | [/Sandbox] 配下ページ一覧 |
-| ----------------------------------- | ------------------------- |
-| $lsx(/,num=15)                      | $lsx(/Sandbox)            |
-
-# Slack
-
-<a href="https://communityinviter.com/apps/wsgrowi/invite/">join our Slack team</a>
+<div class="alert alert-primary" role="alert">
+※こちらのページは wiki の TOP ページとして自由に編集してご活用ください
+</div>
 
-GROWI をより良いものにするために、是非 Slack に参加してください。  
-開発に関する議論を行っている他、導入時の質問等も受け付けています。
+# :beginner: GROWI でできること
+## 1. **【情報の蓄積】** ページを作成し情報やナレッジの蓄積ができます
+- ページの作成と編集方法 
+    - 画面左上の「鉛筆アイコン」から新規でページを作成することが可能です
+    - 作成済みのページは画面右上の「Edit」からページを編集することが可能です
+- ページの管理方法
+    - GROWI ではページを「階層構造」で管理します
+        - ` /ページa/ページb/ページc ` のような構造
+    - 「階層構造」とは別に「タグ」でもページを管理することが可能です
+
+## 2. **【情報の検索】** 情報やナレッジは様々な方法で検索できます
+- キーワード検索
+- 各種サイドバーを活用した検索
+    - 「ページツリー」からの検索
+    - 「最新の変更」からの検索
+    - 「タグ」からの検索 など…
+
+## 3. **【情報の共有】** 情報やナレッジは社内外を問わず簡単に共有可能です
+- 社内のメンバーに対してはページの URL やパーマリンクを送ることで共有が可能です
+    - 社内のメンバー内でも「ユーザーグループ」を活用することで閲覧権限の管理をすることが可能です
+- アカウントを保有していない社外のユーザーのページ閲覧を可能にすることも可能です
+    - 「共有リンク」を活用し社外のユーザーに情報を共有しましょう
+
+#### :bulb:ページの編集方法が分からないときは [Snadbox](/Sandbox) を確認してみましょう!
+
+
+# :wrench:管理者の方へ ~ GROWI を作成したら~
+
+### :arrow_right: 複数人で GROWI を使いますか?
+- :heavy_check_mark: メンバーを招待しましょう!
+    - [GROWI に新しいメンバーを追加・招待する](https://docs.growi.org/ja/admin-guide/management-cookbook/user-management.html#%E6%96%B0%E8%A6%8F%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E4%BB%AE%E7%99%BA%E8%A1%8C)
+
+### :arrow_right: GROWI の見た目はこのままで満足ですか?
+- :heavy_check_mark: GROWI の見た目をカスタイマイズしましょう!
+    - [GROWI のテーマをカスタイマイズする](/admin/customize)
+
+### :arrow_right: GROWI のセキュリティ設定は完了していますか?
+- :heavy_check_mark: GROWI のセキュリティ設定を更新しましょう!
+    - [GROWI のセキュリティ設定を更新する](/admin/security)

+ 0 - 253
apps/app/resource/locales/zh_CN/sandbox-bootstrap4.md

@@ -1,253 +0,0 @@
-# Labels
-
-<span class="badge badge-primary">Primary</span>
-<span class="badge badge-secondary">Secondary</span>
-<span class="badge badge-success">Success</span>
-<span class="badge badge-info">Info</span>
-<span class="badge badge-warning">Warning</span>
-<span class="badge badge-danger">Danger</span>
-<span class="badge badge-light text-dark">Light</span>
-<span class="badge badge-dark">Dark</span>
-
-<span class="badge badge-blue">Blue</span>
-<span class="badge badge-indigo">Indigo</span>
-<span class="badge badge-purple">Purple</span>
-<span class="badge badge-pink">Pink</span>
-<span class="badge badge-red">Red</span>
-<span class="badge badge-orange">Orange</span>
-<span class="badge badge-yellow">Yellow</span>
-<span class="badge badge-green">Green</span>
-<span class="badge badge-teal">Teal</span>
-<span class="badge badge-cyan">Cyan</span>
-
-
-# Alerts
-
-<div class="alert alert-primary" role="alert">
-  This is a primary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-secondary" role="alert">
-  This is a secondary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-success" role="alert">
-  This is a success alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-danger" role="alert">
-  This is a danger alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-warning" role="alert">
-  This is a warning alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-info" role="alert">
-  This is a info alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-light text-dark" role="alert">
-  This is a light alert with <a href="#" class="alert-link text-dark">an example link</a>. Give it a click if you like.
-</div>
-<div class="alert alert-dark" role="alert">
-  This is a dark alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
-</div>
-
-# Cards
-
-<div class="d-flex">
-
-<div class="mr-3">
-<div class="card text-white bg-primary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Primary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-secondary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Secondary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-success mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Success card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-danger mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Danger card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-warning mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Warning card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-info mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Info card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card bg-light mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Light card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card text-white bg-dark mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Dark card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-</div>
-
-<div>
-<div class="card border-primary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-primary">
-    <h5 class="card-title">Primary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-secondary mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-secondary">
-    <h5 class="card-title">Secondary card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-success mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-success">
-    <h5 class="card-title">Success card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-danger mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-danger">
-    <h5 class="card-title">Danger card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-warning mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-warning">
-    <h5 class="card-title">Warning card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-info mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-info">
-    <h5 class="card-title">Info card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-light mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body">
-    <h5 class="card-title">Light card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-<div class="card border-dark mb-3" style="max-width: 18rem;">
-  <div class="card-header">Header</div>
-  <div class="card-body text-dark">
-    <h5 class="card-title">Dark card title</h5>
-    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-  </div>
-</div>
-</div>
-
-</div>
-
-# Wells
-
-## Default well
-
-<div class="card card-body">Look, I'm in a well! </div>
-
-## Optional classes
-
-<div class="card card-body bg-primary text-light p-2">Look, I'm in a well! </div>
-
-# Typography
-
-## Lead body copy
-
-<p class="lead">Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus.</p>
-
-## Marked text
-
-You can use the mark tag to <mark>highlight</mark> text.
-
-## Small text
-
-<small>This line of text is meant to be treated as fine print.</small>
-
-## Alignment classes
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-left">Left aligned text.</p>
-    <p class="text-center">Center aligned text.</p>
-    <p class="text-right">Right aligned text.</p>
-    <p class="text-justify">Justified text.</p>
-    <p class="text-nowrap">No wrap text.</p>
-  </div>
-</div>
-
-## Transformation classes
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-lowercase">Lowercased text.</p>
-    <p class="text-uppercase">Uppercased text.</p>
-    <p class="text-capitalize">Capitalized text.</p>
-  </div>
-</div>
-
-
-# Helper classes
-
-## Contextual colors
-
-<div class="card">
-  <div class="card-body">
-    <p class="text-muted">Fusce dapibus, tellus ac cursus commodo, tortor mauris nibh.</p>
-    <p class="text-light">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
-    <p class="text-secondary">Sed luctus venenatis tellus, in aliquam ligula scelerisque eget.</p>
-    <p class="text-dark">Ut vel lorem aliquet, rhoncus libero at, condimentum mi. Fusce pellentesque quam nec magna maximus porta.</p>
-    <p class="text-primary">Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
-    <p class="text-success">Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p>
-    <p class="text-info">Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
-    <p class="text-warning">Etiam porta sem malesuada magna mollis euismod.</p>
-    <p class="text-danger">Donec ullamcorper nulla non metus auctor fringilla.</p>
-  </div>
-</div>
-
-## Contextual backgrounds
-
-<div class="card">
-  <div class="card-body">
-    <p class="bg-light">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
-    <p class="bg-secondary text-white">Sed luctus venenatis tellus, in aliquam ligula scelerisque eget.</p>
-    <p class="bg-dark text-white">Ut vel lorem aliquet, rhoncus libero at, condimentum mi.</p>
-    <p class="bg-primary text-white">Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
-    <p class="bg-success text-white">Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p>
-    <p class="bg-info text-white">Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
-    <p class="bg-warning text-white">Etiam porta sem malesuada magna mollis euismod.</p>
-    <p class="bg-danger text-white">Donec ullamcorper nulla non metus auctor fringilla.</p>
-  </div>
-</div>

+ 169 - 0
apps/app/resource/locales/zh_CN/sandbox-bootstrap5.md

@@ -0,0 +1,169 @@
+# 1. Badges
+
+<span class="badge text-bg-primary">primary</span>  
+
+<span class="badge text-bg-secondary">secondary</span>  
+
+<span class="badge text-bg-success">success</span>  
+
+<span class="badge text-bg-danger">danger</span>  
+
+<span class="badge text-bg-warning">warning</span>  
+
+<span class="badge text-bg-info">info</span>  
+
+<span class="badge text-bg-light">light</span>  
+
+<span class="badge text-bg-dark">dark</span>  
+
+
+# 2. Alerts
+
+<div class="alert alert-primary" role="alert">
+  This is a primary alert.
+</div>
+
+<div class="alert alert-secondary" role="alert">
+  This is a secondary alert.
+</div>
+
+<div class="alert alert-success" role="alert">
+  This is a success alert.
+</div>
+
+<div class="alert alert-danger" role="alert">
+  This is a danger alert.
+</div>
+
+<div class="alert alert-warning" role="alert">
+  This is a warning alert.
+</div>
+
+<div class="alert alert-info" role="alert">
+  This is a info alert.
+</div>
+
+<div class="alert alert-light" role="alert">
+  This is a light alert.
+</div>
+
+<div class="alert alert-dark" role="alert">
+  This is a dark alert.
+</div>
+
+
+# 3. Cards
+
+<div class="card text-bg-primary mb-3" style="max-width: 50rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Primary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-secondary mb-3" style="max-width: 45rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Secondary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-success mb-3" style="max-width: 40rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Success card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-danger mb-3" style="max-width: 35rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Danger card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-warning mb-3" style="max-width: 30rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Warning card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-info mb-3" style="max-width: 25rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Info card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-light mb-3" style="max-width: 20rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Light card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+<div class="card text-bg-dark mb-3" style="max-width: 15rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body">
+    <h5 class="card-title">Dark card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+
+
+# 4. Colors
+## 背景颜色
+<p class="text-primary">Look, I'm in a well!</p>
+<p class="text-warning">Look, I'm in a well!</p>
+<p class="text-danger">Look, I'm in a well!</p>
+
+## 背景情况
+<p class="text-danger bg-primary">Look, I'm in a well!</p>
+<p class="text-primary bg-warning">Look, I'm in a well!</p>
+<p class="text-warning bg-danger">Look, I'm in a well!</p>
+
+
+# 5. Collapse
+## 显示内容
+<a class="btn btn-primary text-white" data-bs-toggle="collapse" href="#collapse-1">
+  Show content
+</a>
+
+<div class="collapse" id="collapse-1">
+  <div class="card card-body">
+
+- Content you want to display
+  - Content you want to display
+      
+  </div>
+</div>
+
+## 隐藏内容
+<a class="btn btn-secondary text-white" data-bs-toggle="collapse" href="#collapse-2">
+  Hide content
+</a>
+
+<div class="collapse show" id="collapse-2">
+  <div class="card card-body">
+
+- Content you want to hide
+  - Content you want to hide
+
+  </div>
+</div>
+
+
+# 官方文件
+- [点击此处了解徽章详情](https://getbootstrap.com/docs/5.3/components/badge/)
+- [单击此处了解警报详情](https://getbootstrap.com/docs/5.3/components/alerts/)
+- [点击此处了解贺卡详情](https://getbootstrap.com/docs/5.3/components/card/)
+- [点击此处了解颜色详情](https://getbootstrap.com/docs/5.3/utilities/colors/)
+- [点击此处查看折叠详情](https://getbootstrap.com/docs/5.3/components/collapse/)

+ 7 - 10
apps/app/resource/locales/zh_CN/sandbox-diagrams.md

@@ -1,4 +1,4 @@
-# :pencil: diagrams.net(former Draw.io)
+# :pencil: diagrams.net(Draw.io)
 
 See [diagrams.net](https://diagrams.net)
 
@@ -15,7 +15,7 @@ See [diagrams.net](https://diagrams.net)
 ```
 
 
-## AWS diagram
+## AWS configuration diagram
 
 ``` drawio
 3Zhdb5swFIZ/TS4XYRswuUzSr0mtVqmtejkZOASvgJHtfO3Xz+YjgdJqiaa1SbnBvD7G9vv4IJsRmeeba8nK9E7EkI2wE29G5GKEMfa9wNyssq0VhFyvVhaSx422Fx74b2hEp1GXPAbVC9RCZJqXfTESRQGR7mlMSrHuhyUi6/dasgUMhIeIZUP1mcc6rdUA071+A3yRtj0jf1LX5KwNbmaiUhaLdUcilyMyl0LoupRv5pBZ91pf6nZX79TuBiah0G80eFIgf4S/rCfYyVhowFRBI+xFIi9FYZthr3WvVaqYGxZy2+xRsugFpCndPN7dmtu0LJtuMxZBaswE2Te4HR7ezXA3cqW3ravGi9IW883CrpsxWyt3nIuQ24BZwrNsLjIhq2CSJOBHkdGVluIFOjUxnYSOY2pWIDU30G7tPO+F4pqLwsSEQmuRmwCmynp1JHwDZoizerS2HWzeNRR1JnENIgcttyakafANuQ3aZnG7Ph37vk8d6pAgoBO3rl131k3TIO0smVZjjZGLXUd7mKbQ2Ng+dvD+M+6n7xatUqDVgXTJ8XQVGZLFlJqEeYtsUl2fRRb7Y+QEJCCIBhQ5ExL0OBPHOReyqsre6VKnRjM+Vu4dxtg9nnEkFgXXYgh6ThFBV6cHmgRj10XUo9jByA1c90vk8/TeJvQ107Bm2wNpe8fTZiX/uWg6GRD3psSZeadH/C+p7RNvTAhxzaedUuoFwbkgf34w4i3Lw5gdSNw/nnhWvf9nsiyimtWBH/TCjPSzgCP/FXH3SwC/YJqFTMGBsOnxsONtwXIRh0PK1q/Z5PRymzgni3qwfW86X7FsCS113KcSLeXKWnNhd7hQxFN7nNlnk1GuuO2yqo+ZSqtg9BYXPwogTHYuQzw49Lzy2AxELGUEnc28OXgxuQA93AF2SEjIzB5j1X/7EdYNfJqcuU/uB/nUnpfP1ijvo4xC52SUNzTK/yij8DkZ5Q+Nov/HKPO4/2lT1XX+fZHLPw==
@@ -27,8 +27,7 @@ See [diagrams.net](https://diagrams.net)
 
 See [PlantUML](http://plantuml.com/).
 
-## Sequence diagram
-
+## Sequence Diagram
 ``` plantuml
 @startuml
 skinparam sequenceArrowThickness 2
@@ -63,7 +62,6 @@ deactivate A
 
 
 ## Class diagram
-
 ``` plantuml
 @startuml
 
@@ -155,7 +153,7 @@ State3 --> [*] : Aborted
 
 # :pencil: Mermaid
 
-## Pie chart diagram
+## Pie graph
 
 ```mermaid
 %%{init: {"pie": {"textPosition": 0.5}, "themeVariables": {"pieOuterStrokeWidth": "5px"}} }%%
@@ -167,7 +165,7 @@ pie showData
     "Iron" :  5
 ```
 
-## Gantt diagram
+## Gantt chart
 
 ```mermaid
 gantt
@@ -181,7 +179,7 @@ gantt
     another task      : 24d
 ```
 
-## Gitgraph diagram
+## Git tree diagram
 
 ```mermaid
 %%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}} }%%
@@ -202,14 +200,13 @@ gitGraph
   commit
 ```
 
-## Mindmap diagram
+## Mind map
 
 ```mermaid
 mindmap
   root((mindmap))
     Origins
       Long history
-      ::icon(fa fa-book)
       Popularisation
         British popular psychology author Tony Buzan
     Research

+ 110 - 389
apps/app/resource/locales/zh_CN/sandbox.md

@@ -1,439 +1,160 @@
-# :memo: Table of Contents
+# 什么是沙盒?
+- 在本页中,您可以找到帮助您掌握 GROWI 的技巧。
+- 您可以在此层级下的参考资料中丰富您的网页内容
 
-Add `ToC` after some `#` signs.
-`Table of Contents` or `Table-of-Contents` is also OK.
 
-```
-# ToC
-```
-
-## ToC
-
-# :memo: Block Elements
-
-## Headers
+# :closed_book:标题和段落
+- 通过插入标题和段落,可以使页面上的文字更易于阅读
 
-Add one `#` per level at the start of the line
+## 标题
+- 在标题文字前添加 `#` 以创建标题 
+    - 在 "视图 "屏幕中,标题的字体大小会因 "#"的数量而异 
+    - 查看右侧的 "视图 "屏幕,了解标题的效果
+- `#`的数量将决定层次结构的级别,并帮助您组织内容
 
 ```
-# Header 1
-## Header 2
-### Header 3
-#### Header 4
-##### Header 5
-###### Header 6
+# 一级标题
+## 二级标题
+### 三级标题
+#### 第四级标题
+##### 第五级标题
+###### 第六级标题
 ```
 
-### Header 3
+### 断句
+- 在要换行的句子末尾插入两个半宽空格
+    - 您也可以在 "设置 "中进行更改,使换行不使用半宽空格
+        - 在管理页面的 "Markdown 设置 "部分更改换行设置
 
-#### Header 4
+#### 无换行
+段落 1
+第 2 段
 
-##### Header 5
+#### 有换行符
+段落 1  
+第 2 段
 
-###### Header 6
+## 段落
+- 在文本中插入空白表格即可创建段落
+- 可将段落分成若干句子,使其更易于阅读
 
-## Block paragraph
+#### 无段落
+段落 1  
+第 2 段
 
-Pararaphs are created by inserting a newline character
-A paragraph can be created by pressing Enter at the end of the previous paragraph.
+#### 有段落
+第 1 段  
 
-```
-paragraph1
-(Blank line)
-paragraph2
-```
+第 2 段
 
-paragraph1
 
-paragraph2
+# :green_book: 文本样式
+- 可以使用各种样式来丰富句子的文字表达方式
+    - 选择 "编辑 "屏幕底部的工具栏图标,也可以轻松应用这些样式
 
-## Br new line
+##斜体
+- 用星号`*`或下划线`_`括住文本。
 
-Add two spaces before break.
-***This behaviour can be modified in the options menu.***
+#### 示例
+- 这句话用*斜体*表示强调
+- 这句话用 _Italic_ 表示强调 
 
-```
-hoge
-fuga(two spaces)
-piyo
-```
+## 粗体
+- 用两个星号`*`或两个下划线`_`括住文本。
 
-hoge
-fuga
-piyo
+#### 示例
+- 这句话用 ** 粗体** 表示强调 
+- 这句话用__粗体__表示强调
 
-## Blockquotes
+## 斜体和粗体
+- 用三个星号`*`或三个下划线`_`括起来
 
-Add one `>` per level at the start of the line
+#### 示例
+- 本句用***斜体和粗体***表示强调
+- 本句用____斜体和粗体____表示强调
 
-```
-> quote
-> quote
->> nested quotes
-```
 
-> quote
-> quote
->> nested quotes
+# :orange_book: 插入列表
+## 缩略图列表
+- 用连字符 `-`、加号 `+` 或星号 `*` 开头一行,插入一个项目符号列表
 
-## Code
+#### 示例
+- 这句话出现在项目符号列表中
+    - 这句话出现在项目符号列表中
+        - 这句话出现在项目符号列表中
+        - 这句话出现在项目符号列表中
+- 此句出现在项目符号列表中
+    - 此句子出现在项目符号列表中
 
-Wrap code with three back quotes or tildes.
+## 编号列表
+- 在行首添加 `Number.` 以插入编号列表
+- 编号列表和项目符号列表也可合并使用
 
-```
-print 'hoge'
-```
+#### 示例
+1. 编号列表中有这样一句话
+    1. 编号列表中包含这句话
+    1. 该句子出现在编号表中
+    1. 此句出现在编号列表中
+        - 此句出现在项目符号列表中 
+1. 此句出现在项目符号列表中
+    - 此句出现在项目符号列表中
 
-### Syntax highlight and file name
+##任务列表
+- 通过书写 `[] ` 插入未选中复选框列表
+    - 通过书写 `[x]` 选中复选框
 
-- corresponding [highlight.js Demo](https://highlightjs.org/static/demo/) of common category
+#### 示例
+- [ ] 任务 1
+    - [x] 任务 1-1
+    - [ ] 任务 1-2
+- [x] 任务 2
 
 
-~~~
-```javascript:mersenne-twister.js
-function MersenneTwister(seed) {
-  if (arguments.length == 0) {
-    seed = new Date().getTime();
-  }
+# :blue_book: 其他
+### 引号
+- 在段落开头加上`>`,使用引号表达式
+    - 使用`>`字符序列可表达多个引号
+- 列表和其他元素可在方括号内一起使用
 
-  this._mt = new Array(624);
-  this.setSeed(seed);
-}
-```
-~~~
+#### 示例
+> - 引号
+> - 引号
+>> 多个引号需要插入更多的 `>` 字符
 
-```javascript:mersenne-twister.js
-function MersenneTwister(seed) {
-  if (arguments.length == 0) {
-    seed = new Date().getTime();
-  }
+## 代码
+- 可以通过将代码添加到三个 `` `` `` 中来表达代码
 
-  this._mt = new Array(624);
-  this.setSeed(seed);
-}
+#### 示例
 ```
+在此处添加代码  
+代码中可以体现换行和段落
 
-### Inline code
-
-Words wrapped by `` `back quotes` `` will be formatted as inline code.
-
-```
-This is `Inline Code`.
+- 代码中也可使用列表
+    - 也可在代码中使用列表
 ```
 
-This is  `Inline Code`.
+## 内联代码
 
-## Pre-arranged text
 
-Code blocks should be preceded by four spaces or one tab.
 
-```
-    class Hoge
-        def hoge
-            print 'hoge'
-        end
-    end
-```
 
-    class Hoge
-        def hoge
-            print 'hoge'
-        end
-    end
+#### 示例
+以下是内联代码 
 
-## Horizontal Line
+## 水平线
+- 用三个或三个以上连续的星号`*`或下划线`_`插入水平线
 
-Write three underscores `_`, or asterisks`*`.
-
-```
+#### 示例
+以下是水平线
 ***
-___
----
-```
 
-***
+下面是水平线
 ___
----
-
-
-
-# :memo: Typography
-
-## Strong Text
-
-### Italic
-
-To italicize text, add One asterisk or underscores before and after a word or phrase.
-
-```
-This is *Italic* .
-This is _Italic_ .
-```
-
-This is *Italic* .
-This is _Italic_ .
-
-### Bold
-
-To bold text, add two asterisks or underscores before and after a word or phrase.
-
-```
-This is **bold**.
-This is __bold__.
-```
-
-This is **bold**.
-This is __bold__.
-
-### Bold + Italic
-
-To bold and italicize text, add three asterisks or underscores before and after a word or phrase.
-
-```
-This is ***Italic & Bold***.
-This is ___Italic & Bold___.
-```
-
-This is ***Italic & Bold***.
-This is ___Italic & Bold___.
-
-# :memo: Images
-
-You can insert `<img>` tag using `![description](URL)`.
-
-```markdown
-![Minion](https://octodex.github.com/images/minion.png)
-![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")
-```
-
-![Minion](https://octodex.github.com/images/minion.png)
-![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")
-
-The size of the image can be set by using an HTML image tag
-
-```html
-<img src="https://octodex.github.com/images/dojocat.jpg" width="200px">
-```
-
-<img src="https://octodex.github.com/images/dojocat.jpg" width="200px">
-
-
-# :memo: Link
-
-## Markdown standard
-
-You can create links using `[Display text](URL)`.
-
-```
-[Google](https://www.google.co.jp/)
-```
-
-[Google](https://www.google.co.jp/)
-
-## Pukiwiki like linker
-
-This is the most flexible linker.
-Both the page description and link address can be displayed on the page.
-
-```
-[[./Bootstrap4]]
-Example of Bootstrap4 is [[here>./Bootstrap4]]
-```
-
-[[./Bootstrap4]]  
-Example of Bootstrap4 is [[here>./Bootstrap4]]
-
-# :memo: Lists
-
-## Ul Bulleted list
-
-To create an unordered list, add dashes (-), asterisks (*), or plus signs (+) in front of line items. 
-Items can be nested using indentation.
-
-```
-- List1
-    - List1_1
-        - List1_1_1
-        - List1_1_2
-    - List1_2
-- List2
-- List3
-```
-
-- List1
-    - List1_1
-        - List1_1_1
-        - List1_1_2
-    - List1_2
-- List2
-- List3
-
-## Ol Numbered List
-
-To create an ordered list, add line items with numbers followed by periods. 
-The numbers don’t have to be in numerical order, but the list should start with the number one.
-
-```
-1. Number list 1
-    1. Number list 1-1
-    1. Number list 1-2
-1. Number list 2
-1. Number list 3
-```
-
-1. Number list 1
-    1. Number list 1-1
-    1. Number list 1-2
-1. Number list 2
-1. Number list 3
-
-
-## Check list
-
-```
-- [ ] Task 1
-    - [x] Task 1.1
-    - [ ] Task 1.2
-- [x] Task2
-```
-
-- [ ] Task 1
-    - [x] Task 1.1
-    - [ ] Task 1.2
-- [x] Task2
-
-
-# :memo: Table
-
-## Markdown Standard
-
-```markdown
-| Left align | Right align | Center align |
-|:-----------|------------:|:------------:|
-| This       | This        | This         |
-| column     | column      | column       |
-| will       | will        | will         |
-| be         | be          | be           |
-| left       | right       | center       |
-| aligned    | aligned     | aligned      |
-
-OR
-
-Left align | Right align | Center align
-:--|--:|:-:
-This       | This        | This
-column     | column      | column
-will       | will        | will
-be         | be          | be
-left       | right       | center
-aligned    | aligned     | aligned
-```
-
-| Left align | Right align | Center align |
-|:-----------|------------:|:------------:|
-| This       | This        | This         |
-| column     | column      | column       |
-| will       | will        | will         |
-| be         | be          | be           |
-| left       | right       | center       |
-| aligned    | aligned     | aligned      |
-
-## TSV
-
-~~~
-``` tsv
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-~~~
-
-``` tsv
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-
-## TSV with header
-
-~~~
-``` tsv-h
-First Header	Second Header
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-~~~
-
-``` tsv-h
-First Header	Second Header
-Content Cell	Content Cell
-Content Cell	Content Cell
-```
-
-## CSV
-
-~~~
-``` csv
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-~~~
-
-``` csv
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-
-## CSV with header
-
-~~~
-``` csv-h
-First Header,Second Header
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-~~~
-
-``` csv-h
-First Header,Second Header
-Content Cell,Content Cell
-Content Cell,Content Cell
-```
-
-
-# :memo: Footnote
-
-You can write a reference [^1] to a footnote.
-
-Long footnotes can be written as [^longnote].
-
-[^1]: A_reference_to_the_first_footnote.
-
-[^longnote]: An_example_of_writing_a_footnote_in_multiple_blocks.
-
-    Subsequent paragraphs are indented and belong to the previous footnote.
-
-
-# :memo: Emoji
-
-:smiley: :smile: :laughing: :innocent: :drooling_face:
-
-:family: :man-boy: :man-girl: :man-girl-girl: :woman-girl-girl:
-
-:+1: :-1: :open_hands: :raised_hands: :point_right:
-
-:apple: :green_apple: :strawberry: :cake: :hamburger:
-
-:basketball: :football: :baseball: :volleyball: :8ball:
-
-:hearts: :broken_heart: :heartbeat: :heartpulse: :heart_decoration:
 
-:watch: :gear: :gem: :wrench: :email:
 
+# :ledger: 更多应用
+- [Bootstrap5](/Sandbox/Bootstrap5)
 
-# :heavy_plus_sign: More..
+- [Diagrams](/Sandbox/Diagrams)
 
-- Try to attach Bootstrap4 Tags?
-    - :arrow_right: [/Sandbox/Bootstrap4]
-- Try to draw Diagrams?
-    - :arrow_right: [/Sandbox/Diagrams]
-- Try to write Math Formulas?
-    - :arrow_right: [/Sandbox/Math]
+- [Math](/Sandbox/Math)

+ 46 - 59
apps/app/resource/locales/zh_CN/welcome.md

@@ -1,64 +1,51 @@
-# :tada: 欢迎来到GROWI
+# :tada: 欢迎访问 GROWI
 
-[![GitHub Releases](https://img.shields.io/github/release/weseek/growi.svg)](https://github.com/weseek/growi/releases/latest)
-[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/weseek/growi/blob/master/LICENSE)
+GROWI 是面向企业和个人的维基知识库工具。  
+知识信息可以在公司、大学实验室和俱乐部中轻松共享,任何人都可以编辑创建的页面。  
 
-GROWI是一个针对个人和公司的Wiki - 一个知识库工具。
-公司、大学实验室和俱乐部的知识可以轻松共享,任何人都可以编辑页面。
+随手写下你所知道的信息,然后一起编辑,可以减少团队中的隐性知识。  
+理所当然地增加每天共享的信息量!
 
-我们可以很容易地写下我们知道的东西,并一起编辑,我们可以**简化我们团队中的隐性知识(难以用语言解释的知识)**。 
-让我们每天增加信息交流。
-
-### :beginner: 如何轻松制作一个页面 
-
-- 从右上方的 "**创建**"按钮,或右下方的**铅笔图标开始。
-    - 页面标题以后可以再编辑,不用担心标题的问题。
-        - 在标题输入栏,可以用半宽的`/`(斜线)创建页面的层次。
-        - 例子)尝试输入`/category1/category2/page-title-we-want-to-create`。
-- 我们可以通过在行首添加`-`来创建一个要点。
-- 我们还可以复制和粘贴,拖放附件,如图片、PDF、Word/Excel/PowerPoint等。
-- 一旦我们完成了,按 "**更新**"按钮来发布页面。
-    - 我们也可以通过`Ctrl(⌘) + S`来保存。
-
-了解更多信息: [Create page](https://docs.growi.org/en/guide/features/create_page.html)
-
-<div class="mt-4 card border-primary">
-  <div class="card-header bg-primary text-light">
-    Tips
-  </div>
-  <div class="card-body">
-    <ul>
-      <li>Ctrl(⌘) + "/" 显示快速帮助。</li>
-      <li>你可以用 <a href="https://getbootstrap.com/docs/4.6/components/">Bootstrap 4编写HTML</a>.</li>
-    </ul>
-  </div>
+<div class="alert alert-primary" role="alert">
+※此页面可自由编辑,并作为维基的首页使用
 </div>
 
-# :anchor: 对于管理员来说 <small>〜如果你创建了一个Wiki〜</small>
-
-### :arrow_right: 你会和多个人一起使用Wiki吗?
-- :heavy_check_mark: 让我们邀请一些成员。
-    - [Add/invite new members to the Wiki](https://docs.growi.org/en/admin-guide/management-cookbook/user-management.html#temporary-issuance-of-a-new-user)
-### :arrow_right: 与Slack合作,接收页面和评论通知。
-- :heavy_check_mark:  [Slack integration](https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/#overview)
-### :arrow_right: 你是否从另一个系统转换?
-- :heavy_check_mark: 可以从其他GROWI, esa.io, Qiita:Team导入数据。
-    -  [Import Data](https://docs.growi.org/en/admin-guide/management-cookbook/import.html)
-
-了解更多信息: [Admin Guide](https://docs.growi.org/en/admin-guide/)
-
-
-# 内容列表示例
-
-你可以用一个表格和`$lsx`来显示内容列表。
-
-| 所有页面列表(前15页)      | [/Sandbox] 下级页面列表 |
-| ---------------------------| ------------------------|
-| $lsx(/,num=15)             | $lsx(/Sandbox)          |
-
-# Slack
-
-<a href="https://communityinviter.com/apps/wsgrowi/invite/">join our Slack team</a>
-
-我们欢迎新人加入我们的slack频道,帮助改善Growi。
-除了讨论发展问题,我们也很乐意在你加入时回答你的问题。
+# :beginner: 使用 GROWI 可以做什么
+## 1. 可以创建页面来存储信息和知识。
+- 如何创建和编辑页面
+    - 可以通过屏幕左上角的 "铅笔图标 "创建新页面。
+    - 点击屏幕右上角的 "编辑 "可编辑已创建的页面。
+- 如何管理页面
+    - GROWI 采用 "分层结构 "管理页面。
+        - ` /page a/page b/page c ` 结构类似。
+    - 除了 "层次结构",还可以通过 "标签 "来管理页面。
+
+## 2. 检索信息和知识的方式有以下几种。
+- 关键词搜索
+- 使用各种侧边栏进行搜索。
+    - 按 "页面树 "搜索。
+    - 按 "最新更改 "搜索。
+    - 按 "标签 "搜索 例如...
+
+## 3. 信息和知识可以很容易地在内部和外部共享。
+- 内部成员可通过发送页面的 URL 或 URL 链接获得通知。
+    - 使用 "用户组 "可以管理公司成员内部的查看权限。
+- 还可以允许未持有账户的外部用户查看页面。
+    - 使用 "共享链接 "与公司以外的用户共享信息。
+
+#### :bulb:如果不确定如何编辑页面,请选中 [Sandbox](/Sandbox)!
+
+
+# :wrench:针对管理员 - GROWI 创建后
+
+### :arrow_right: 您是否与多人一起使用 GROWI?
+- :heavy_check_mark: 邀请您的会员
+    - [添加和邀请新成员加入 GROWI](https://docs.growi.org/en/admin-guide/management-cookbook/user-management.html#%E6%96%B0%E8%A6%8F%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E4%BB%AE%E7%99%BA%E8%A1%8C)
+
+### :arrow_right: 您对 GROWI 现在的样子满意吗?
+- :heavy_check_mark: 定制 GROWI 的外观和感觉!
+    - [定制 GROWI 主题](/admin/customize)
+
+### :arrow_right: GROWI 安全配置是否已完成?
+- :heavy_check_mark: 更新您的 GROWI 安全设置!
+    - [更新 GROWI 安全设置](/admin/security)

+ 30 - 9
apps/app/src/client/services/side-effects/page-updated.ts

@@ -3,17 +3,24 @@ import { useCallback, useEffect } from 'react';
 import { useGlobalSocket } from '@growi/core/dist/swr';
 
 import { SocketEventName } from '~/interfaces/websocket';
-import { useCurrentPageId } from '~/stores/page';
+import { usePageStatusAlert } from '~/stores/alert';
+import { useSWRxCurrentPage, useSWRMUTxCurrentPage } from '~/stores/page';
 import { useSetRemoteLatestPageData, type RemoteRevisionData } from '~/stores/remote-latest-page';
+import { useEditorMode, EditorMode } from '~/stores/ui';
+
 
 export const usePageUpdatedEffect = (): void => {
 
   const { setRemoteLatestPageData } = useSetRemoteLatestPageData();
 
   const { data: socket } = useGlobalSocket();
-  const { data: currentPageId } = useCurrentPageId();
+  const { data: editorMode } = useEditorMode();
+  const { data: currentPage } = useSWRxCurrentPage();
+  const { trigger: mutateCurrentPage } = useSWRMUTxCurrentPage();
+  const { open: openPageStatusAlert, close: closePageStatusAlert } = usePageStatusAlert();
 
-  const setLatestRemotePageData = useCallback((data) => {
+  const remotePageDataUpdateHandler = useCallback((data) => {
+    // Set remote page data
     const { s2cMessagePageUpdated } = data;
 
     const remoteData: RemoteRevisionData = {
@@ -23,22 +30,36 @@ export const usePageUpdatedEffect = (): void => {
       remoteRevisionLastUpdatedAt: s2cMessagePageUpdated.revisionUpdateAt,
     };
 
-    if (currentPageId != null && currentPageId === s2cMessagePageUpdated.pageId) {
+    if (currentPage?._id != null && currentPage._id === s2cMessagePageUpdated.pageId) {
       setRemoteLatestPageData(remoteData);
-    }
 
-  }, [currentPageId, setRemoteLatestPageData]);
+      // Open PageStatusAlert
+      const currentRevisionId = currentPage?.revision?._id;
+      const remoteRevisionId = s2cMessagePageUpdated.revisionId;
+      const isRevisionOutdated = (currentRevisionId != null || remoteRevisionId != null) && currentRevisionId !== remoteRevisionId;
+
+      // !!CAUTION!! Timing of calling openPageStatusAlert may clash with components/PageEditor/conflict.tsx
+      if (isRevisionOutdated && editorMode === EditorMode.View) {
+        openPageStatusAlert({ hideEditorMode: EditorMode.Editor, onRefleshPage: mutateCurrentPage });
+      }
+
+      // Clear cache
+      if (!isRevisionOutdated) {
+        closePageStatusAlert();
+      }
+    }
+  }, [currentPage?._id, currentPage?.revision?._id, editorMode, mutateCurrentPage, openPageStatusAlert, closePageStatusAlert, setRemoteLatestPageData]);
 
   // listen socket for someone updating this page
   useEffect(() => {
 
     if (socket == null) { return }
 
-    socket.on(SocketEventName.PageUpdated, setLatestRemotePageData);
+    socket.on(SocketEventName.PageUpdated, remotePageDataUpdateHandler);
 
     return () => {
-      socket.off(SocketEventName.PageUpdated, setLatestRemotePageData);
+      socket.off(SocketEventName.PageUpdated, remotePageDataUpdateHandler);
     };
 
-  }, [setLatestRemotePageData, socket]);
+  }, [remotePageDataUpdateHandler, socket]);
 };

+ 0 - 0
apps/app/src/client/services/update-page/conflict.ts → apps/app/src/client/services/update-page/conflict.tsx


+ 4 - 3
apps/app/src/components/LoginForm.tsx

@@ -72,9 +72,9 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
     }
   }, []);
 
-  const tWithOpt = useCallback((key: string, opt?: any): string => {
+  const tWithOpt = useCallback((key: string, opt?: any) => {
     if (typeof opt === 'object') {
-      return t(key, opt as object);
+      return t(key, opt).toString();
     }
     return t(key);
   }, [t]);
@@ -179,7 +179,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
     return (
       <>
         {/* !! - DO NOT DELETE HIDDEN ELEMENT - !! -- 7.12 ryoji-s */}
-        {/* Import font-awesome to prevent MongoStore.js "Unable to find the session to touch" error */}
+        {/* https://github.com/weseek/growi/pull/7873 */}
         <div className="visually-hidden">
           <LoadingSpinner />
         </div>
@@ -187,6 +187,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
         {isLdapSetupFailed && (
           <div className="alert alert-warning small">
             <strong><span className="material-symbols-outlined">info</span>{t('login.enabled_ldap_has_configuration_problem')}</strong><br />
+            {/* eslint-disable-next-line react/no-danger */}
             <span dangerouslySetInnerHTML={{ __html: t('login.set_env_var_for_logs') }}></span>
           </div>
         )}

+ 7 - 4
apps/app/src/components/Page/DisplaySwitcher.tsx

@@ -2,17 +2,16 @@ import React from 'react';
 
 import dynamic from 'next/dynamic';
 
-
 import { useHashChangedEffect } from '~/client/services/side-effects/hash-changed';
 import { usePageUpdatedEffect } from '~/client/services/side-effects/page-updated';
 import { useIsEditable } from '~/stores/context';
+import { useIsLatestRevision } from '~/stores/page';
 import { EditorMode, useEditorMode } from '~/stores/ui';
 
 import { LazyRenderer } from '../Common/LazyRenderer';
 
-
 const PageEditor = dynamic(() => import('../PageEditor'), { ssr: false });
-
+const PageEditorReadOnly = dynamic(() => import('../PageEditor/PageEditorReadOnly').then(mod => mod.PageEditorReadOnly), { ssr: false });
 
 type Props = {
   pageView: JSX.Element,
@@ -23,6 +22,7 @@ export const DisplaySwitcher = (props: Props): JSX.Element => {
 
   const { data: editorMode = EditorMode.View } = useEditorMode();
   const { data: isEditable } = useIsEditable();
+  const { data: isLatestRevision } = useIsLatestRevision();
 
   usePageUpdatedEffect();
   useHashChangedEffect();
@@ -34,7 +34,10 @@ export const DisplaySwitcher = (props: Props): JSX.Element => {
       { isViewMode && pageView }
 
       <LazyRenderer shouldRender={isEditable === true && editorMode === EditorMode.Editor}>
-        <PageEditor />
+        { isLatestRevision
+          ? <PageEditor />
+          : <PageEditorReadOnly />
+        }
       </LazyRenderer>
     </>
   );

+ 20 - 8
apps/app/src/components/PageAlert/OldRevisionAlert.tsx

@@ -1,27 +1,39 @@
-import React from 'react';
+import React, { useCallback } from 'react';
 
 import { returnPathForURL } from '@growi/core/dist/utils/path-utils';
-import Link from 'next/link';
+import { useRouter } from 'next/router';
 import { useTranslation } from 'react-i18next';
 
-import { useSWRxCurrentPage, useIsLatestRevision } from '~/stores/page';
+import { useSWRxCurrentPage, useSWRMUTxCurrentPage, useIsLatestRevision } from '~/stores/page';
 
 export const OldRevisionAlert = (): JSX.Element => {
-
+  const router = useRouter();
   const { t } = useTranslation();
-  const { data: isLatestRevision } = useIsLatestRevision();
+
+  const { data: isOldRevisionPage } = useIsLatestRevision();
   const { data: page } = useSWRxCurrentPage();
+  const { trigger: mutateCurrentPage } = useSWRMUTxCurrentPage();
+
+  const onClickShowLatestButton = useCallback(async() => {
+    if (page == null) {
+      return;
+    }
+
+    const url = returnPathForURL(page.path, page._id);
+    await router.push(url);
+    mutateCurrentPage();
+  }, [mutateCurrentPage, page, router]);
 
-  if (page == null || isLatestRevision == null || isLatestRevision) {
+  if (page == null || isOldRevisionPage) {
     return <></>;
   }
 
   return (
     <div className="alert alert-warning">
       <strong>{t('Warning')}: </strong> {t('page_page.notice.version')}
-      <Link href={returnPathForURL(page.path, page._id)}>
+      <button type="button" className="btn btn-outline-natural-secondary" onClick={onClickShowLatestButton}>
         <span className="material-symbols-outlined me-1">arrow_circle_right</span>{t('Show latest')}
-      </Link>
+      </button>
     </div>
   );
 };

+ 48 - 119
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -3,11 +3,11 @@ import React, {
   useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState,
 } from 'react';
 
+
 import type EventEmitter from 'events';
 import nodePath from 'path';
 
 import { type IPageHasId, Origin } from '@growi/core';
-import { useGlobalSocket } from '@growi/core/dist/swr';
 import { pathUtils } from '@growi/core/dist/utils';
 import {
   CodeMirrorEditorMain, GlobalCodeMirrorEditorKey,
@@ -20,10 +20,9 @@ import { throttle, debounce } from 'throttle-debounce';
 
 import { useShouldExpandContent } from '~/client/services/layout';
 import { useUpdateStateAfterSave } from '~/client/services/page-operation';
-import { updatePage } from '~/client/services/update-page';
+import { updatePage, extractRemoteRevisionDataFromErrorObj } from '~/client/services/update-page';
 import { apiv3Get, apiv3PostForm } from '~/client/util/apiv3-client';
-import { toastError, toastSuccess } from '~/client/util/toastr';
-import { SocketEventName } from '~/interfaces/websocket';
+import { toastError, toastSuccess, toastWarning } from '~/client/util/toastr';
 import {
   useDefaultIndentSize, useCurrentUser,
   useCurrentPathname, useIsEnabledAttachTitleHeader,
@@ -32,22 +31,14 @@ import {
 } from '~/stores/context';
 import {
   useEditorSettings,
-  useCurrentIndentSize, usePageTagsForEditors,
-  useIsConflict,
+  useCurrentIndentSize,
   useEditingMarkdown,
   useWaitingSaveProcessing,
 } from '~/stores/editor';
-import { useConflictDiffModal } from '~/stores/modal';
 import {
-  useCurrentPagePath, useSWRMUTxCurrentPage, useSWRxCurrentPage, useSWRxTagsInfo, useCurrentPageId, useIsNotFound, useIsLatestRevision, useTemplateBodyData,
+  useCurrentPagePath, useSWRxCurrentPage, useCurrentPageId, useIsNotFound, useTemplateBodyData,
 } from '~/stores/page';
 import { mutatePageTree } from '~/stores/page-listing';
-import {
-  useRemoteRevisionId,
-  useRemoteRevisionBody,
-  useRemoteRevisionLastUpdatedAt,
-  useRemoteRevisionLastUpdateUser,
-} from '~/stores/remote-latest-page';
 import { usePreviewOptions } from '~/stores/renderer';
 import {
   EditorMode,
@@ -60,7 +51,8 @@ import loggerFactory from '~/utils/logger';
 import { EditorNavbar } from './EditorNavbar';
 import EditorNavbarBottom from './EditorNavbarBottom';
 import Preview from './Preview';
-import { scrollEditor, scrollPreview } from './ScrollSyncHelper';
+import { useScrollSync } from './ScrollSyncHelper';
+import { useConflictResolver, useConflictEffect, type ConflictHandler } from './conflict';
 
 import '@growi/editor/dist/style.css';
 
@@ -73,9 +65,16 @@ declare global {
   var globalEmitter: EventEmitter;
 }
 
-// for scrolling
-let isOriginOfScrollSyncEditor = false;
-let isOriginOfScrollSyncPreview = false;
+export type SaveOptions = {
+  slackChannels: string,
+  overwriteScopesOfDescendants?: boolean
+}
+export type Save = (
+  revisionId?: string,
+  requestMarkdown?: string,
+  opts?: SaveOptions,
+  onConflict?: ConflictHandler
+) => Promise<IPageHasId | null>
 
 type Props = {
   visibility?: boolean,
@@ -93,11 +92,8 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const { data: currentPagePath } = useCurrentPagePath();
   const { data: currentPathname } = useCurrentPathname();
   const { data: currentPage } = useSWRxCurrentPage();
-  const { trigger: mutateCurrentPage } = useSWRMUTxCurrentPage();
   const { data: grantData } = useSelectedGrant();
-  const { sync: syncTagsInfoForEditor } = usePageTagsForEditors(pageId);
-  const { mutate: mutateTagsInfo } = useSWRxTagsInfo(pageId);
-  const { data: editingMarkdown, mutate: mutateEditingMarkdown } = useEditingMarkdown();
+  const { data: editingMarkdown } = useEditingMarkdown();
   const { data: isEnabledAttachTitleHeader } = useIsEnabledAttachTitleHeader();
   const { data: templateBodyData } = useTemplateBodyData();
   const { data: isEditable } = useIsEditable();
@@ -107,20 +103,12 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const { data: currentIndentSize, mutate: mutateCurrentIndentSize } = useCurrentIndentSize();
   const { data: defaultIndentSize } = useDefaultIndentSize();
   const { data: acceptedUploadFileType } = useAcceptedUploadFileType();
-  const { data: conflictDiffModalStatus, close: closeConflictDiffModal } = useConflictDiffModal();
   const { data: editorSettings } = useEditorSettings();
-  const { mutate: mutateIsLatestRevision } = useIsLatestRevision();
-  const { mutate: mutateRemotePageId } = useRemoteRevisionId();
-  const { mutate: mutateRemoteRevisionId } = useRemoteRevisionBody();
-  const { mutate: mutateRemoteRevisionLastUpdatedAt } = useRemoteRevisionLastUpdatedAt();
-  const { mutate: mutateRemoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser();
   const { data: user } = useCurrentUser();
   const { onEditorsUpdated } = useEditingUsers();
-
-  const { data: socket } = useGlobalSocket();
+  const onConflict = useConflictResolver();
 
   const { data: rendererOptions } = usePreviewOptions();
-  const { mutate: mutateIsConflict } = useIsConflict();
 
   const { mutate: mutateResolvedTheme } = useResolvedThemeForEditor();
 
@@ -128,10 +116,13 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
 
   const updateStateAfterSave = useUpdateStateAfterSave(pageId, { supressEditingMarkdownMutation: true });
 
+  useConflictEffect();
+
   const { resolvedTheme } = useNextThemes();
   mutateResolvedTheme({ themeData: resolvedTheme });
 
   const currentRevisionId = currentPage?.revision?._id;
+  const isRevisionIdRequiredForPageUpdate = currentPage?.revision?.origin === undefined;
 
   const initialValueRef = useRef('');
   const initialValue = useMemo(() => {
@@ -168,43 +159,26 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
 
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
 
+  const { scrollEditorHandler, scrollPreviewHandler } = useScrollSync(GlobalCodeMirrorEditorKey.MAIN, previewRef);
 
-  const checkIsConflict = useCallback((data) => {
-    const { s2cMessagePageUpdated } = data;
-
-    const isConflict = markdownToPreview !== s2cMessagePageUpdated.revisionBody;
-
-    mutateIsConflict(isConflict);
-
-  }, [markdownToPreview, mutateIsConflict]);
-
-  useEffect(() => {
-    if (socket == null) { return }
-
-    socket.on(SocketEventName.PageUpdated, checkIsConflict);
-
-    return () => {
-      socket.off(SocketEventName.PageUpdated, checkIsConflict);
-    };
-
-  }, [socket, checkIsConflict]);
+  const scrollEditorHandlerThrottle = useMemo(() => throttle(25, scrollEditorHandler), [scrollEditorHandler]);
+  const scrollPreviewHandlerThrottle = useMemo(() => throttle(25, scrollPreviewHandler), [scrollPreviewHandler]);
 
-  const save = useCallback(async(opts?: {slackChannels: string, overwriteScopesOfDescendants?: boolean}): Promise<IPageHasId | null> => {
-    if (pageId == null || currentRevisionId == null || grantData == null) {
+  const save: Save = useCallback(async(revisionId, markdown, opts, onConflict) => {
+    if (pageId == null || grantData == null) {
       logger.error('Some materials to save are invalid', {
-        pageId, currentRevisionId, grantData,
+        pageId, grantData,
       });
       throw new Error('Some materials to save are invalid');
     }
 
     try {
       mutateWaitingSaveProcessing(true);
-      const isRevisionIdRequiredForPageUpdate = currentPage?.revision?.origin === undefined;
 
       const { page } = await updatePage({
         pageId,
-        revisionId: isRevisionIdRequiredForPageUpdate ? currentRevisionId : undefined,
-        body: codeMirrorEditor?.getDoc() ?? '',
+        revisionId,
+        body: markdown ?? '',
         grant: grantData?.grant,
         origin: Origin.Editor,
         userRelatedGrantUserGroupIds: grantData?.userRelatedGrantedGroups?.map((group) => {
@@ -220,41 +194,45 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     }
     catch (error) {
       logger.error('failed to save', error);
-      toastError(error);
-      if (error.code === 'conflict') {
-        mutateRemotePageId(error.data.revisionId);
-        mutateRemoteRevisionId(error.data.revisionBody);
-        mutateRemoteRevisionLastUpdatedAt(error.data.createdAt);
-        mutateRemoteRevisionLastUpdateUser(error.data.user);
+
+      const remoteRevisionData = extractRemoteRevisionDataFromErrorObj(error);
+      if (remoteRevisionData != null) {
+        onConflict?.(remoteRevisionData, markdown ?? '', save, opts);
+        toastWarning(t('modal_resolve_conflict.conflicts_with_new_body_on_server_side'));
+        return null;
       }
+
+      toastError(error);
       return null;
     }
     finally {
       mutateWaitingSaveProcessing(false);
     }
+  }, [pageId, grantData, mutateWaitingSaveProcessing, t]);
 
-  // eslint-disable-next-line max-len
-  }, [codeMirrorEditor, grantData, pageId, currentRevisionId, mutateWaitingSaveProcessing, mutateRemotePageId, mutateRemoteRevisionId, mutateRemoteRevisionLastUpdatedAt, mutateRemoteRevisionLastUpdateUser]);
-
-  const saveAndReturnToViewHandler = useCallback(async(opts: {slackChannels: string, overwriteScopesOfDescendants?: boolean}) => {
-    const page = await save(opts);
+  const saveAndReturnToViewHandler = useCallback(async(opts: SaveOptions) => {
+    const markdown = codeMirrorEditor?.getDoc();
+    const revisionId = isRevisionIdRequiredForPageUpdate ? currentRevisionId : undefined;
+    const page = await save(revisionId, markdown, opts, onConflict);
     if (page == null) {
       return;
     }
 
     mutateEditorMode(EditorMode.View);
     updateStateAfterSave?.();
-  }, [mutateEditorMode, save, updateStateAfterSave]);
+  }, [codeMirrorEditor, currentRevisionId, isRevisionIdRequiredForPageUpdate, mutateEditorMode, onConflict, save, updateStateAfterSave]);
 
   const saveWithShortcut = useCallback(async() => {
-    const page = await save();
+    const markdown = codeMirrorEditor?.getDoc();
+    const revisionId = isRevisionIdRequiredForPageUpdate ? currentRevisionId : undefined;
+    const page = await save(revisionId, markdown, undefined, onConflict);
     if (page == null) {
       return;
     }
 
     toastSuccess(t('toaster.save_succeeded'));
     updateStateAfterSave?.();
-  }, [save, t, updateStateAfterSave]);
+  }, [codeMirrorEditor, currentRevisionId, isRevisionIdRequiredForPageUpdate, onConflict, save, t, updateStateAfterSave]);
 
 
   // the upload event handler
@@ -295,55 +273,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
 
   }, [codeMirrorEditor, pageId]);
 
-  const scrollEditorHandler = useCallback(() => {
-    if (codeMirrorEditor?.view?.scrollDOM == null || previewRef.current == null) {
-      return;
-    }
-
-    if (isOriginOfScrollSyncPreview) {
-      isOriginOfScrollSyncPreview = false;
-      return;
-    }
-
-    isOriginOfScrollSyncEditor = true;
-    scrollEditor(codeMirrorEditor.view.scrollDOM, previewRef.current);
-  }, [codeMirrorEditor]);
-
-  const scrollEditorHandlerThrottle = useMemo(() => throttle(25, scrollEditorHandler), [scrollEditorHandler]);
-
-  const scrollPreviewHandler = useCallback(() => {
-    if (codeMirrorEditor?.view?.scrollDOM == null || previewRef.current == null) {
-      return;
-    }
-
-    if (isOriginOfScrollSyncEditor) {
-      isOriginOfScrollSyncEditor = false;
-      return;
-    }
-
-    isOriginOfScrollSyncPreview = true;
-    scrollPreview(codeMirrorEditor.view.scrollDOM, previewRef.current);
-  }, [codeMirrorEditor]);
-
-  const scrollPreviewHandlerThrottle = useMemo(() => throttle(25, scrollPreviewHandler), [scrollPreviewHandler]);
-
-  const afterResolvedHandler = useCallback(async() => {
-    // get page data from db
-    const pageData = await mutateCurrentPage();
-
-    // update tag
-    await mutateTagsInfo(); // get from DB
-    syncTagsInfoForEditor(); // sync global state for client
-
-    // clear isConflict
-    mutateIsConflict(false);
-
-    // set resolved markdown in editing markdown
-    const markdown = pageData?.revision?.body ?? '';
-    mutateEditingMarkdown(markdown);
-
-  }, [mutateCurrentPage, mutateEditingMarkdown, mutateIsConflict, mutateTagsInfo, syncTagsInfoForEditor]);
-
   // initial caret line
   useEffect(() => {
     codeMirrorEditor?.setCaretLine();

+ 58 - 0
apps/app/src/components/PageEditor/PageEditorReadOnly.tsx

@@ -0,0 +1,58 @@
+import react, { useMemo, useRef } from 'react';
+
+import { CodeMirrorEditorReadOnly, GlobalCodeMirrorEditorKey } from '@growi/editor';
+import { throttle } from 'throttle-debounce';
+
+import { useShouldExpandContent } from '~/client/services/layout';
+import { useSWRxCurrentPage, useIsLatestRevision } from '~/stores/page';
+import { usePreviewOptions } from '~/stores/renderer';
+
+import { EditorNavbar } from './EditorNavbar';
+import Preview from './Preview';
+import { useScrollSync } from './ScrollSyncHelper';
+
+export const PageEditorReadOnly = react.memo((): JSX.Element => {
+  const previewRef = useRef<HTMLDivElement>(null);
+
+  const { data: currentPage } = useSWRxCurrentPage();
+  const { data: rendererOptions } = usePreviewOptions();
+  const { data: isLatestRevision } = useIsLatestRevision();
+  const shouldExpandContent = useShouldExpandContent(currentPage);
+
+  const { scrollEditorHandler, scrollPreviewHandler } = useScrollSync(GlobalCodeMirrorEditorKey.READONLY, previewRef);
+  const scrollEditorHandlerThrottle = useMemo(() => throttle(25, scrollEditorHandler), [scrollEditorHandler]);
+  const scrollPreviewHandlerThrottle = useMemo(() => throttle(25, scrollPreviewHandler), [scrollPreviewHandler]);
+
+  const revisionBody = currentPage?.revision?.body;
+
+  if (rendererOptions == null || isLatestRevision) {
+    return <></>;
+  }
+
+  return (
+    <div id="page-editor" className="flex-expand-vert">
+      <EditorNavbar />
+
+      <div className="flex-expand-horiz">
+        <div className="page-editor-editor-container flex-expand-vert border-end">
+          <CodeMirrorEditorReadOnly
+            markdown={revisionBody}
+            onScroll={scrollEditorHandlerThrottle}
+          />
+        </div>
+        <div
+          ref={previewRef}
+          onScroll={scrollPreviewHandlerThrottle}
+          className="page-editor-preview-container flex-expand-vert overflow-y-auto d-none d-lg-flex"
+        >
+          <Preview
+            markdown={revisionBody}
+            pagePath={currentPage?.path}
+            rendererOptions={rendererOptions}
+            expandContentWidth={shouldExpandContent}
+          />
+        </div>
+      </div>
+    </div>
+  );
+});

+ 44 - 2
apps/app/src/components/PageEditor/ScrollSyncHelper.ts → apps/app/src/components/PageEditor/ScrollSyncHelper.tsx

@@ -1,3 +1,7 @@
+import { useCallback, type RefObject, useRef } from 'react';
+
+import { useCodeMirrorEditorIsolated, type GlobalCodeMirrorEditorKey } from '@growi/editor';
+
 let defaultTop = 0;
 const padding = 5;
 
@@ -88,7 +92,7 @@ const calcScorllElementByRatio = (sourceElement: SourceElement, targetElement: T
 };
 
 
-export const scrollEditor = (editorRootElement: HTMLElement, previewRootElement: HTMLElement): void => {
+const scrollEditor = (editorRootElement: HTMLElement, previewRootElement: HTMLElement): void => {
 
   setDefaultTop(editorRootElement.getBoundingClientRect().top);
 
@@ -120,7 +124,7 @@ export const scrollEditor = (editorRootElement: HTMLElement, previewRootElement:
 
 };
 
-export const scrollPreview = (editorRootElement: HTMLElement, previewRootElement: HTMLElement): void => {
+const scrollPreview = (editorRootElement: HTMLElement, previewRootElement: HTMLElement): void => {
 
   setDefaultTop(previewRootElement.getBoundingClientRect().y);
 
@@ -150,3 +154,41 @@ export const scrollPreview = (editorRootElement: HTMLElement, previewRootElement
   editorRootElement.scrollTop = newScrollTop;
 
 };
+
+// eslint-disable-next-line max-len
+export const useScrollSync = (codeMirrorKey: GlobalCodeMirrorEditorKey, previewRef: RefObject<HTMLDivElement>): { scrollEditorHandler: () => void; scrollPreviewHandler: () => void } => {
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(codeMirrorKey);
+
+  const isOriginOfScrollSyncEditor = useRef(false);
+  const isOriginOfScrollSyncPreview = useRef(false);
+
+  const scrollEditorHandler = useCallback(() => {
+    if (codeMirrorEditor?.view?.scrollDOM == null || previewRef.current == null) {
+      return;
+    }
+
+    if (isOriginOfScrollSyncPreview.current) {
+      isOriginOfScrollSyncPreview.current = false;
+      return;
+    }
+
+    isOriginOfScrollSyncEditor.current = true;
+    scrollEditor(codeMirrorEditor.view.scrollDOM, previewRef.current);
+  }, [codeMirrorEditor, isOriginOfScrollSyncPreview, previewRef]);
+
+  const scrollPreviewHandler = useCallback(() => {
+    if (codeMirrorEditor?.view?.scrollDOM == null || previewRef.current == null) {
+      return;
+    }
+
+    if (isOriginOfScrollSyncEditor.current) {
+      isOriginOfScrollSyncEditor.current = false;
+      return;
+    }
+
+    isOriginOfScrollSyncPreview.current = true;
+    scrollPreview(codeMirrorEditor.view.scrollDOM, previewRef.current);
+  }, [codeMirrorEditor, isOriginOfScrollSyncEditor, previewRef]);
+
+  return { scrollEditorHandler, scrollPreviewHandler };
+};

+ 135 - 0
apps/app/src/components/PageEditor/conflict.tsx

@@ -0,0 +1,135 @@
+import { useCallback, useEffect } from 'react';
+
+import { Origin } from '@growi/core';
+import { useGlobalSocket } from '@growi/core/dist/swr';
+import { GlobalCodeMirrorEditorKey, useCodeMirrorEditorIsolated } from '@growi/editor';
+import { useTranslation } from 'react-i18next';
+
+import { useUpdateStateAfterSave } from '~/client/services/page-operation';
+import { toastSuccess } from '~/client/util/toastr';
+import type { Save, SaveOptions } from '~/components/PageEditor/PageEditor';
+import { SocketEventName } from '~/interfaces/websocket';
+import { usePageStatusAlert } from '~/stores/alert';
+import { useConflictDiffModal } from '~/stores/modal';
+import { useCurrentPageId, useSWRxCurrentPage } from '~/stores/page';
+import { type RemoteRevisionData, useSetRemoteLatestPageData } from '~/stores/remote-latest-page';
+import { EditorMode, useEditorMode } from '~/stores/ui';
+
+
+export type ConflictHandler = (
+  remoteRevisionData: RemoteRevisionData,
+  requestMarkdown: string,
+  save: Save,
+  saveOptions?: SaveOptions,
+) => void;
+
+type GenerateResolveConflicthandler = () => (
+  revisionId: string,
+  save: Save,
+  saveOptions?: SaveOptions,
+  onConflict?: () => void
+) => (newMarkdown: string) => Promise<void>
+
+const useGenerateResolveConflictHandler: GenerateResolveConflicthandler = () => {
+  const { t } = useTranslation();
+
+  const { data: pageId } = useCurrentPageId();
+  const { close: closePageStatusAlert } = usePageStatusAlert();
+  const { close: closeConflictDiffModal } = useConflictDiffModal();
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+  const updateStateAfterSave = useUpdateStateAfterSave(pageId, { supressEditingMarkdownMutation: true });
+
+  return useCallback((revisionId, save, saveOptions, onConflict) => {
+    return async(newMarkdown) => {
+      const page = await save(revisionId, newMarkdown, saveOptions, onConflict);
+      if (page == null) {
+        return;
+      }
+
+      // Reflect conflict resolution results in CodeMirrorEditor
+      codeMirrorEditor?.initDoc(newMarkdown);
+
+      closePageStatusAlert();
+      closeConflictDiffModal();
+
+      toastSuccess(t('toaster.save_succeeded'));
+      updateStateAfterSave?.();
+    };
+  }, [closeConflictDiffModal, closePageStatusAlert, codeMirrorEditor, t, updateStateAfterSave]);
+};
+
+
+type ConflictResolver = () => ConflictHandler;
+
+export const useConflictResolver: ConflictResolver = () => {
+  const { open: openPageStatusAlert } = usePageStatusAlert();
+  const { open: openConflictDiffModal } = useConflictDiffModal();
+  const { setRemoteLatestPageData } = useSetRemoteLatestPageData();
+  const generateResolveConflictHandler = useGenerateResolveConflictHandler();
+
+  return useCallback((remoteRevidsionData, requestMarkdown, save, saveOptions) => {
+    const conflictHandler = () => {
+      const resolveConflictHandler = generateResolveConflictHandler(remoteRevidsionData.remoteRevisionId, save, saveOptions, conflictHandler);
+      openPageStatusAlert({ onResolveConflict: () => openConflictDiffModal(requestMarkdown, resolveConflictHandler) });
+      setRemoteLatestPageData(remoteRevidsionData);
+    };
+
+    conflictHandler();
+  }, [generateResolveConflictHandler, openConflictDiffModal, openPageStatusAlert, setRemoteLatestPageData]);
+};
+
+export const useConflictEffect = (): void => {
+  const { data: currentPage } = useSWRxCurrentPage();
+  const { close: closePageStatusAlert } = usePageStatusAlert();
+  const { close: closeConflictDiffModal } = useConflictDiffModal();
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+  const { open: openPageStatusAlert } = usePageStatusAlert();
+  const { open: openConflictDiffModal } = useConflictDiffModal();
+  const { data: socket } = useGlobalSocket();
+  const { data: editorMode } = useEditorMode();
+
+  const conflictHandler = useCallback(() => {
+    const onResolveConflict = () => {
+      const resolveConflictHandler = (newMarkdown: string) => {
+        codeMirrorEditor?.initDoc(newMarkdown);
+        closeConflictDiffModal();
+        closePageStatusAlert();
+      };
+
+      const markdown = codeMirrorEditor?.getDoc();
+      openConflictDiffModal(markdown ?? '', resolveConflictHandler);
+    };
+
+    openPageStatusAlert({ onResolveConflict });
+  }, [closeConflictDiffModal, closePageStatusAlert, codeMirrorEditor, openConflictDiffModal, openPageStatusAlert]);
+
+  const updateRemotePageDataHandler = useCallback((data) => {
+    const { s2cMessagePageUpdated } = data;
+
+    const remoteRevisionId = s2cMessagePageUpdated.revisionId;
+    const remoteRevisionOrigin = s2cMessagePageUpdated.revisionOrigin;
+    const currentRevisionId = currentPage?.revision?._id;
+    const isRevisionOutdated = (currentRevisionId != null || remoteRevisionId != null) && currentRevisionId !== remoteRevisionId;
+
+    // !!CAUTION!! Timing of calling openPageStatusAlert may clash with client/services/side-effects/page-updated.ts
+    if (isRevisionOutdated && editorMode === EditorMode.Editor && (remoteRevisionOrigin === Origin.View || remoteRevisionOrigin === undefined)) {
+      conflictHandler();
+    }
+
+    // Clear cache
+    if (!isRevisionOutdated) {
+      closePageStatusAlert();
+    }
+  }, [closePageStatusAlert, currentPage?.revision?._id, editorMode, conflictHandler]);
+
+  useEffect(() => {
+    if (socket == null) { return }
+
+    socket.on(SocketEventName.PageUpdated, updateRemotePageDataHandler);
+
+    return () => {
+      socket.off(SocketEventName.PageUpdated, updateRemotePageDataHandler);
+    };
+
+  }, [socket, updateRemotePageDataHandler]);
+};

+ 37 - 98
apps/app/src/components/PageStatusAlert.tsx

@@ -1,133 +1,72 @@
-import React, { useCallback, useMemo } from 'react';
+import React, { useCallback } from 'react';
 
 import { useTranslation } from 'next-i18next';
-import * as ReactDOMServer from 'react-dom/server';
 
+import { usePageStatusAlert } from '~/stores/alert';
 import { useIsGuestUser, useIsReadOnlyUser } from '~/stores/context';
-import { useEditingMarkdown, useIsConflict } from '~/stores/editor';
-import { useConflictDiffModal } from '~/stores/modal';
-import { useSWRMUTxCurrentPage, useSWRxCurrentPage } from '~/stores/page';
+import { useSWRxCurrentPage } from '~/stores/page';
 import { useRemoteRevisionId, useRemoteRevisionLastUpdateUser } from '~/stores/remote-latest-page';
+import { useEditorMode } from '~/stores/ui';
 
 import { Username } from './User/Username';
 
 import styles from './PageStatusAlert.module.scss';
 
-type AlertComponentContents = {
-  additionalClasses: string[],
-  label: JSX.Element,
-  btn: JSX.Element
-}
-
 export const PageStatusAlert = (): JSX.Element => {
-
   const { t } = useTranslation();
-  const { data: isConflict } = useIsConflict();
-  const { mutate: mutateEditingMarkdown } = useEditingMarkdown();
-  const { open: openConflictDiffModal } = useConflictDiffModal();
+
+  const { data: editorMode } = useEditorMode();
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isReadOnlyUser } = useIsReadOnlyUser();
-
-  // store remote latest page data
+  const { data: pageStatusAlertData } = usePageStatusAlert();
   const { data: remoteRevisionId } = useRemoteRevisionId();
   const { data: remoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser();
-
   const { data: pageData } = useSWRxCurrentPage();
-  const { trigger: mutatePageData } = useSWRMUTxCurrentPage();
-  const revision = pageData?.revision;
 
-  const refreshPage = useCallback(async() => {
-    const updatedPageData = await mutatePageData();
-    mutateEditingMarkdown(updatedPageData?.revision?.body);
-  }, [mutateEditingMarkdown, mutatePageData]);
+  const onClickRefreshPage = useCallback(() => {
+    pageStatusAlertData?.onRefleshPage?.();
+  }, [pageStatusAlertData]);
 
   const onClickResolveConflict = useCallback(() => {
-    // openConflictDiffModal();
-  }, [openConflictDiffModal]);
-
-  // TODO: re-impl for builtin editor
-  //
-  // const getContentsForSomeoneEditingAlert = useCallback((): AlertComponentContents => {
-  //   return {
-  //     additionalClasses: ['bg-success', 'd-hackmd-none'],
-  //     label:
-  // <>
-  //   <span className="material-symbols-outlined">person</span>
-  //   {t('hackmd.someone_editing')}
-  // </>,
-  //     btn:
-  // <a href="#hackmd" key="btnOpenHackmdSomeoneEditing" className="btn btn-outline-white">
-  //   <span class="material-symbols-outlined">description</span>
-  //   Open HackMD Editor
-  // </a>,
-  //   };
-  // }, [t]);
-
-  const getContentsForUpdatedAlert = useCallback((): AlertComponentContents => {
+    pageStatusAlertData?.onResolveConflict?.();
+  }, [pageStatusAlertData]);
 
-    const usernameComponentToString = ReactDOMServer.renderToString(<Username user={remoteRevisionLastUpdateUser} />);
+  const hasResolveConflictHandler = pageStatusAlertData?.onResolveConflict != null;
+  const hasRefreshPageHandler = pageStatusAlertData?.onRefleshPage != null;
 
-    const label1 = isConflict
-      ? t('modal_resolve_conflict.file_conflicting_with_newer_remote')
-      // eslint-disable-next-line react/no-danger
-      : <span dangerouslySetInnerHTML={{ __html: `${usernameComponentToString} ${t('edited this page')}` }} />;
+  const currentRevisionId = pageData?.revision?._id;
+  const isRevisionOutdated = (currentRevisionId != null || remoteRevisionId != null) && currentRevisionId !== remoteRevisionId;
 
-    return {
-      additionalClasses: ['bg-warning text-dark'],
-      label:
-  <>
-    <span className="material-symbols-outlined">lightbulb</span>
-    {label1}
-  </>,
-      btn:
-  <>
-    <button type="button" onClick={() => refreshPage()} className="btn btn-outline-white me-4">
-      <span className="material-symbols-outlined">refresh</span>
-      {t('Load latest')}
-    </button>
-    { isConflict && (
-      <button
-        type="button"
-        onClick={onClickResolveConflict}
-        className="btn btn-outline-white"
-      >
-        <span className="material-symbols-outlined">description</span>
-        {t('modal_resolve_conflict.resolve_conflict')}
-      </button>
-    )}
-  </>,
-    };
-  }, [remoteRevisionLastUpdateUser, isConflict, t, onClickResolveConflict, refreshPage]);
+  if (!pageStatusAlertData?.isOpen || !!isGuestUser || !!isReadOnlyUser || !isRevisionOutdated) {
+    return <></>;
+  }
 
-  const alertComponentContents = useMemo(() => {
-    const isRevisionOutdated = revision?._id !== remoteRevisionId;
-
-    // 'revision?._id' and 'remoteRevisionId' are can not be undefined
-    if (revision?._id == null || remoteRevisionId == null) { return }
-
-    // when remote revision is newer than both
-    if (isRevisionOutdated) {
-      return getContentsForUpdatedAlert();
-    }
-
-    return null;
-  }, [revision?._id, remoteRevisionId, getContentsForUpdatedAlert]);
-
-  if (!!isGuestUser || !!isReadOnlyUser || alertComponentContents == null) { return <></> }
-
-  const { additionalClasses, label, btn } = alertComponentContents;
+  if (editorMode === pageStatusAlertData?.hideEditorMode) {
+    return <></>;
+  }
 
   return (
-    <div className={`${styles['grw-page-status-alert']} card text-white fixed-bottom animated fadeInUp faster ${additionalClasses.join(' ')}`}>
+    <div className={`${styles['grw-page-status-alert']} card fixed-bottom animated fadeInUp faster text-bg-warning`}>
       <div className="card-body">
         <p className="card-text grw-card-label-container">
-          {label}
+          { hasResolveConflictHandler
+            ? <>{t('modal_resolve_conflict.file_conflicting_with_newer_remote')}</>
+            : <><Username user={remoteRevisionLastUpdateUser} /> {t('edited this page')}</>
+          }
         </p>
         <p className="card-text grw-card-btn-container">
-          {btn}
+          {hasRefreshPageHandler && (
+            <button type="button" onClick={onClickRefreshPage} className="btn btn-outline-white">
+              <span className="material-symbols-outlined">refresh</span>{t('Load latest')}
+            </button>
+          )}
+          {hasResolveConflictHandler && (
+            <button type="button" onClick={onClickResolveConflict} className="btn btn-outline-white">
+              <span className="material-symbols-outlined">description</span>{t('modal_resolve_conflict.resolve_conflict')}
+            </button>
+          )}
         </p>
       </div>
     </div>
   );
-
 };

+ 10 - 0
apps/app/src/components/TableOfContents.module.scss

@@ -40,3 +40,13 @@
     border: solid 1px bs.$gray-400;
   }
 }
+
+
+// == Colors
+.revision-toc :global {
+  .revision-toc-content {
+    ::marker {
+      color: var(--bs-tertiary-color);
+    }
+  }
+}

+ 5 - 10
apps/app/src/pages/_app.page.tsx

@@ -1,29 +1,26 @@
-import React, { ReactElement, ReactNode, useEffect } from 'react';
+import type { ReactElement, ReactNode } from 'react';
+import React, { useEffect } from 'react';
 
-import { NextPage } from 'next';
+import type { NextPage } from 'next';
 import { appWithTranslation } from 'next-i18next';
-import { AppProps } from 'next/app';
+import type { AppProps } from 'next/app';
 import { SWRConfig } from 'swr';
 
 import * as nextI18nConfig from '^/config/next-i18next.config';
 
 import { GlobalFonts } from '~/components/FontFamily/GlobalFonts';
-import { useI18nextHMR } from '~/services/i18next-hmr';
 import {
   useAppTitle, useConfidential, useGrowiVersion, useSiteUrl, useIsDefaultLogo, useForcedColorScheme,
 } from '~/stores/context';
 import { swrGlobalConfiguration } from '~/utils/swr-utils';
 
-import { CommonProps } from './utils/commons';
+import type { CommonProps } from './utils/commons';
 import { registerTransformerForObjectId } from './utils/objectid-transformer';
 
 import '~/styles/prebuilt/vendor.css';
-import '~/styles/font-icons.scss';
 import '~/styles/style-app.scss';
 
 
-const isDev = process.env.NODE_ENV === 'development';
-
 // eslint-disable-next-line @typescript-eslint/ban-types
 export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
   getLayout?: (page: ReactElement) => ReactNode,
@@ -37,8 +34,6 @@ type GrowiAppProps = AppProps & {
 registerTransformerForObjectId();
 
 function GrowiApp({ Component, pageProps }: GrowiAppProps): JSX.Element {
-  useI18nextHMR(isDev);
-
   useEffect(() => {
     import('bootstrap/dist/js/bootstrap');
   }, []);

+ 3 - 2
apps/app/src/pages/_private-legacy-pages.page.tsx

@@ -6,6 +6,7 @@ import { useTranslation } from 'next-i18next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
+import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
@@ -48,8 +49,8 @@ const PrivateLegacyPage: NextPage<Props> = (props: Props) => {
   useCurrentUser(props.currentUser ?? null);
 
   // clear the cache for the current page
-  const { mutate } = useSWRxCurrentPage();
-  mutate(undefined, { revalidate: false });
+  //  in order to fix https://redmine.weseek.co.jp/issues/135811
+  useSWRxCurrentPage(null);
   useCurrentPageId(null);
   useCurrentPathname('/_private-legacy-pages');
 

+ 7 - 4
apps/app/src/pages/_search.page.tsx

@@ -4,7 +4,9 @@ import type { IUser } from '@growi/core';
 import type { GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { useTranslation } from 'next-i18next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
+import dynamic from 'next/dynamic';
 import Head from 'next/head';
+import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import SearchResultLayout from '~/components/Layout/SearchResultLayout';
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
@@ -16,8 +18,6 @@ import {
 } from '~/stores/context';
 import { useCurrentPageId, useSWRxCurrentPage } from '~/stores/page';
 
-import { SearchPage } from '../components/SearchPage';
-
 import type { NextPageWithLayout } from './_app.page';
 import type { CommonProps } from './utils/commons';
 import {
@@ -25,6 +25,9 @@ import {
 } from './utils/commons';
 
 
+const SearchPage = dynamic(() => import('../components/SearchPage').then(mod => mod.SearchPage), { ssr: false });
+
+
 type Props = CommonProps & {
   currentUser: IUser,
 
@@ -52,8 +55,8 @@ const SearchResultPage: NextPageWithLayout<Props> = (props: Props) => {
   useCurrentUser(props.currentUser ?? null);
 
   // clear the cache for the current page
-  const { mutate } = useSWRxCurrentPage();
-  mutate(undefined, { revalidate: false });
+  //  in order to fix https://redmine.weseek.co.jp/issues/135811
+  useSWRxCurrentPage(null);
   useCurrentPageId(null);
   useCurrentPathname('/_search');
 

+ 3 - 2
apps/app/src/pages/me/[[...path]].page.tsx

@@ -8,6 +8,7 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
 import { useRouter } from 'next/router';
+import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import { BasicLayout } from '~/components/Layout/BasicLayout';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
@@ -99,8 +100,8 @@ const MePage: NextPageWithLayout<Props> = (props: Props) => {
   useCurrentUser(props.currentUser ?? null);
 
   // clear the cache for the current page
-  const { mutate } = useSWRxCurrentPage();
-  mutate(undefined, { revalidate: false });
+  //  in order to fix https://redmine.weseek.co.jp/issues/135811
+  useSWRxCurrentPage(null);
   useCurrentPageId(null);
   useCurrentPathname('/me');
 

+ 3 - 2
apps/app/src/pages/tags.page.tsx

@@ -8,6 +8,7 @@ import { useTranslation } from 'next-i18next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
+import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import type { CrowiRequest } from '~/interfaces/crowi-request';
 import type { RendererConfig } from '~/interfaces/services/renderer';
@@ -49,8 +50,8 @@ const TagPage: NextPageWithLayout<CommonProps> = (props: Props) => {
   useCurrentUser(props.currentUser ?? null);
 
   // clear the cache for the current page
-  const { mutate } = useSWRxCurrentPage();
-  mutate(undefined, { revalidate: false });
+  //  in order to fix https://redmine.weseek.co.jp/issues/135811
+  useSWRxCurrentPage(null);
   useCurrentPageId(null);
   useCurrentPathname('/tags');
 

+ 6 - 11
apps/app/src/pages/trash.page.tsx

@@ -6,6 +6,7 @@ import type { GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
+import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import { PagePathNavSticky } from '~/components/Common/PagePathNav';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
@@ -43,8 +44,10 @@ const TrashPage: NextPageWithLayout<CommonProps> = (props: Props) => {
   useCurrentUser(props.currentUser ?? null);
 
   // clear the cache for the current page
-  const { mutate } = useSWRxCurrentPage();
-  mutate(undefined, { revalidate: false });
+  //  in order to fix https://redmine.weseek.co.jp/issues/135811
+  useSWRxCurrentPage(null);
+  useCurrentPageId(null);
+  useCurrentPathname('/trash');
 
   useGrowiCloudUri(props.growiCloudUri);
 
@@ -53,8 +56,6 @@ const TrashPage: NextPageWithLayout<CommonProps> = (props: Props) => {
   useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
 
   useIsSearchPage(false);
-  useCurrentPageId(null);
-  useCurrentPathname('/trash');
 
   // init sidebar config with UserUISettings and sidebarConfig
   useInitSidebarConfig(props.sidebarConfig, props.userUISettings);
@@ -69,16 +70,10 @@ const TrashPage: NextPageWithLayout<CommonProps> = (props: Props) => {
         <title>{title}</title>
       </Head>
       <div className="dynamic-layout-root">
-        <nav className="sticky-top">
-          TODO: implement navigation for /trash
-        </nav>
-
-        <div className="content-main container-lg mb-5 pb-5">
+        <div className="content-main container-lg mt-5 ms-md-5 ms-xl-0">
           <PagePathNavSticky pagePath="/trash" />
           <TrashPageList />
         </div>
-
-        <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
       </div>
     </>
   );

+ 0 - 22
apps/app/src/server/crowi/dev.js

@@ -2,8 +2,6 @@ import path from 'path';
 
 import express from 'express';
 
-import { i18n } from '^/config/next-i18next.config';
-
 import loggerFactory from '~/utils/logger';
 
 import nextFactory from '../routes/next';
@@ -24,8 +22,6 @@ class CrowiDev {
   }
 
   init() {
-    this.requireForAutoReloadServer();
-
     this.initPromiseRejectionWarningHandler();
   }
 
@@ -34,17 +30,6 @@ class CrowiDev {
     process.on('unhandledRejection', console.dir); // eslint-disable-line no-console
   }
 
-  /**
-   * require files for node-dev auto reloading
-   */
-  requireForAutoReloadServer() {
-    // load all json files for live reloading
-    i18n.locales
-      .forEach((localeId) => {
-        require(path.join(this.crowi.publicDir, 'static/locales', localeId, 'translation.json'));
-      });
-  }
-
   /**
    *
    * @param {any} app express
@@ -92,8 +77,6 @@ class CrowiDev {
   }
 
   setupExpressAfterListening(app) {
-    // this.setupBrowserSync(app);
-    this.setupWebpackHmr(app);
     this.setupNextjsStackFrame(app);
   }
 
@@ -102,11 +85,6 @@ class CrowiDev {
     app.use('/analyze', express.static(path.resolve(__dirname, '../../../.next/analyze')));
   }
 
-  setupWebpackHmr(app) {
-    const next = nextFactory(this.crowi);
-    app.all('/_next/webpack-hmr', next.delegateToNext);
-  }
-
   setupNextjsStackFrame(app) {
     const next = nextFactory(this.crowi);
     app.get('/__nextjs_original-stack-frame', next.delegateToNext);

+ 1 - 0
apps/app/src/server/models/vo/s2c-message.js

@@ -17,6 +17,7 @@ class S2cMessagePageUpdated {
     this.revisionId = revision;
     this.revisionBody = page.revision.body;
     this.revisionUpdateAt = updatedAt;
+    this.revisionOrigin = page.revision.origin;
 
     if (user != null) {
       this.remoteLastUpdateUser = user;

+ 1 - 1
apps/app/src/server/service/installer.ts

@@ -69,7 +69,7 @@ export class InstallerService {
      *   2. avoid difference for order in VRT
      */
     await this.createPage(path.join(localeDir, lang, 'sandbox.md'), '/Sandbox');
-    await this.createPage(path.join(localeDir, lang, 'sandbox-bootstrap4.md'), '/Sandbox/Bootstrap4');
+    await this.createPage(path.join(localeDir, lang, 'sandbox-bootstrap5.md'), '/Sandbox/Bootstrap5');
     await this.createPage(path.join(localeDir, lang, 'sandbox-diagrams.md'), '/Sandbox/Diagrams');
     await this.createPage(path.join(localeDir, lang, 'sandbox-math.md'), '/Sandbox/Math');
 

+ 0 - 26
apps/app/src/services/i18next-hmr.ts

@@ -1,26 +0,0 @@
-import { useEffect } from 'react';
-
-import { isServer } from '@growi/core/dist/utils';
-import { useTranslation } from 'next-i18next';
-
-export const useI18nextHMR = (isDev: boolean): void => {
-  const { i18n } = useTranslation();
-
-  useEffect(() => {
-    if (isDev) {
-      import('i18next-hmr/client').then(({ applyClientHMR }) => {
-        applyClientHMR(i18n);
-      });
-    }
-  }, [i18n, isDev]);
-
-  if (!isDev) {
-    return;
-  }
-
-  if ((isServer())) {
-    import('i18next-hmr/server').then(({ applyServerHMR }) => {
-      applyServerHMR(i18n);
-    });
-  }
-};

+ 39 - 0
apps/app/src/stores/alert.tsx

@@ -0,0 +1,39 @@
+import { useSWRStatic } from '@growi/core/dist/swr';
+import type { SWRResponse } from 'swr';
+
+import type { EditorMode } from './ui';
+
+/*
+* PageStatusAlert
+*/
+type OpenPageStatusAlertOptions = {
+  hideEditorMode?: EditorMode
+  onRefleshPage?: () => void
+  onResolveConflict?: () => void
+}
+
+type PageStatusAlertStatus = {
+  isOpen: boolean
+  hideEditorMode?: EditorMode,
+  onRefleshPage?: () => void
+  onResolveConflict?: () => void
+}
+
+type PageStatusAlertUtils = {
+  open: (openPageStatusAlert: OpenPageStatusAlertOptions) => void,
+  close: () => void,
+}
+export const usePageStatusAlert = (): SWRResponse<PageStatusAlertStatus, Error> & PageStatusAlertUtils => {
+  const initialData: PageStatusAlertStatus = { isOpen: false };
+  const swrResponse = useSWRStatic<PageStatusAlertStatus, Error>('pageStatusAlert', undefined, { fallbackData: initialData });
+
+  return {
+    ...swrResponse,
+    open({ ...options }) {
+      swrResponse.mutate({ isOpen: true, ...options });
+    },
+    close() {
+      swrResponse.mutate({ isOpen: false });
+    },
+  };
+};

+ 0 - 4
apps/app/src/stores/editor.tsx

@@ -120,7 +120,3 @@ export const usePageTagsForEditors = (pageId: Nullable<string>): SWRResponse<str
 export const useIsEnabledUnsavedWarning = (): SWRResponse<boolean, Error> => {
   return useStaticSWR<boolean, Error>('isEnabledUnsavedWarning');
 };
-
-export const useIsConflict = (): SWRResponse<boolean, Error> => {
-  return useStaticSWR<boolean, Error>('isConflict', undefined, { fallbackData: false });
-};

+ 0 - 5
apps/app/src/styles/font-icons.scss

@@ -1,5 +0,0 @@
-// DO NOT CHANGE THER OERDER OF font-awesome AND simple-line-icons.
-// font-familiy used in simple-line-icons has to be prioritized than the one used in font-awesome.
-@import 'font-awesome';
-@import 'simple-line-icons';
-@import '@icon/themify-icons/themify-icons';

+ 7 - 3
apps/app/tsconfig.build.client.json

@@ -1,10 +1,14 @@
 {
   "$schema": "http://json.schemastore.org/tsconfig",
   "extends": "./tsconfig.json",
+  "include": [
+    ".next/types/**/*.ts"
+  ],
   "compilerOptions": {
     "module": "ESNext",
-
     "strict": false,
+    "strictNullChecks": true,
+
     "noFallthroughCasesInSwitch": true,
     "incremental": true,
 
@@ -12,8 +16,8 @@
     "paths": {
       "~/*": ["./src/*"],
       "^/*": ["./*"],
-
       "debug": ["./src/server/utils/logger/alias-for-debug"]
-    }
+    },
+    "plugins": [{"name": "next"}]
   }
 }

+ 9 - 5
packages/editor/src/components/CodeMirrorEditor/CodeMirrorEditor.tsx

@@ -41,11 +41,13 @@ export type CodeMirrorEditorProps = {
 
 type Props = CodeMirrorEditorProps & {
   editorKey: string | GlobalCodeMirrorEditorKey,
+  hideToolbar?: boolean,
 }
 
 export const CodeMirrorEditor = (props: Props): JSX.Element => {
   const {
     editorKey,
+    hideToolbar,
     acceptedUploadFileType = AcceptedUploadFileType.NONE,
     indentSize,
     editorSettings,
@@ -209,11 +211,13 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
         <FileDropzoneOverlay isEnabled={isDragActive} />
         <CodeMirrorEditorContainer ref={containerRef} />
       </div>
-      <Toolbar
-        editorKey={editorKey}
-        acceptedUploadFileType={acceptedUploadFileType}
-        onUpload={onUpload}
-      />
+      { !hideToolbar && (
+        <Toolbar
+          editorKey={editorKey}
+          acceptedUploadFileType={acceptedUploadFileType}
+          onUpload={onUpload}
+        />
+      ) }
     </div>
   );
 };

+ 39 - 0
packages/editor/src/components/CodeMirrorEditorReadOnly.tsx

@@ -0,0 +1,39 @@
+import { useEffect } from 'react';
+
+import { type Extension, EditorState } from '@codemirror/state';
+
+import { GlobalCodeMirrorEditorKey } from '../consts';
+import { setDataLine } from '../services/extensions/setDataLine';
+import { useCodeMirrorEditorIsolated } from '../stores';
+
+import { CodeMirrorEditor } from '.';
+
+const additionalExtensions: Extension[] = [
+  [
+    setDataLine,
+    EditorState.readOnly.of(true),
+  ],
+];
+
+type Props = {
+  markdown?: string,
+  onScroll?: () => void,
+}
+
+export const CodeMirrorEditorReadOnly = ({ markdown, onScroll }: Props): JSX.Element => {
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.READONLY);
+
+  codeMirrorEditor?.initDoc(markdown);
+
+  useEffect(() => {
+    return codeMirrorEditor?.appendExtensions?.(additionalExtensions);
+  }, [codeMirrorEditor]);
+
+  return (
+    <CodeMirrorEditor
+      hideToolbar
+      editorKey={GlobalCodeMirrorEditorKey.READONLY}
+      onScroll={onScroll}
+    />
+  );
+};

+ 1 - 0
packages/editor/src/components/index.ts

@@ -1,5 +1,6 @@
 export * from './CodeMirrorEditor';
 export * from './CodeMirrorEditorMain';
+export * from './CodeMirrorEditorReadOnly';
 export * from './CodeMirrorEditorComment';
 export * from './CodeMirrorEditorDiff';
 export * from './MergeViewer';

+ 1 - 0
packages/editor/src/consts/global-code-mirror-editor-key.ts

@@ -2,5 +2,6 @@ export const GlobalCodeMirrorEditorKey = {
   MAIN: 'main',
   COMMENT: 'comment',
   DIFF: 'diff',
+  READONLY: 'readonly',
 } as const;
 export type GlobalCodeMirrorEditorKey = typeof GlobalCodeMirrorEditorKey[keyof typeof GlobalCodeMirrorEditorKey]

+ 1 - 1
packages/presentation/package.json

@@ -46,7 +46,7 @@
   },
   "peerDependencies": {
     "@marp-team/marpit": "*",
-    "next": "^13",
+    "next": "^14",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
   }

+ 1 - 1
packages/remark-lsx/package.json

@@ -50,7 +50,7 @@
     "unist-util-visit": "^4.0.0"
   },
   "peerDependencies": {
-    "next": "^13",
+    "next": "^14",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
   }

+ 1 - 1
packages/ui/package.json

@@ -40,7 +40,7 @@
     "reactstrap": "^9.2.0"
   },
   "peerDependencies": {
-    "next": "^13",
+    "next": "^14",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
   }

+ 180 - 238
yarn.lock

@@ -1176,13 +1176,20 @@
     core-js-pure "^3.20.2"
     regenerator-runtime "^0.13.4"
 
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.8", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.19.4", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.6", "@babel/runtime@^7.22.15", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.8", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.22.15", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
   version "7.23.6"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.6.tgz#c05e610dc228855dc92ef1b53d07389ed8ab521d"
   integrity sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==
   dependencies:
     regenerator-runtime "^0.14.0"
 
+"@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9":
+  version "7.24.0"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e"
+  integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==
+  dependencies:
+    regenerator-runtime "^0.14.0"
+
 "@babel/template@^7.22.15", "@babel/template@^7.23.9", "@babel/template@^7.3.3":
   version "7.23.9"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.23.9.tgz#f881d0487cba2828d3259dcb9ef5005a9731011a"
@@ -1591,6 +1598,11 @@
     debug "^3.1.0"
     lodash.once "^4.1.1"
 
+"@discoveryjs/json-ext@0.5.7":
+  version "0.5.7"
+  resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
+  integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
+
 "@elastic/elasticsearch7@npm:@elastic/elasticsearch@^7.17.0":
   version "7.17.0"
   resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.17.0.tgz#589fb219234cf1b0da23744e82b1d25e2fe9a797"
@@ -1964,11 +1976,6 @@
   resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
   integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
 
-"@icon/themify-icons@1.0.1-alpha.3":
-  version "1.0.1-alpha.3"
-  resolved "https://registry.yarnpkg.com/@icon/themify-icons/-/themify-icons-1.0.1-alpha.3.tgz#adb1652d37d4e58f507b1634785a3779f6829e0b"
-  integrity sha512-KDE5pjBgnEVugPhcQxBmhMMT+5n2YU/A6yHHeDHSGL68gHaLp27a5WxV4LVakN0kiiA3MVdSkUPdX6n/UWS7zw==
-
 "@isaacs/cliui@^8.0.2":
   version "8.0.2"
   resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
@@ -2625,17 +2632,17 @@
   dependencies:
     sparse-bitfield "^3.0.3"
 
-"@next/bundle-analyzer@^13.2.3":
-  version "13.2.4"
-  resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-13.2.4.tgz#ad319bf566528f8afee34df07574fd97170b03f2"
-  integrity sha512-bY4Clt7f1roJextpeQOQQWfNiXI0O5UvfOEyfuM5YUGPQMOCAZD2zjLjolakdn9Dm2yyMQUQ6JDE+iJK0dIeLA==
+"@next/bundle-analyzer@^14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-14.1.3.tgz#2aa561c16838b72af792029e0c7a9d52f794f9c5"
+  integrity sha512-QjMT5RGqvaObprL4Oim4SsjWUW6DxxfG+Fhq9arGw4CHbPBsjQkNWgUtW3WWW/Bjh4VhT+YBsJfxTyBVPHIlVw==
   dependencies:
-    webpack-bundle-analyzer "4.7.0"
+    webpack-bundle-analyzer "4.10.1"
 
-"@next/env@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/env/-/env-13.3.0.tgz#cc2e49f03060a4684ce7ec7fd617a21bc5b9edba"
-  integrity sha512-AjppRV4uG3No7L1plinoTQETH+j2F10TEnrMfzbTUYwze5sBUPveeeBAPZPm8OkJZ1epq9OyYKhZrvbD6/9HCQ==
+"@next/env@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/env/-/env-14.1.3.tgz#73007b64d487bbb95ed83145195f734fc1182d10"
+  integrity sha512-VhgXTvrgeBRxNPjyfBsDIMvgsKDxjlpw4IAUsHCX8Gjl1vtHUYRT3+xfQ/wwvLPDd/6kqfLqk9Pt4+7gysuCKQ==
 
 "@next/eslint-plugin-next@12.1.6":
   version "12.1.6"
@@ -2644,50 +2651,50 @@
   dependencies:
     glob "7.1.7"
 
-"@next/swc-darwin-arm64@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.0.tgz#38f18e0639cd4c7edc6a38d4b83fe00f38eea4f2"
-  integrity sha512-DmIQCNq6JtccLPPBzf0dgh2vzMWt5wjxbP71pCi5EWpWYE3MsP6FcRXi4MlAmFNDQOfcFXR2r7kBeG1LpZUh1w==
-
-"@next/swc-darwin-x64@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.0.tgz#b670ed1fd1d231aa21279173ec52e3ad56dc6aeb"
-  integrity sha512-oQoqFa88OGgwnYlnAGHVct618FRI/749se0N3S8t9Bzdv5CRbscnO0RcX901+YnNK4Q6yeiizfgO3b7kogtsZg==
-
-"@next/swc-linux-arm64-gnu@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.0.tgz#b114935f6b4c94c123f6cac55a4823d483209ba5"
-  integrity sha512-Wzz2p/WqAJUqTVoLo6H18WMeAXo3i+9DkPDae4oQG8LMloJ3if4NEZTnOnTUlro6cq+S/W4pTGa97nWTrOjbGw==
-
-"@next/swc-linux-arm64-musl@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.0.tgz#67a57309f8761c7d00d629d6785d56ed0567a0d2"
-  integrity sha512-xPVrIQOQo9WXJYgmoTlMnAD/HlR/1e1ZIWGbwIzEirXBVBqMARUulBEIKdC19zuvoJ477qZJgBDCKtKEykCpyQ==
-
-"@next/swc-linux-x64-gnu@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.0.tgz#11bd2bea7c00b40be111c0dd16e71171f3792086"
-  integrity sha512-jOFlpGuPD7W2tuXVJP4wt9a3cpNxWAPcloq5EfMJRiXsBBOjLVFZA7boXYxEBzSVgUiVVr1V9T0HFM7pULJ1qA==
-
-"@next/swc-linux-x64-musl@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.0.tgz#d57e99f85890799b78719c3ea32a4624de8d701b"
-  integrity sha512-2OwKlzaBgmuet9XYHc3KwsEilzb04F540rlRXkAcjMHL7eCxB7uZIGtsVvKOnQLvC/elrUegwSw1+5f7WmfyOw==
-
-"@next/swc-win32-arm64-msvc@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.0.tgz#0c209aa35d1c88b01e78259a89cd68f4139b5093"
-  integrity sha512-OeHiA6YEvndxT46g+rzFK/MQTfftKxJmzslERMu9LDdC6Kez0bdrgEYed5eXFK2Z1viKZJCGRlhd06rBusyztA==
-
-"@next/swc-win32-ia32-msvc@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.0.tgz#52ae74da1dd6d840c3743923367d27ed013803dd"
-  integrity sha512-4aB7K9mcVK1lYEzpOpqWrXHEZympU3oK65fnNcY1Qc4HLJFLJj8AViuqQd4jjjPNuV4sl8jAwTz3gN5VNGWB7w==
-
-"@next/swc-win32-x64-msvc@13.3.0":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.0.tgz#db7b55fee834dc8c2c484c696469e65bae2ee770"
-  integrity sha512-Reer6rkLLcoOvB0dd66+Y7WrWVFH7sEEkF/4bJCIfsSKnTStTYaHtwIJAwbqnt9I392Tqvku0KkoqZOryWV9LQ==
+"@next/swc-darwin-arm64@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.3.tgz#b4c218fdb49275972d91e9a9a0ccadba243b6739"
+  integrity sha512-LALu0yIBPRiG9ANrD5ncB3pjpO0Gli9ZLhxdOu6ZUNf3x1r3ea1rd9Q+4xxUkGrUXLqKVK9/lDkpYIJaCJ6AHQ==
+
+"@next/swc-darwin-x64@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.3.tgz#aa0d4357179d68daaa6f400708b76666708ffec9"
+  integrity sha512-E/9WQeXxkqw2dfcn5UcjApFgUq73jqNKaE5bysDm58hEUdUGedVrnRhblhJM7HbCZNhtVl0j+6TXsK0PuzXTCg==
+
+"@next/swc-linux-arm64-gnu@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.3.tgz#1ba8df39c04368ede185f268c3a817a8f4290e4c"
+  integrity sha512-USArX9B+3rZSXYLFvgy0NVWQgqh6LHWDmMt38O4lmiJNQcwazeI6xRvSsliDLKt+78KChVacNiwvOMbl6g6BBw==
+
+"@next/swc-linux-arm64-musl@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.3.tgz#2fa8fe435862eb186aca6d6068c8aef2126ab11e"
+  integrity sha512-esk1RkRBLSIEp1qaQXv1+s6ZdYzuVCnDAZySpa62iFTMGTisCyNQmqyCTL9P+cLJ4N9FKCI3ojtSfsyPHJDQNw==
+
+"@next/swc-linux-x64-gnu@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.3.tgz#57a687b44337af219e07a79ecc8c63a3c1b2d020"
+  integrity sha512-8uOgRlYEYiKo0L8YGeS+3TudHVDWDjPVDUcST+z+dUzgBbTEwSSIaSgF/vkcC1T/iwl4QX9iuUyUdQEl0Kxalg==
+
+"@next/swc-linux-x64-musl@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.3.tgz#8c057f8f7fb9679915df25eda6ab0ea1b7af85ff"
+  integrity sha512-DX2zqz05ziElLoxskgHasaJBREC5Y9TJcbR2LYqu4r7naff25B4iXkfXWfcp69uD75/0URmmoSgT8JclJtrBoQ==
+
+"@next/swc-win32-arm64-msvc@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.3.tgz#5367333e701f722009592013502aa8e735bee782"
+  integrity sha512-HjssFsCdsD4GHstXSQxsi2l70F/5FsRTRQp8xNgmQs15SxUfUJRvSI9qKny/jLkY3gLgiCR3+6A7wzzK0DBlfA==
+
+"@next/swc-win32-ia32-msvc@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.3.tgz#dc455021fee85e037f6fb4134e85895dce5a0495"
+  integrity sha512-DRuxD5axfDM1/Ue4VahwSxl1O5rn61hX8/sF0HY8y0iCbpqdxw3rB3QasdHn/LJ6Wb2y5DoWzXcz3L1Cr+Thrw==
+
+"@next/swc-win32-x64-msvc@14.1.3":
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.3.tgz#4a8d4384901f0c48ece9dbb60cb9aea107d39e7c"
+  integrity sha512-uC2DaDoWH7h1P/aJ4Fok3Xiw6P0Lo4ez7NbowW2VGNXw/Xv6tOuLUcxhBYZxsSUJtpeknCi8/fvnSpyCFp4Rcg==
 
 "@node-rs/xxhash-android-arm-eabi@1.3.0":
   version "1.3.0"
@@ -3578,7 +3585,14 @@
     "@swc/core-win32-ia32-msvc" "1.3.36"
     "@swc/core-win32-x64-msvc" "1.3.36"
 
-"@swc/helpers@0.4.14", "@swc/helpers@^0.4.14":
+"@swc/helpers@0.5.2":
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d"
+  integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==
+  dependencies:
+    tslib "^2.4.0"
+
+"@swc/helpers@^0.4.14":
   version "0.4.14"
   resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74"
   integrity sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==
@@ -3980,10 +3994,10 @@
   dependencies:
     "@types/unist" "*"
 
-"@types/hoist-non-react-statics@^3.3.1":
-  version "3.3.1"
-  resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
-  integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
+"@types/hoist-non-react-statics@^3.3.4":
+  version "3.3.5"
+  resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494"
+  integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==
   dependencies:
     "@types/react" "*"
     hoist-non-react-statics "^3.3.0"
@@ -5798,11 +5812,16 @@ can-use-dom@^0.1.0:
   resolved "https://registry.yarnpkg.com/can-use-dom/-/can-use-dom-0.1.0.tgz#22cc4a34a0abc43950f42c6411024a3f6366b45a"
   integrity sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo=
 
-caniuse-lite@^1.0.30000865, caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001580:
+caniuse-lite@^1.0.30000865, caniuse-lite@^1.0.30001580:
   version "1.0.30001582"
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001582.tgz#db3070547ce0b48d9f44a509b86c4a02ba5d9055"
   integrity sha512-vsJG3V5vgfduaQGVxL53uSX/HUzxyr2eA8xCo36OLal7sRcSZbibJtLeh0qja4sFOr/QQGt4opB4tOy+eOgAxg==
 
+caniuse-lite@^1.0.30001579:
+  version "1.0.30001599"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz#571cf4f3f1506df9bf41fcbb6d10d5d017817bce"
+  integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==
+
 capital-case@^1.0.4:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669"
@@ -6506,13 +6525,6 @@ cookie@~0.4.1:
   resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
   integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
 
-copy-anything@^2.0.1:
-  version "2.0.6"
-  resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480"
-  integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==
-  dependencies:
-    is-what "^3.14.1"
-
 copy-anything@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-3.0.2.tgz#7189171ff5e1893b2287e8bf574b8cd448ed50b1"
@@ -6643,12 +6655,12 @@ cross-env@^7.0.0:
   dependencies:
     cross-spawn "^7.0.1"
 
-cross-fetch@3.1.5:
-  version "3.1.5"
-  resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
-  integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
+cross-fetch@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983"
+  integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==
   dependencies:
-    node-fetch "2.6.7"
+    node-fetch "^2.6.12"
 
 cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
   version "7.0.3"
@@ -7148,6 +7160,11 @@ dayjs@^1.10.4, dayjs@^1.11.7:
   resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
   integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
 
+debounce@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
+  integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
+
 debug@2.6.9, debug@^2.0.0, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
   version "2.6.9"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -7776,7 +7793,7 @@ err-code@^2.0.2:
   resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
   integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
 
-errno@^0.1.1, errno@~0.1.1:
+errno@~0.1.1:
   version "0.1.8"
   resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
   integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
@@ -8747,11 +8764,6 @@ follow-redirects@^1.14.0, follow-redirects@^1.14.4, follow-redirects@^1.14.8, fo
   resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
   integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
 
-font-awesome@^4.7.0:
-  version "4.7.0"
-  resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
-  integrity sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==
-
 for-each@^0.3.3:
   version "0.3.3"
   resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
@@ -9294,7 +9306,7 @@ google-p12-pem@^3.0.3:
   dependencies:
     node-forge "^0.10.0"
 
-graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
+graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
   version "4.2.11"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
   integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -9708,6 +9720,11 @@ html-escaper@^2.0.0:
   resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491"
   integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==
 
+html-escaper@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
+  integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
 html-parse-stringify@^3.0.1:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
@@ -9847,43 +9864,43 @@ humanize-ms@^1.2.1:
   dependencies:
     ms "^2.0.0"
 
-i18next-chained-backend@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/i18next-chained-backend/-/i18next-chained-backend-4.0.0.tgz#97679ee4b6e04e1ad96e49b3c4ab755ff62238eb"
-  integrity sha512-gOfkl2tvRDSMKQ2vaYbP+n5fsHeYM/836/Co8/NVP8LplRE8Ck7IrKWswp4vKw4D5Ji7cEdzA4drrG4ssgsXIg==
+i18next-chained-backend@^4.6.2:
+  version "4.6.2"
+  resolved "https://registry.yarnpkg.com/i18next-chained-backend/-/i18next-chained-backend-4.6.2.tgz#96bd1fd8c0f719154040665b435cf3f032d7ccec"
+  integrity sha512-2P092fR+nAPQlGzPUoIIxbwo7PTBqQYgLxwv1XhSTQUAUoelLo5LkX+FqRxxSDg9WEAsrc8+2WL6mJtMGIa6WQ==
   dependencies:
-    "@babel/runtime" "^7.19.4"
+    "@babel/runtime" "^7.23.2"
 
-i18next-fs-backend@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz#07c6393be856c5a398e3dfc1257bf8439841cd89"
-  integrity sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA==
+i18next-fs-backend@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-2.3.1.tgz#0c7d2459ff4a039e2b3228131809fbc0e74ff1a8"
+  integrity sha512-tvfXskmG/9o+TJ5Fxu54sSO5OkY6d+uMn+K6JiUGLJrwxAVfer+8V3nU8jq3ts9Pe5lXJv4b1N7foIjJ8Iy2Gg==
 
-i18next-hmr@^1.11.0:
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/i18next-hmr/-/i18next-hmr-1.11.0.tgz#2c474f68910f2f45d10ce7c76402a99bb0dc589f"
-  integrity sha512-OUKJ9oCwLjlBQ4rbB8PAaYVzsOcl6FjeRM1yA6kqyzfpS7uSNgk0aGhSIZ6vexu1Wu6Ymi3dTKM9rseUG+5Mog==
+i18next-hmr@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/i18next-hmr/-/i18next-hmr-3.0.4.tgz#d3a7037bc32d0a80640339814fe98c711b218f24"
+  integrity sha512-vTcCn8SBO8BRfspkyiKYBKdXo397q+MCvIAdmtP9pstj9VZXI0xU7KhhVnoCDm7cTKVRHDTpZyN1YAfbKBtEWw==
 
-i18next-http-backend@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.0.0.tgz#7be736eb4c592e110b9ee54a985b737248d1c43f"
-  integrity sha512-6aFT5LcDOSxFyaoezruIxZDzpp6nu92j1iZc444nrz/OOaF7rsxQFNi1es19la53MQQFzG7uD2Koxi7Jav8khg==
+i18next-http-backend@^2.5.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.5.0.tgz#8396a7df30bfe722eff7a65f629df32a61720414"
+  integrity sha512-Z/aQsGZk1gSxt2/DztXk92DuDD20J+rNudT7ZCdTrNOiK8uQppfvdjq9+DFQfpAnFPn3VZS+KQIr1S/W1KxhpQ==
   dependencies:
-    cross-fetch "3.1.5"
+    cross-fetch "4.0.0"
 
-i18next-localstorage-backend@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/i18next-localstorage-backend/-/i18next-localstorage-backend-4.0.0.tgz#bd1b4318fe0f97baa1121dbb31c0c57e61e45a5d"
-  integrity sha512-XErjf0Zvciw3fo9/vzU1hWQfwHViq8l31ahKEvf6lgtqysPCtCBxNlIdrSjVZWEe76LD/thox1ixmO9PmlsL/w==
+i18next-localstorage-backend@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/i18next-localstorage-backend/-/i18next-localstorage-backend-4.2.0.tgz#b25e8943f4e135bf55da016cf4bddc26588ba609"
+  integrity sha512-vglEQF0AnLriX7dLA2drHnqAYzHxnLwWQzBDw8YxcIDjOvYZz5rvpal59Dq4In+IHNmGNM32YgF0TDjBT0fHmA==
   dependencies:
-    "@babel/runtime" "^7.19.4"
+    "@babel/runtime" "^7.22.15"
 
-i18next@^22.4.10:
-  version "22.4.11"
-  resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.4.11.tgz#8b6c9be95176de90d3f10a78af125d95d3a3258d"
-  integrity sha512-ShfTzXVMjXdF2iPiT/wbizOrssLh9Ab6VpuVROihLCAu+u25KbZiEYVgsA0W6g0SgjPa/JmGWcUEV/g6cKzEjQ==
+i18next@^23.10.1:
+  version "23.10.1"
+  resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.10.1.tgz#217ce93b75edbe559ac42be00a20566b53937df6"
+  integrity sha512-NDiIzFbcs3O9PXpfhkjyf7WdqFn5Vq6mhzhtkXzj51aOcNuPNcTwuYNuXCpHsanZGHlHKL35G7huoFeVic1hng==
   dependencies:
-    "@babel/runtime" "^7.20.6"
+    "@babel/runtime" "^7.23.2"
 
 iconv-lite@0.4.24, iconv-lite@^0.4.24:
   version "0.4.24"
@@ -9918,11 +9935,6 @@ ignore@^5.1.4, ignore@^5.2.0:
   resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
   integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
 
-image-size@~0.5.0:
-  version "0.5.5"
-  resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
-  integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
-
 image2uri@~1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/image2uri/-/image2uri-1.0.5.tgz#b85919fb5accb42ab4db0ae30a0d00afa932ce99"
@@ -10487,11 +10499,6 @@ is-weakset@^2.0.1:
     call-bind "^1.0.2"
     get-intrinsic "^1.1.1"
 
-is-what@^3.14.1:
-  version "3.14.1"
-  resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
-  integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
-
 is-what@^4.1.6:
   version "4.1.7"
   resolved "https://registry.yarnpkg.com/is-what/-/is-what-4.1.7.tgz#c41dc1d2d2d6a9285c624c2505f61849c8b1f9cc"
@@ -11404,22 +11411,6 @@ ldapjs@^3.0.2:
     vasync "^2.2.1"
     verror "^1.10.1"
 
-less@^3.12.2:
-  version "3.13.1"
-  resolved "https://registry.yarnpkg.com/less/-/less-3.13.1.tgz#0ebc91d2a0e9c0c6735b83d496b0ab0583077909"
-  integrity sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==
-  dependencies:
-    copy-anything "^2.0.1"
-    tslib "^1.10.0"
-  optionalDependencies:
-    errno "^0.1.1"
-    graceful-fs "^4.1.2"
-    image-size "~0.5.0"
-    make-dir "^2.1.0"
-    mime "^1.4.1"
-    native-request "^1.0.5"
-    source-map "~0.6.0"
-
 level-codec@^9.0.0:
   version "9.0.2"
   resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc"
@@ -11866,14 +11857,6 @@ make-dir@3.1.0, make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
   dependencies:
     semver "^6.0.0"
 
-make-dir@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
-  integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
-  dependencies:
-    pify "^4.0.1"
-    semver "^5.6.0"
-
 make-dir@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e"
@@ -12691,7 +12674,7 @@ mime-types@^2.0.8, mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.19, m
   dependencies:
     mime-db "1.51.0"
 
-mime@1.6.0, mime@^1.4.1:
+mime@1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
   integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
@@ -13138,7 +13121,7 @@ nan@^2.14.0, nan@^2.14.2:
   resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554"
   integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==
 
-nanoid@^3.3.4, nanoid@^3.3.6:
+nanoid@^3.3.6:
   version "3.3.6"
   resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
   integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
@@ -13165,11 +13148,6 @@ napi-macros@~2.0.0:
   resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b"
   integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==
 
-native-request@^1.0.5:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/native-request/-/native-request-1.1.0.tgz#acdb30fe2eefa3e1bc8c54b3a6852e9c5c0d3cb0"
-  integrity sha512-uZ5rQaeRn15XmpgE0xoPL8YWqcX90VtCFglYwAgkvKM5e8fog+vePLAhHxuuv/gRkrQxIeh5U3q9sMNUrENqWw==
-
 natural-compare-lite@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
@@ -13205,16 +13183,16 @@ new-find-package-json@^2.0.0:
   dependencies:
     debug "^4.3.4"
 
-next-i18next@^13.2.1:
-  version "13.2.2"
-  resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-13.2.2.tgz#9609546fab1d1d5f9b227e86c5ca23d0cbbbddb4"
-  integrity sha512-t0WU6K+HJoq2nVQ0n6OiiEZja9GyMqtDSU74FmOafgk4ljns+iZ18bsNJiI8rOUXfFfkW96ea1N7D5kbMyT+PA==
+next-i18next@^15.2.0:
+  version "15.2.0"
+  resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-15.2.0.tgz#96455f282b0dbd0319ce9647b3c319fb50258681"
+  integrity sha512-Rl5yZ4oGffsB0AjRykZ5PzNQ2M6am54MaMayldGmH/UKZisrIxk2SKEPJvaHhKlWe1qgdNi2FkodwK8sEjfEmg==
   dependencies:
-    "@babel/runtime" "^7.20.13"
-    "@types/hoist-non-react-statics" "^3.3.1"
+    "@babel/runtime" "^7.23.2"
+    "@types/hoist-non-react-statics" "^3.3.4"
     core-js "^3"
     hoist-non-react-statics "^3.3.2"
-    i18next-fs-backend "^2.1.1"
+    i18next-fs-backend "^2.3.1"
 
 next-superjson@^0.0.4:
   version "0.0.4"
@@ -13232,27 +13210,28 @@ next-themes@^0.2.1:
   resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.2.1.tgz#0c9f128e847979daf6c67f70b38e6b6567856e45"
   integrity sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==
 
-next@^13.3.0:
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/next/-/next-13.3.0.tgz#40632d303d74fc8521faa0a5bf4a033a392749b1"
-  integrity sha512-OVTw8MpIPa12+DCUkPqRGPS3thlJPcwae2ZL4xti3iBff27goH024xy4q2lhlsdoYiKOi8Kz6uJoLW/GXwgfOA==
+next@^14.1.3:
+  version "14.1.3"
+  resolved "https://registry.yarnpkg.com/next/-/next-14.1.3.tgz#465bb21a1a6e703e776ca53ea71d05642867fdb5"
+  integrity sha512-oexgMV2MapI0UIWiXKkixF8J8ORxpy64OuJ/J9oVUmIthXOUCcuVEZX+dtpgq7wIfIqtBwQsKEDXejcjTsan9g==
   dependencies:
-    "@next/env" "13.3.0"
-    "@swc/helpers" "0.4.14"
+    "@next/env" "14.1.3"
+    "@swc/helpers" "0.5.2"
     busboy "1.6.0"
-    caniuse-lite "^1.0.30001406"
-    postcss "8.4.14"
+    caniuse-lite "^1.0.30001579"
+    graceful-fs "^4.2.11"
+    postcss "8.4.31"
     styled-jsx "5.1.1"
   optionalDependencies:
-    "@next/swc-darwin-arm64" "13.3.0"
-    "@next/swc-darwin-x64" "13.3.0"
-    "@next/swc-linux-arm64-gnu" "13.3.0"
-    "@next/swc-linux-arm64-musl" "13.3.0"
-    "@next/swc-linux-x64-gnu" "13.3.0"
-    "@next/swc-linux-x64-musl" "13.3.0"
-    "@next/swc-win32-arm64-msvc" "13.3.0"
-    "@next/swc-win32-ia32-msvc" "13.3.0"
-    "@next/swc-win32-x64-msvc" "13.3.0"
+    "@next/swc-darwin-arm64" "14.1.3"
+    "@next/swc-darwin-x64" "14.1.3"
+    "@next/swc-linux-arm64-gnu" "14.1.3"
+    "@next/swc-linux-arm64-musl" "14.1.3"
+    "@next/swc-linux-x64-gnu" "14.1.3"
+    "@next/swc-linux-x64-musl" "14.1.3"
+    "@next/swc-win32-arm64-msvc" "14.1.3"
+    "@next/swc-win32-ia32-msvc" "14.1.3"
+    "@next/swc-win32-x64-msvc" "14.1.3"
 
 nice-try@^1.0.4:
   version "1.0.4"
@@ -13292,14 +13271,7 @@ node-fetch-h2@^2.3.0:
   dependencies:
     http2-client "^1.2.5"
 
-node-fetch@2.6.7:
-  version "2.6.7"
-  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
-  integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
-  dependencies:
-    whatwg-url "^5.0.0"
-
-node-fetch@^2.3.0, node-fetch@^2.6.1, node-fetch@^2.6.7:
+node-fetch@^2.3.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7:
   version "2.7.0"
   resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
   integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
@@ -14193,10 +14165,6 @@ pify@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
 
-pify@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
-
 pikaday@1.5.1:
   version "1.5.1"
   resolved "https://registry.npmjs.org/pikaday/-/pikaday-1.5.1.tgz#0a48549bc1a14ea1d08c44074d761bc2f2bfcfd3"
@@ -14311,12 +14279,12 @@ postcss-value-parser@^4.1.0:
   resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
   integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
 
-postcss@8.4.14:
-  version "8.4.14"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
-  integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
+postcss@8.4.31, postcss@^8.3.11, postcss@^8.4.19, postcss@^8.4.21, postcss@^8.4.27, postcss@^8.4.31:
+  version "8.4.31"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
+  integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
   dependencies:
-    nanoid "^3.3.4"
+    nanoid "^3.3.6"
     picocolors "^1.0.0"
     source-map-js "^1.0.2"
 
@@ -14328,15 +14296,6 @@ postcss@^7.0.0:
     picocolors "^0.2.1"
     source-map "^0.6.1"
 
-postcss@^8.3.11, postcss@^8.4.19, postcss@^8.4.21, postcss@^8.4.27, postcss@^8.4.31:
-  version "8.4.31"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
-  integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
-  dependencies:
-    nanoid "^3.3.6"
-    picocolors "^1.0.0"
-    source-map-js "^1.0.2"
-
 precond@0.2:
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac"
@@ -14730,12 +14689,12 @@ react-hotkeys@^2.0.0:
   dependencies:
     prop-types "^15.6.1"
 
-react-i18next@^12.2.0:
-  version "12.2.0"
-  resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-12.2.0.tgz#010e3f6070b8d700442947233352ebe4b252d7a1"
-  integrity sha512-5XeVgSygaGfyFmDd2WcXvINRw2WEC1XviW1LXY/xLOEMzsCFRwKqfnHN+hUjla8ZipbVJR27GCMSuTr0BhBBBQ==
+react-i18next@^14.1.0:
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-14.1.0.tgz#44da74fbffd416f5d0c5307ef31735cf10cc91d9"
+  integrity sha512-3KwX6LHpbvGQ+sBEntjV4sYW3Zovjjl3fpoHbUwSgFHf0uRBcbeCBLR5al6ikncI5+W0EFb71QXZmfop+J6NrQ==
   dependencies:
-    "@babel/runtime" "^7.20.6"
+    "@babel/runtime" "^7.23.9"
     html-parse-stringify "^3.0.1"
 
 react-image-crop@^8.3.0:
@@ -16008,13 +15967,6 @@ signal-exit@^4.0.1:
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967"
   integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==
 
-simple-line-icons@^2.5.5:
-  version "2.5.5"
-  resolved "https://registry.yarnpkg.com/simple-line-icons/-/simple-line-icons-2.5.5.tgz#32ea1babd842a28cc1764537ba5535e0b8f42be7"
-  integrity sha512-v52iGG/qFZTSD/70yOfA1lYoN6zmjEfDjzFT6U6jNSCsh/aeVjy+8sYyTXWz1w7tLIkN2XeMmG+cLJp/0zYK4Q==
-  dependencies:
-    less "^3.12.2"
-
 simple-load-script@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/simple-load-script/-/simple-load-script-1.0.2.tgz#d92951fe7b601ad90af8c9429bd4b2ee127ab8a3"
@@ -16046,15 +15998,6 @@ simplebar@^5.3.6:
     lodash.memoize "^4.1.2"
     lodash.throttle "^4.1.1"
 
-sirv@^1.0.7:
-  version "1.0.19"
-  resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49"
-  integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==
-  dependencies:
-    "@polka/url" "^1.0.0-next.20"
-    mrmime "^1.0.0"
-    totalist "^1.0.0"
-
 sirv@^2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.3.tgz#ca5868b87205a74bef62a469ed0296abceccd446"
@@ -16259,7 +16202,7 @@ source-map@^0.5.6:
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
   integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
 
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
 
@@ -17243,11 +17186,6 @@ toml-eslint-parser@^0.7.0:
   dependencies:
     eslint-visitor-keys "^3.0.0"
 
-totalist@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
-  integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
-
 totalist@^3.0.0:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8"
@@ -17436,7 +17374,7 @@ tslib@2.2.0:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
   integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
 
-tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1:
+tslib@^1.11.1, tslib@^1.8.1:
   version "1.14.1"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
@@ -18210,19 +18148,23 @@ webidl-conversions@^7.0.0:
   resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a"
   integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==
 
-webpack-bundle-analyzer@4.7.0:
-  version "4.7.0"
-  resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz#33c1c485a7fcae8627c547b5c3328b46de733c66"
-  integrity sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==
+webpack-bundle-analyzer@4.10.1:
+  version "4.10.1"
+  resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz#84b7473b630a7b8c21c741f81d8fe4593208b454"
+  integrity sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==
   dependencies:
+    "@discoveryjs/json-ext" "0.5.7"
     acorn "^8.0.4"
     acorn-walk "^8.0.0"
-    chalk "^4.1.0"
     commander "^7.2.0"
+    debounce "^1.2.1"
+    escape-string-regexp "^4.0.0"
     gzip-size "^6.0.0"
-    lodash "^4.17.20"
+    html-escaper "^2.0.2"
+    is-plain-object "^5.0.0"
     opener "^1.5.2"
-    sirv "^1.0.7"
+    picocolors "^1.0.0"
+    sirv "^2.0.3"
     ws "^7.3.1"
 
 well-known-symbols@^2.0.0:

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio