Forráskód Böngészése

Merge branch 'master' into imprv/140677-145630-new-design

Shun Miyazawa 2 éve
szülő
commit
7c57cc106f
100 módosított fájl, 695 hozzáadás és 1202 törlés
  1. 25 0
      .changeset/config.json
  2. 1 0
      .eslintrc.js
  3. 0 13
      .github/workflows/release-rc-scheduled.yml
  4. 115 0
      .github/workflows/release-subpackages.yml
  5. 5 5
      .github/workflows/release.yml
  6. 14 5
      .stylelintrc.json
  7. 56 1
      CHANGELOG.md
  8. 0 1
      apps/app/.eslintrc.js
  9. 3 17
      apps/app/.stylelintrc.json
  10. 0 710
      apps/app/_obsolete/src/styles/theme/apply-colors.scss
  11. 1 1
      apps/app/docker/README.md
  12. 14 11
      apps/app/package.json
  13. 0 1
      apps/app/public/images/icons/editor/bold.svg
  14. 0 1
      apps/app/public/images/icons/editor/check.svg
  15. 0 1
      apps/app/public/images/icons/editor/code.svg
  16. 0 1
      apps/app/public/images/icons/editor/header.svg
  17. 0 1
      apps/app/public/images/icons/editor/italic.svg
  18. 0 1
      apps/app/public/images/icons/editor/list-ol.svg
  19. 0 1
      apps/app/public/images/icons/editor/list-ul.svg
  20. 0 1
      apps/app/public/images/icons/editor/picture.svg
  21. 0 1
      apps/app/public/images/icons/editor/quote.svg
  22. 0 1
      apps/app/public/images/icons/editor/strikethrough.svg
  23. 0 1
      apps/app/public/images/icons/editor/table.svg
  24. 8 0
      apps/app/public/static/locales/en_US/translation.json
  25. 2 0
      apps/app/public/static/locales/fr_FR/translation.json
  26. 8 0
      apps/app/public/static/locales/ja_JP/translation.json
  27. 8 0
      apps/app/public/static/locales/zh_CN/translation.json
  28. 0 147
      apps/app/src/client/models/MarkdownTable.js
  29. 1 2
      apps/app/src/client/services/create-page/index.ts
  30. 0 112
      apps/app/src/client/services/create-page/use-create-page-and-transit.tsx
  31. 138 0
      apps/app/src/client/services/create-page/use-create-page.tsx
  32. 7 6
      apps/app/src/client/services/create-page/use-create-template-page.ts
  33. 9 0
      apps/app/src/client/services/page-operation.ts
  34. 1 1
      apps/app/src/client/services/side-effects/handsontable-modal-launcher-for-view.ts
  35. 3 1
      apps/app/src/components/Admin/App/MaskedInput.module.scss
  36. 2 2
      apps/app/src/components/Admin/Customize/CustomizeThemeOptions.tsx
  37. 1 1
      apps/app/src/components/Admin/Customize/ThemeColorBox.module.scss
  38. 2 1
      apps/app/src/components/Admin/UserManagement.module.scss
  39. 1 1
      apps/app/src/components/AuthorInfo/AuthorInfo.module.scss
  40. 1 2
      apps/app/src/components/Common/CopyDropdown/CopyDropdown.module.scss
  41. 1 3
      apps/app/src/components/Common/DrawerToggler/DrawerToggler.module.scss
  42. 1 1
      apps/app/src/components/Common/PagePathHierarchicalLink/CollapsedParentsDropdown.module.scss
  43. 1 2
      apps/app/src/components/Common/PagePathNav/PagePathNav.module.scss
  44. 3 2
      apps/app/src/components/Common/PageViewLayout.module.scss
  45. 2 2
      apps/app/src/components/CustomNavigation/CustomNav.module.scss
  46. 2 2
      apps/app/src/components/DescendantsPageListModal.module.scss
  47. 69 0
      apps/app/src/components/GrantedGroupsInheritanceSelectModal.tsx
  48. 1 1
      apps/app/src/components/Icons/GrowiLogo.module.scss
  49. 4 0
      apps/app/src/components/ItemsTree/ItemsTree.module.scss
  50. 2 0
      apps/app/src/components/ItemsTree/ItemsTreeContentSkeleton.module.scss
  51. 4 2
      apps/app/src/components/Layout/Admin.module.scss
  52. 28 0
      apps/app/src/components/Layout/BasicLayout.module.scss
  53. 9 1
      apps/app/src/components/Layout/BasicLayout.tsx
  54. 17 13
      apps/app/src/components/Layout/NoLoginLayout.module.scss
  55. 1 1
      apps/app/src/components/Layout/SearchResultLayout.module.scss
  56. 3 4
      apps/app/src/components/LoginForm/LoginForm.module.scss
  57. 0 2
      apps/app/src/components/Me/ColorModeSettings.tsx
  58. 1 1
      apps/app/src/components/Me/UISettings.module.scss
  59. 2 2
      apps/app/src/components/Navbar/GrowiContextualSubNavigation.module.scss
  60. 1 0
      apps/app/src/components/Navbar/GrowiNavbarBottom.module.scss
  61. 3 1
      apps/app/src/components/Navbar/PageEditorModeManager.module.scss
  62. 9 6
      apps/app/src/components/Navbar/PageEditorModeManager.tsx
  63. 1 1
      apps/app/src/components/Page/markdown-table-util-for-view.ts
  64. 2 2
      apps/app/src/components/PageAccessoriesModal/PageAccessoriesModal.module.scss
  65. 2 2
      apps/app/src/components/PageAlert/FixPageGrantAlert.tsx
  66. 1 1
      apps/app/src/components/PageComment.module.scss
  67. 6 7
      apps/app/src/components/PageComment/Comment.module.scss
  68. 2 3
      apps/app/src/components/PageComment/CommentEditor.module.scss
  69. 3 2
      apps/app/src/components/PageComment/CommentEditor.tsx
  70. 1 0
      apps/app/src/components/PageComment/CommentPreview.module.scss
  71. 1 0
      apps/app/src/components/PageComment/DeleteCommentModal.module.scss
  72. 2 1
      apps/app/src/components/PageComment/SwitchingButtonGroup.module.scss
  73. 4 4
      apps/app/src/components/PageComment/_comment-inheritance.scss
  74. 2 1
      apps/app/src/components/PageContentFooter.module.scss
  75. 3 3
      apps/app/src/components/PageControls/BookmarkButtons.module.scss
  76. 2 3
      apps/app/src/components/PageControls/LikeButtons.module.scss
  77. 1 3
      apps/app/src/components/PageControls/PageControls.module.scss
  78. 18 19
      apps/app/src/components/PageControls/PageControls.tsx
  79. 1 3
      apps/app/src/components/PageControls/SearchButton.module.scss
  80. 1 3
      apps/app/src/components/PageControls/SeenUserInfo.module.scss
  81. 1 3
      apps/app/src/components/PageControls/SubscribeButton.module.scss
  82. 1 1
      apps/app/src/components/PageControls/_button-styles.scss
  83. 0 3
      apps/app/src/components/PageCreateModal.module.scss
  84. 12 9
      apps/app/src/components/PageCreateModal.tsx
  85. 3 2
      apps/app/src/components/PageEditor/ConflictDiffModal.tsx
  86. 1 2
      apps/app/src/components/PageEditor/DrawioModal.tsx
  87. 2 1
      apps/app/src/components/PageEditor/EditorNavbar/EditorNavbar.module.scss
  88. 2 2
      apps/app/src/components/PageEditor/EditorNavbarBottom.module.scss
  89. 6 5
      apps/app/src/components/PageEditor/GridEditModal.module.scss
  90. 1 1
      apps/app/src/components/PageEditor/HandsontableModal.module.scss
  91. 2 2
      apps/app/src/components/PageEditor/HandsontableModal.tsx
  92. 2 2
      apps/app/src/components/PageEditor/LinkEditModal.tsx
  93. 2 2
      apps/app/src/components/PageEditor/LinkEditPreview.module.scss
  94. 1 1
      apps/app/src/components/PageEditor/MarkdownTableDataImportForm.tsx
  95. 8 5
      apps/app/src/components/PageEditor/PageEditor.tsx
  96. 2 1
      apps/app/src/components/PageEditor/PageEditorReadOnly.tsx
  97. 1 1
      apps/app/src/components/PageEditor/Preview.module.scss
  98. 2 1
      apps/app/src/components/PageEditor/ScrollSyncHelper.tsx
  99. 2 1
      apps/app/src/components/PageEditor/conflict.tsx
  100. 1 2
      apps/app/src/components/PageEditor/markdown-table-util-for-editor.ts

+ 25 - 0
.changeset/config.json

@@ -0,0 +1,25 @@
+{
+  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
+  "changelog": ["@changesets/changelog-github", { "repo": "weseek/growi" }],
+  "commit": false,
+  "fixed": [],
+  "linked": [],
+  "access": "public",
+  "baseBranch": "master",
+  "updateInternalDependencies": "patch",
+  "snapshot": {
+    "useCalculatedVersion": true,
+    "prereleaseTemplate": "{tag}.{commit}"
+  },
+  "ignore": [
+    "@growi/app",
+    "@growi/slackbot-proxy",
+    "@growi/custom-icons",
+    "@growi/editor",
+    "@growi/presentation",
+    "@growi/preset-*",
+    "@growi/remark-*",
+    "@growi/slack",
+    "@growi/ui"
+  ]
+}

+ 1 - 0
.eslintrc.js

@@ -48,6 +48,7 @@ module.exports = {
         'newlines-between': 'always',
       },
     ],
+    '@typescript-eslint/consistent-type-imports': 'warn',
     '@typescript-eslint/no-explicit-any': 'off',
     '@typescript-eslint/explicit-module-boundary-types': 'off',
     indent: [

+ 0 - 13
.github/workflows/release-rc-scheduled.yml

@@ -65,16 +65,3 @@ jobs:
       tag-temporary: latest-rc
     secrets:
       DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
-
-  publish-image-rc-ghcr:
-    needs: [determine-tags, build-image-rc]
-
-    uses: weseek/growi/.github/workflows/reusable-app-create-manifests.yml@master
-    with:
-      tags: ${{ needs.determine-tags.outputs.TAGS_GHCR }}
-      registry: ghcr.io
-      image-name: weseek/growi
-      tag-temporary: latest-rc
-    secrets:
-      DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_ON_GITHUB_PASSWORD }}
-

+ 115 - 0
.github/workflows/release-subpackages.yml

@@ -0,0 +1,115 @@
+name: Release Subpackages
+
+on:
+  push:
+    branches:
+      - master
+    paths:
+      - .changeset/**
+      - .github/workflows/release-subpackages.yml
+  workflow_run:
+    workflows: ["Node CI for app development"]
+    types:
+      - completed
+    branches:
+      - master
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  release-subpackages-snapshot:
+
+    if: "!startsWith(github.head_ref, 'changeset-release/')"
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - uses: actions/setup-node@v4
+      with:
+        node-version: '20'
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: Cache/Restore node_modules
+      id: cache-dependencies
+      uses: actions/cache@v4
+      with:
+        path: |
+          **/node_modules
+        key: node_modules-release-subpackages-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
+        restore-keys: |
+          node_modules-release-subpackages-${{ runner.OS }}-node${{ inputs.node-version }}-
+
+    - name: Install dependencies
+      run: |
+        yarn global add turbo
+        yarn global add node-gyp
+        yarn --frozen-lockfile
+
+    - name: Setup .npmrc
+      run: |
+        cat << EOF > "$HOME/.npmrc"
+          //registry.npmjs.org/:_authToken=$NPM_TOKEN
+        EOF
+      env:
+        NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+
+    - name: Retrieve changesets information
+      id: changesets-status
+      run: |
+        yarn changeset status --output status.json
+        echo "CHANGESETS_LENGTH=$(jq -r '.changesets | length' status.json)" >> $GITHUB_OUTPUT
+        rm status.json
+
+    - name: Snapshot release to npm
+      if: steps.changesets-status.outputs.CHANGESETS_LENGTH > 0
+      run: |
+        yarn release-subpackages:snapshot
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+
+
+  release-subpackages:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - uses: actions/setup-node@v4
+      with:
+        node-version: '20'
+        cache: 'yarn'
+        cache-dependency-path: '**/yarn.lock'
+
+    - name: Cache/Restore node_modules
+      id: cache-dependencies
+      uses: actions/cache@v4
+      with:
+        path: |
+          **/node_modules
+        key: node_modules-release-subpackages-${{ runner.OS }}-node${{ inputs.node-version }}-${{ hashFiles('**/yarn.lock') }}
+        restore-keys: |
+          node_modules-release-subpackages-${{ runner.OS }}-node${{ inputs.node-version }}-
+
+    - name: Install dependencies
+      run: |
+        yarn global add turbo
+        yarn global add node-gyp
+        yarn --frozen-lockfile
+
+    - name: Create Release Pull Request or Publish to npm
+      id: changesets
+      uses: changesets/action@v1
+      with:
+        title: Release Subpackages
+        version: yarn version-subpackages
+        publish: yarn release-subpackages
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

+ 5 - 5
.github/workflows/release.yml

@@ -103,7 +103,7 @@ jobs:
           type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}.{{minor}}.{{patch}}
 
 
-  build-image:
+  build-app-image:
     needs: create-github-release
 
     uses: weseek/growi/.github/workflows/reusable-app-build-image.yml@master
@@ -115,8 +115,8 @@ jobs:
       AWS_ROLE_TO_ASSUME_FOR_OIDC: ${{ secrets.AWS_ROLE_TO_ASSUME_FOR_OIDC }}
 
 
-  publish-image:
-    needs: [determine-tags, build-image]
+  publish-app-image:
+    needs: [determine-tags, build-app-image]
 
     uses: weseek/growi/.github/workflows/reusable-app-create-manifests.yml@master
     with:
@@ -129,7 +129,7 @@ jobs:
 
 
   post-publish:
-    needs: [create-github-release, publish-image]
+    needs: [create-github-release, publish-app-image]
     runs-on: ubuntu-latest
 
     steps:
@@ -154,7 +154,7 @@ jobs:
 
 
   create-pr-for-next-rc:
-    needs: [create-github-release, publish-image]
+    needs: [create-github-release, publish-app-image]
     runs-on: ubuntu-latest
 
     steps:

+ 14 - 5
.stylelintrc.json

@@ -1,16 +1,25 @@
 {
   "extends": [
+    "stylelint-config-recommended-scss",
     "stylelint-config-recess-order"
   ],
-  "customSyntax": "postcss-scss",
   "rules": {
-    "indentation": 2,
-    "string-quotes": "single",
+    "no-duplicate-selectors": null,
+    "scss/comment-no-empty": null,
+    "scss/at-extend-no-missing-placeholder": null,
     "rule-empty-line-before": [ "always-multi-line", {
       "except": ["after-single-line-comment", "first-nested"],
       "ignore": ["after-comment", "inside-block"]
     } ],
-    "selector-combinator-space-before": "always",
-    "selector-combinator-space-after": "always"
+    "color-function-notation": "legacy",
+    "selector-pseudo-class-no-unknown": [
+      true,
+      {
+        "ignorePseudoClasses": [
+          "global",
+          "local"
+        ]
+      }
+    ]
   }
 }

+ 56 - 1
CHANGELOG.md

@@ -1,9 +1,64 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v7.0.5...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v7.0.9...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v7.0.9](https://github.com/weseek/growi/compare/v7.0.8...v7.0.9) - 2024-05-30
+
+### 🐛 Bug Fixes
+
+* fix: Supress warning of checkbox (#8865) @yuki-takei
+* fix: Editor package import/export (#8864) @yuki-takei
+
+## [v7.0.8](https://github.com/weseek/growi/compare/v7.0.7...v7.0.8) - 2024-05-30
+
+### 💎 Features
+
+* feat: Select unrelated group inheritance on child page create (#8812) @arafubeatbox
+
+### 🚀 Improvement
+
+* imprv: Design coding of search result page (#8828) @miya
+
+### 🐛 Bug Fixes
+
+* fix: Page body sometimes appears doubled up when the editor is opened (#8858) @miya
+* fix: Brackets appearance when Nord editor theme (#8852) @satof3
+* fix: Slack notification not sent on page update (#8841) @miya
+* fix: Table icon is not displayed when hovering over the table (#8830) @WNomunomu
+
+### 🧰 Maintenance
+
+* support: Reorganize editor module exports (#8846) @yuki-takei
+
+## [v7.0.7](https://github.com/weseek/growi/compare/v7.0.6...v7.0.7) - 2024-05-27
+
+### 🚀 Improvement
+
+* imprv: Behavior of dropdown toggle in groundglassbar (#8832) @maeshinshin
+* imprv: toastr location (#8831) @yuki-takei
+
+### 🐛 Bug Fixes
+
+* fix: Do not insert initial value when input is empty in editor (#8773) @miya
+
+### 🧰 Maintenance
+
+* support: Apply changesets (#8840) @yuki-takei
+* support: Upgrade yjs packages (#8839) @yuki-takei
+* support: Upgrade stylelint (#8835) @yuki-takei
+
+## [v7.0.6](https://github.com/weseek/growi/compare/v7.0.5...v7.0.6) - 2024-05-20
+
+### 🐛 Bug Fixes
+
+* fix: S3 configurations are considered invalid wrongly (#8823) @yuki-takei
+
+### 🧰 Maintenance
+
+* support: Publish @growi/core-styles package (#8819) @yuki-takei
+
 ## [v7.0.5](https://github.com/weseek/growi/compare/v7.0.4...v7.0.5) - 2024-05-20
 
 ### 🚀 Improvement

+ 0 - 1
apps/app/.eslintrc.js

@@ -27,7 +27,6 @@ module.exports = {
       },
     ]],
     '@typescript-eslint/no-var-requires': 'off',
-    '@typescript-eslint/consistent-type-imports': 'warn',
 
     // set 'warn' temporarily -- 2021.08.02 Yuki Takei
     '@typescript-eslint/no-use-before-define': ['warn'],

+ 3 - 17
apps/app/.stylelintrc.json

@@ -1,20 +1,6 @@
 {
-  "extends": [
-    "stylelint-config-recess-order"
-  ],
-  "customSyntax": "postcss-scss",
+  "extends": "../../.stylelintrc.json",
   "ignoreFiles": [
-    "src/styles/prebuilt/*.css",
-    "src/linter-checker/test.scss"
-  ],
-  "rules": {
-    "indentation": 2,
-    "string-quotes": "single",
-    "rule-empty-line-before": [ "always-multi-line", {
-      "except": ["after-single-line-comment", "first-nested"],
-      "ignore": ["after-comment", "inside-block"]
-    } ],
-    "selector-combinator-space-before": "always",
-    "selector-combinator-space-after": "always"
-  }
+    "src/styles/prebuilt/*.css"
+  ]
 }

+ 0 - 710
apps/app/_obsolete/src/styles/theme/apply-colors.scss

@@ -1,710 +0,0 @@
-@use '@growi/core/scss/bootstrap/init' as *;
-
-@use '../variables' as var;
-@use '../mixins';
-@use '../atoms/mixins/code';
-@use './mixins/hsl-button';
-@use './hsl-functions' as hsl;
-
-@import 'apply-colors-dark';
-@import 'apply-colors-light';
-
-//
-//== Apply to Bootstrap
-//
-
-// determine optional variables
-$bgcolor-search-top-dropdown: var(--bgcolor-search-top-dropdown,var(--secondary));
-$bgcolor-sidebar-nav-item-active: var(--bgcolor-sidebar-nav-item-active,#{hsl.darken(var(--primary),10%)});
-$text-shadow-sidebar-nav-item-active: var(--text-shadow-sidebar-nav-item-active,1px 1px 2px var(--primary));
-$bgcolor-inline-code: var(--bgcolor-inline-code, #{$gray-100});
-$color-inline-code: var(--color-inline-code, #{darken($red, 15%)});
-$bordercolor-inline-code: var(--bordercolor-inline-code, #{$gray-400});
-$bordercolor-nav-tabs: var(--bordercolor-nav-tabs, #{$gray-300});
-$bordercolor-nav-tabs-hover: var(--bordercolor-nav-tabs-hover,#{$gray-200} #{$gray-200} #{$bordercolor-nav-tabs});
-$border-nav-tabs-link-active: var(--border-nav-tabs-link-active, #{$gray-600});
-$bordercolor-nav-tabs-active: var(--bordercolor-nav-tabs-active,$bordercolor-nav-tabs $bordercolor-nav-tabs var(--bgcolor-global));
-$color-btn-reload-in-sidebar: var(--color-btn-reload-in-sidebar,#{$gray-500});
-$bgcolor-keyword-highlighted: var(--bgcolor-keyword-highlighted,#{var.$grw-marker-yellow});
-$color-page-list-group-item-meta: var(--color-page-list-group-item-meta,#{$gray-500});
-$color-search-page-list-title: var(--color-search-page-list-title,var(--color-global));
-
-// override bootstrap variables
-$body-bg: var(--bgcolor-global);
-$body-color: var(--color-global);
-$link-color: var(--color-link);
-$link-hover-color: var(--color-link-hover);
-$input-focus-color: var(--color-global);
-$nav-tabs-border-color: $bordercolor-nav-tabs;
-$nav-tabs-link-hover-border-color: $bordercolor-nav-tabs-hover;
-$nav-tabs-link-active-color: var(--color-nav-tabs-link-active);
-$nav-tabs-link-active-bg: var(--bgcolor-global);
-$nav-tabs-link-active-border-color: $bordercolor-nav-tabs-active;
-$theme-colors: map-merge($theme-colors, ( primary: $primary ));
-
-// TODO: activate (https://redmine.weseek.co.jp/issues/128307)
-// @import 'reboot-bootstrap-buttons';
-// @import 'reboot-bootstrap-colors';
-// @import 'reboot-bootstrap-theme-colors';
-// @import 'hsl-reboot-bootstrap-theme-colors';
-// @import 'reboot-bootstrap-nav';
-// @import 'reboot-toastr-colors';
-
-// determine variables with bootstrap function (These variables can be used after importing bootstrap above)
-$color-modal-header: var(--color-modal-header,#{hsl.contrast(var(--primary))});
-
-code:not([class^='language-']) {
-  @include code.code-inline-color($color-inline-code, $bgcolor-inline-code, $bordercolor-inline-code);
-}
-
-.code-highlighted {
-  border-color: $bordercolor-inline-code;
-}
-
-//
-//== Apply to Bootstrap Elements
-//
-
-// TODO: activate (https://redmine.weseek.co.jp/issues/128307)
-// theme-color-level() dropped in bootstrap v5
-// Alert link
-// @each $color, $value in $theme-colors {
-//   .alert.alert-#{$color} {
-//     a,
-//     a:hover {
-//       color: theme-color-level($color, $alert-color-level - 2);
-//     }
-//   }
-// }
-
-// Dropdown
-.grw-apperance-mode-dropdown {
-  .grw-sidebar-mode-icon svg {
-    fill: var(--secondary);
-  }
-  .grw-color-mode-icon svg {
-    fill: var(--color-global);
-  }
-  .grw-color-mode-icon-muted svg {
-    fill: var(--secondary);
-  }
-}
-
-// TODO: activate (https://redmine.weseek.co.jp/issues/128307)
-// form-control-focus() dropped in bootstrap v5
-// Form
-// .form-control {
-//   @include form-control-focus();
-// }
-
-// Tabs
-.nav.nav-tabs .nav-link.active {
-  color: var(--color-link);
-  background: transparent;
-
-  &:hover,
-  &:focus {
-    color: var(--color-link-hover);
-  }
-}
-
-// Pagination
-ul.pagination {
-  li.page-item.disabled {
-    button.page-link {
-      color: $gray-400;
-    }
-  }
-  li.page-item.active {
-    button.page-link {
-      color: hsl.contrast(var(--primary));
-      background-color: var(--primary);
-      &:hover,
-      &:focus {
-        color: hsl.contrast(var(--primary));
-        background-color: var(--primary);
-      }
-    }
-  }
-  li.page-item {
-    button.page-link {
-      color: var(--primary);
-      border-color: var(--secondary) !important;
-      &:hover,
-      &:active,
-      &:focus {
-        color: var(--primary);
-      }
-    }
-  }
-}
-
-//
-//== Apply to Handsontable
-//
-.handsontable {
-  color: initial;
-}
-
-//
-//== Apply to GROWI Elements
-//
-
-.grw-logo {
-  // set transition for fill
-  svg, svg * {
-    transition: fill 0.8s ease-out;
-  }
-
-  svg {
-    fill: var(--fillcolor-logo-mark);
-  }
-
-  &:hover {
-    svg {
-      .group1 {
-        fill: var.$growi-green;
-      }
-
-      .group2 {
-        fill: var.$growi-blue;
-      }
-    }
-  }
-}
-
-.grw-navbar {
-  background: var(--bgcolor-navbar);
-  .nav-item .nav-link {
-    color: var(--color-link-nabvar);
-  }
-
-  border-image: var(--border-image-navbar) !important;
-  border-image-slice: 1 !important;
-
-  .grw-app-title {
-    color: var(--fillcolor-logo-mark);
-  }
-}
-
-.grw-global-search {
-  .btn-secondary.dropdown-toggle {
-    @include hsl-button.button-variant(var(--bgcolor-search-top-dropdown), var(--bgcolor-search-top-dropdown));
-  }
-
-  // for https://youtrack.weseek.co.jp/issue/GW-2603
-  .search-typeahead {
-    background-color: hsl.alpha(var(--bgcolor-global),10%);
-  }
-  input.form-control {
-    border: none;
-  }
-}
-
-.grw-sidebar {
-  $color-resize-button: var(--color-resize-button,var(--color-global));
-  $bgcolor-resize-button: var(--bgcolor-resize-button,white);
-  $color-resize-button-hover: var(--color-resize-button-hover,var(--color-reversal));
-  $bgcolor-resize-button-hover: var(--bgcolor-resize-button-hover,#{hsl.lighten(var(--bgcolor-resize-button), 5%)});
-  // .grw-navigation-resize-button {
-  //   .hexagon-container svg {
-  //     .background {
-  //       fill: var(--bgcolor-resize-button);
-  //     }
-  //     .icon {
-  //       fill: var(--color-resize-button);
-  //     }
-  //   }
-  //   &:hover .hexagon-container svg {
-  //     .background {
-  //       fill: var(--bgcolor-resize-button-hover);
-  //     }
-  //     .icon {
-  //       fill: var(--color-resize-button-hover);
-  //     }
-  //   }
-  // }
-  div.grw-contextual-navigation {
-    > div {
-      color: var(--color-sidebar-context);
-      background-color: var(--bgcolor-sidebar-context);
-    }
-  }
-
-  .grw-sidebar-nav {
-    .btn {
-      @include hsl-button.button-variant(
-        var(--bgcolor-sidebar),
-        var(--bgcolor-sidebar),
-      );
-    }
-  }
-  .grw-sidebar-nav-primary-container {
-    .btn.active {
-      i {
-        text-shadow: $text-shadow-sidebar-nav-item-active;
-      }
-      // fukidashi
-      &:after {
-        border-right-color: var(--bgcolor-sidebar-context) !important;
-      }
-    }
-  }
-
-  .grw-sidebar-content-header {
-    .grw-btn-reload {
-      color: $color-btn-reload-in-sidebar;
-    }
-
-    .grw-recent-changes-resize-button {
-      .form-check-label::before {
-        background-color: var(--primary);
-      }
-
-      .form-check-label::after {
-        background-color: var(--bgcolor-global);
-      }
-
-      .form-check-input:not(:checked) + .form-check-label::before {
-        color: var(--bgcolor-global);
-      }
-
-      .form-check-input:checked + .form-check-label::before {
-        color: var(--bgcolor-global);
-        background-color: var(--primary);
-        border-color: var(--primary);
-      }
-      .form-check-input:checked + .form-check-label::after {
-        color: var(--bgcolor-global);
-      }
-    }
-  }
-
-  .grw-pagetree, .grw-foldertree {
-    .list-group-item {
-      .grw-pagetree-title-anchor, .grw-foldertree-title-anchor {
-        color: inherit;
-      }
-    }
-  }
-
-  .grw-pagetree-footer {
-    .h5.grw-private-legacy-pages-anchor {
-      color: inherit;
-    }
-  }
-
-  .grw-recent-changes {
-    .list-group {
-      .list-group-item {
-        background-color: transparent !important;
-
-        .icon-lock {
-          color: var(--color-link);
-        }
-
-        .grw-recent-changes-item-lower {
-          color: $gray-500;
-
-          svg {
-            fill: $gray-500;
-          }
-        }
-      }
-    }
-  }
-
-}
-
-/*
- * Icon
- */
-.editor-container .navbar-editor svg {
-  fill: var(--color-editor-icons);
-}
-
-// page preview button in link form
-.btn-page-preview svg {
-  fill: white;
-}
-
-/*
- * Modal
- */
-.modal {
-  .modal-header {
-    border-bottom-color: var(--border-color-theme);
-    .modal-title {
-      color: $color-modal-header;
-    }
-    .btn-close {
-      color: $color-modal-header;
-      opacity: 0.5;
-
-      &:hover {
-        opacity: 0.9;
-      }
-    }
-  }
-
-  .modal-content {
-    background-color: var(--bgcolor-global);
-  }
-
-  .modal-footer {
-    border-top-color: var(--border-color-theme);
-  }
-}
-
-.grw-page-accessories-modal,.grw-descendants-page-list-modal {
-  .modal-header {
-    .btn-close {
-      color: #{hsl.contrast(var(--bgcolor-global))};
-    }
-  }
-}
-
-.grw-custom-nav-tab {
-  .nav-item {
-    &:hover,
-    &:focus {
-      background-color: hsl.alpha(var(--color-link),10%);
-    }
-    .nav-link {
-      -webkit-appearance: none;
-      color: var(--color-link);
-      svg {
-        fill: var(--color-link);
-      }
-
-      // Disabled state lightens text
-      &.disabled {
-        color: $nav-link-disabled-color;
-        svg {
-          fill: $nav-link-disabled-color;
-        }
-      }
-    }
-  }
-
-  .grw-nav-slide-hr {
-    border-color: var(--color-link) !important;
-  }
-}
-
-/*
- * cards
- */
-.card.custom-card {
-  color: var(--color-global);
-  background-color: var(--bgcolor-card);
-  border-color: var(--light);
-  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-}
-
-/*
- * Form Slider
- */
-.admin-page {
-  span.slider {
-    background-color: $gray-300;
-
-    &:before {
-      background-color: white;
-    }
-  }
-
-  input:checked + .slider {
-    background-color: #007bff;
-  }
-
-  input:focus + .slider {
-    box-shadow: 0 0 1px #007bff;
-  }
-}
-
-/*
- * GROWI wiki
- */
-.wiki {
-  h1,
-  h2,
-  h3,
-  h4,
-  h5,
-  h6,
-  h7 {
-    &.blink {
-      @include mixins.blink-bgcolor(var(--bgcolor-blinked-section));
-    }
-  }
-
-  .highlighted-keyword {
-    background: linear-gradient(transparent 60%, $bgcolor-keyword-highlighted 60%);
-  }
-
-  a {
-    color: var(--color-link-wiki);
-
-    &:hover {
-      color: var(--color-link-wiki-hover);
-    }
-  }
-
-  // table with handsontable modal button
-  .editable-with-handsontable {
-    button {
-      color: var(--color-link-wiki);
-    }
-
-    button:hover {
-      color: var(--color-link-wiki-hover);
-    }
-  }
-}
-
-/*
- * GROWI page-list
- */
-.page-list {
-  // List group
-  .list-group {
-    .list-group-item {
-      background-color: var(--bgcolor-global) !important;
-      a {
-        svg {
-          fill: var(--color-global);
-        }
-
-        &:hover {
-          svg {
-            fill: var(--color-global);
-          }
-        }
-      }
-
-      .page-list-meta {
-        color: $color-page-list-group-item-meta;
-        svg {
-          fill: $color-page-list-group-item-meta;
-        }
-      }
-
-      &.list-group-item-action {
-        background-color: var(--bgcolor-list);
-        &.active {
-          border-left-color: var(--primary);
-        }
-      }
-    }
-  }
-}
-
-/*
- * GROWI Editor
- */
-.layout-root.editing {
-  background-color: hsl.darken(var(--bgcolor-global),2%);
-
-  &.builtin-editor {
-    .page-editor-editor-container {
-      border-right-color: var(--border-color-theme);
-    }
-  }
-
-  .navbar-editor {
-    background-color: var(--bgcolor-global); // same color with active tab
-    border-bottom-color: var(--border-color-theme);
-  }
-
-  .page-editor-preview-container {
-    background-color: var(--bgcolor-global);
-  }
-}
-
-
-/*
- * Preview for editing /Sidebar
- */
-.page-editor-preview-body.preview-sidebar {
-  color: var(--color-sidebar-context);
-  background-color: var(--bgcolor-sidebar-context);
-}
-
-/*
- * GROWI Grid Edit Modal
- */
-.grw-grid-edit-preview {
-  .desktop-preview,
-  .tablet-preview,
-  .mobile-preview {
-    background: var(--bgcolor-global);
-  }
-  .grid-edit-border-for-each-cols {
-    border: 2px solid var(--bgcolor-global);
-  }
-}
-
-.grid-preview-col-0 {
-  background: var.$growi-blue;
-}
-
-.grid-preview-col-1 {
-  background: var(--info);
-}
-
-.grid-preview-col-2 {
-  background: var(--success);
-}
-
-.grid-preview-col-3 {
-  background: var.$growi-green;
-}
-
-/*
- * GROWI comment form
- */
-.page-comments-row {
-  background: var(--bgcolor-subnav);
-  .page-comment .page-comment-main,
-  .page-comment-form .comment-form-main {
-    background-color: var(--bgcolor-global);
-
-    .nav.nav-tabs {
-      > li > a.active {
-        background: transparent;
-        border-bottom: solid 1px hsl.darken(var(--bgcolor-global),4%);
-        border-bottom-color: hsl.darken(var(--bgcolor-global),4%);
-      }
-    }
-  }
-}
-
-/*
- * GROWI search result
- */
-.search-result-base {
-  .grw-search-page-nav {
-    background-color: var(--bgcolor-subnav);
-  }
-  .search-control {
-    background-color: var(--bgcolor-global);
-  }
-  .page-list {
-    .highlighted-keyword {
-      background: linear-gradient(transparent 60%, $bgcolor-keyword-highlighted 60%);
-    }
-  }
-}
-
-/*
- * react bootstrap typeahead
- */
-mark.rbt-highlight-text {
-  // Temporarily the highlight color is black
-  color: black;
-}
-
-/*
- * GROWI page content footer
- */
-.page-content-footer {
-  background-color: hsl.darken(var(--bgcolor-global),2%);
-  border-top-color: var(--border-color-theme);
-}
-
-/*
- * GROWI admin page #layoutOptions #themeOptions
- */
-.admin-page {
-  #layoutOptions {
-    .customize-layout-card {
-      &.border-active {
-        border-color: var(--color-theme-color-box);
-      }
-    }
-  }
-
-  #themeOptions {
-    .theme-option-container.active {
-      .theme-option-name {
-        color: var(--color-global);
-      }
-      a {
-        background-color: var(--color-theme-color-box);
-        border-color: var(--color-theme-color-box);
-      }
-    }
-  }
-}
-
-/*
- * HackMd
- */
-.bg-box {
-  background-color: var(--bgcolor-global);
-}
-
-/*
-  Slack Integration
-*/
-.selecting-bot-type {
-  .bot-type-disc {
-    width: 20px;
-  }
-}
-
-/*
-  In App Notification
-*/
-.grw-unopend-notification {
-  width: 7px;
-  height: 7px;
-  background-color: var(--primary);
-}
-
-/*
-Emoji picker modal
-*/
-.emoji-picker-modal {
-  background-color: transparent !important;
-}
-
-/*
-Expand / compress button bookmark list on users page
-*/
-.grw-user-page-list-m {
-  .grw-expand-compress-btn {
-    color: $body-color;
-    background-color: $body-bg;
-    &.active {
-      background-color: hsl.darken($body-bg, 12%),
-    }
-  }
-}
-
-/*
- * Questionnaire modal
- */
-.grw-questionnaire-btn-group {
-  .btn-outline-primary {
-    @include hsl-button.button-outline-variant(
-      #{hsl.lighten(var(--primary), 30%)} !important,
-      #{hsl.contrast(var(--primary))} !important,
-      var(--primary) !important,
-      #{hsl.lighten(var(--primary), 30%)} !important,
-    );
-    &:not(:disabled):not(.disabled):active,
-    &:not(:disabled):not(.disabled).active {
-      color: #{hsl.contrast(var(--primary))} !important;
-      background-color: var(--primary) !important;
-    }
-  }
-}
-
-/*
- * revision-history-diff
- */
-.revision-history-diff {
-  background-color: white;
-}

+ 1 - 1
apps/app/docker/README.md

@@ -10,7 +10,7 @@ GROWI Official docker image
 Supported tags and respective Dockerfile links
 ------------------------------------------------
 
-* [`7.0.5`, `7.0`, `7`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v7.0.5/apps/app/docker/Dockerfile)
+* [`7.0.9`, `7.0`, `7`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v7.0.9/apps/app/docker/Dockerfile)
 * [`6.3.2`, `6.3`, `6` (Dockerfile)](https://github.com/weseek/growi/blob/v6.3.2/apps/app/docker/Dockerfile)
 * [`6.2.4`, `6.2` (Dockerfile)](https://github.com/weseek/growi/blob/v6.2.4/apps/app/docker/Dockerfile)
 * [`6.1.15`, `6.1` (Dockerfile)](https://github.com/weseek/growi/blob/v6.1.15/apps/app/docker/Dockerfile)

+ 14 - 11
apps/app/package.json

@@ -1,7 +1,8 @@
 {
   "name": "@growi/app",
-  "version": "7.0.6-RC.0",
+  "version": "7.0.10-RC.0",
   "license": "MIT",
+  "private": "true",
   "scripts": {
     "//// for production": "",
     "build": "run-p build:*",
@@ -29,7 +30,7 @@
     "dev:ci": "yarn cross-env NODE_ENV=development yarn ts-node src/server/app.ts --ci",
     "lint:typecheck": "npx -y tsc",
     "lint:eslint": "yarn eslint --quiet \"**/*.{js,jsx,ts,tsx}\"",
-    "lint:styles": "stylelint src/**/*.scss",
+    "lint:styles": "stylelint \"src/**/*.scss\"",
     "lint:swagger2openapi": "node node_modules/.bin/oas-validate tmp/swagger.json",
     "lint": "run-p lint:*",
     "prelint:swagger2openapi": "yarn openapi:v3",
@@ -71,7 +72,6 @@
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
     "@growi/core": "link:../../packages/core",
-    "@growi/custom-icons": "link:../../packages/custom-icons",
     "@growi/pluginkit": "link:../../packages/pluginkit",
     "@growi/preset-templates": "link:../../packages/preset-templates",
     "@growi/preset-themes": "link:../../packages/preset-themes",
@@ -179,7 +179,7 @@
     "react-syntax-highlighter": "^15.5.0",
     "react-toastify": "^9.1.3",
     "react-use-ripple": "^1.5.2",
-    "reactstrap": "^9.2.0",
+    "reactstrap": "^9.2.2",
     "reconnecting-websocket": "^4.4.0",
     "redis": "^3.0.2",
     "rehype-katex": "^6.0.2",
@@ -195,7 +195,7 @@
     "remark-toc": "^8.0.1",
     "remark-wiki-link": "^1.0.4",
     "sanitize-filename": "^1.6.3",
-    "socket.io": "^4.7.2",
+    "socket.io": "^4.7.5",
     "stream-to-promise": "^3.0.0",
     "string-width": "=4.2.2",
     "superjson": "^1.9.1",
@@ -211,20 +211,24 @@
     "validator": "^13.7.0",
     "ws": "^8.3.0",
     "xss": "^1.0.14",
-    "y-mongodb-provider": "^0.1.7",
-    "y-socket.io": "^1.1.0",
-    "yjs": "^13.6.12"
+    "y-mongodb-provider": "^0.1.10",
+    "y-socket.io": "^1.1.3",
+    "yjs": "^13.6.15"
   },
   "// comments for defDependencies": {
+    "bootstrap": "v5.3.3 has a bug. refs: https://github.com/twbs/bootstrap/issues/39798",
     "@handsontable/react": "v3 requires handsontable >= 7.0.0.",
     "handsontable": "v7.0.0 or above is no loger MIT lisence."
   },
   "devDependencies": {
+    "@growi/core-styles": "link:../../packages/core-styles",
+    "@growi/custom-icons": "link:../../packages/custom-icons",
     "@growi/editor": "link:../../packages/editor",
     "@growi/presentation": "link:../../packages/presentation",
     "@growi/ui": "link:../../packages/ui",
     "@handsontable/react": "=2.1.0",
     "@next/bundle-analyzer": "^14.1.3",
+    "@popperjs/core": "^2.11.8",
     "@swc-node/jest": "^1.6.2",
     "@swc/jest": "^0.2.24",
     "@testing-library/react": "^14.1.2",
@@ -239,9 +243,8 @@
     "@types/url-join": "^4.0.2",
     "@vitejs/plugin-react": "^4.2.1",
     "@vitest/coverage-v8": "^0.34.6",
-    "autoprefixer": "^9.0.0",
     "babel-loader": "^8.2.5",
-    "bootstrap": "^5.3.1",
+    "bootstrap": "=5.3.2",
     "connect-browser-sync": "^2.1.0",
     "cypress-real-events": "^1.12.0",
     "diff2html": "^3.4.47",
@@ -278,7 +281,7 @@
     "sass": "^1.53.0",
     "simple-load-script": "^1.0.2",
     "simplebar-react": "^2.3.6",
-    "socket.io-client": "^4.2.0",
+    "socket.io-client": "^4.7.5",
     "source-map-loader": "^4.0.1",
     "swagger2openapi": "^7.0.8",
     "tsc-alias": "^1.2.9"

+ 0 - 1
apps/app/public/images/icons/editor/bold.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="109" height="140" viewBox="0 0 10.9 14"><path d="M0 0h5.6c3 0 4.7 1.1 4.7 3.4a3.1 3.1 0 0 1-2.5 3.1 3.7 3.7 0 0 1 3.1 3.5c0 2.9-1.4 4-4.2 4H0zm5.2 6.5c2.7 0 2.6-1.4 2.6-3.1S7.9.7 5.6.7H2.3v5.8zm-2.9 6.6h3.4c2.1 0 2.7-1.1 2.7-3.1s0-2.8-3.2-2.8H2.3z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/check.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="144" height="160" viewBox="0 0 14.4 16"><path d="M13.9 5.5a.5.5 0 0 1 .5.5v9a1.1 1.1 0 0 1-1.1 1H1a1.1 1.1 0 0 1-1-1V2.6a1.1 1.1 0 0 1 1-1h7.1a.5.5 0 0 1 .5.5.5.5 0 0 1-.5.5H1V15h12.3V6a.6.6 0 0 1 .6-.5zM3.6 8.3a.5.5 0 0 0 0 .7l2.5 2.5a.8.8 0 0 0 1.1 0h.1l7-10.7c.1-.2.1-.6-.2-.7a.5.5 0 0 0-.7.1L6.6 10.6 4.3 8.3a.5.5 0 0 0-.7 0z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/code.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="181" height="140" viewBox="0 0 18.1 14"><path d="M17.8 7.9l-4 3.8a.5.5 0 0 1-.8 0 .5.5 0 0 1 0-.8L16.8 7 13 3.2a.6.6 0 0 1 0-.9.5.5 0 0 1 .8 0l4 3.8a1.3 1.3 0 0 1 0 1.8zM5.2 2.3a.7.7 0 0 1 0 .9L1.3 7l3.9 3.9a.6.6 0 0 1 0 .8.6.6 0 0 1-.9 0L.4 7.9a1.3 1.3 0 0 1 0-1.8l3.9-3.8a.6.6 0 0 1 .9 0zM11.5.8L7.8 13.6a.6.6 0 0 1-.7.4.6.6 0 0 1-.5-.8L10.3.4a.7.7 0 0 1 .8-.4.6.6 0 0 1 .4.8z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/header.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="137" height="140" viewBox="0 0 13.7 14"><path d="M10.2 0h2.9a.6.6 0 0 1 .6.6.6.6 0 0 1-.6.6h-.8v11.6h.8a.6.6 0 0 1 .6.6.6.6 0 0 1-.6.6h-2.9a.6.6 0 0 1-.6-.6.6.6 0 0 1 .6-.6h.8V7.2H2.7v5.6h.8a.6.6 0 0 1 .6.6.6.6 0 0 1-.6.6H.6a.6.6 0 0 1-.6-.6.6.6 0 0 1 .6-.6h.7V1.2H.6A.6.6 0 0 1 0 .6.6.6 0 0 1 .6 0h2.9a.6.6 0 0 1 .6.6.6.6 0 0 1-.6.6h-.8v4.9H11V1.2h-.8a.6.6 0 0 1-.6-.6.6.6 0 0 1 .6-.6z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/italic.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="86" height="139" viewBox="0 0 8.6 13.9"><path d="M8.1 0a.6.6 0 0 1 .5.6c0 .3-.2.6-.7.6H6.2L3.8 12.8h1.8c.2 0 .4.3.4.5a.7.7 0 0 1-.7.6H.5c-.3 0-.5-.4-.5-.6s.4-.6.7-.6h1.7L4.9 1.2H3.1a.5.5 0 0 1-.5-.5c0-.3.1-.7.8-.7z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/list-ol.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="237" height="160" viewBox="0 0 23.7 16"><path d="M23.7 2a.8.8 0 0 1-.8.8H6.6a.8.8 0 0 1-.7-.8.7.7 0 0 1 .7-.7h16.3a.7.7 0 0 1 .8.7zM6.6 8.7h16.3a.7.7 0 0 0 .8-.7.8.8 0 0 0-.8-.8H6.6a.8.8 0 0 0-.7.8.7.7 0 0 0 .7.7zm0 5.9h16.3a.7.7 0 0 0 .8-.7.7.7 0 0 0-.8-.7H6.6a.7.7 0 0 0-.7.7.7.7 0 0 0 .7.7zM1.5.5V4h.6V0h-.5L.7.5v.4l.8-.4zM.9 9.6l.3-.3c.9-.9 1.4-1.5 1.4-2.2a1.2 1.2 0 0 0-1.3-1.2h-.1a1.4 1.4 0 0 0-1.2.6l.3.4a1.2 1.2 0 0 1 .9-.5.6.6 0 0 1 .8.6v.2c0 .6-.4 1.1-1.5 2.1l-.4.4v.3h2.6v-.4zm.9 4.1a1 1 0 0 0 .7-.9 1 1 0 0 0-1.1-1 2 2 0 0 0-1.1.3v.4l.8-.2c.5 0 .8.2.8.6s-.5.7-.9.7H.7v.4H1c.6 0 1.1.2 1.1.8a.8.8 0 0 1-.9.8l-.9-.3-.2.4a2 2 0 0 0 1.1.3c1 0 1.5-.6 1.5-1.2a1.2 1.2 0 0 0-.9-1.1z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/list-ul.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="216" height="135" viewBox="0 0 21.6 13.5"><path d="M6.4 1.5h14.5a.7.7 0 0 0 .7-.7.7.7 0 0 0-.7-.7H6.4a.8.8 0 0 0-.8.7.8.8 0 0 0 .8.7zm0 6h14.5a.7.7 0 0 0 .7-.7.7.7 0 0 0-.7-.7H6.4a.8.8 0 0 0-.8.7.8.8 0 0 0 .8.7zm0 6h14.5a.7.7 0 0 0 .7-.7.7.7 0 0 0-.7-.7H6.4a.8.8 0 0 0-.8.7.8.8 0 0 0 .8.7zM.9 1.5h1a.8.8 0 0 0 .9-.7.8.8 0 0 0-.9-.8h-1a.8.8 0 0 0-.9.7.8.8 0 0 0 .9.8zm0 6h1a.8.8 0 0 0 .9-.7.8.8 0 0 0-.9-.8h-1a.8.8 0 0 0-.9.7.8.8 0 0 0 .9.8zm0 6h1a.8.8 0 0 0 .9-.7.8.8 0 0 0-.9-.7h-1a.8.8 0 0 0-.9.7.8.8 0 0 0 .9.7z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/picture.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="190" height="160" viewBox="0 0 19 16"><path d="M17.8 0H1.2A1.2 1.2 0 0 0 0 1.2v13.6A1.2 1.2 0 0 0 1.2 16h16.6a1.2 1.2 0 0 0 1.2-1.2V1.2a1.4 1.4 0 0 0-.2-.6.8.8 0 0 0-.4-.4zm0 14.8H1.2v-3.5l4.7-4.6 5 4.9.3.2.5-.2 2.1-1.9 3.9 4h.1v1.1zm0-2.8l-3.5-3.5-.4-.2h-.4l-2.2 2-4.9-4.8-.4-.2c-.2 0-.4 0-.5.2L1.2 9.7V1.2h16.6V12zm-4.2-6.1h.6a1.1 1.1 0 0 0 .6-1.1 1.2 1.2 0 0 0-1.2-1.1 1.3 1.3 0 0 0-1.2 1.2 1.2 1.2 0 0 0 .4.8 1.1 1.1 0 0 0 .8.3z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/quote.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="170" height="120" viewBox="0 0 17 12"><path d="M5 0H2a2 2 0 0 0-2 2v3a2 2 0 0 0 2 2h3a1.7 1.7 0 0 0 1-.3V10a.9.9 0 0 1-1 1H3v1h2a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm0 6H2a.9.9 0 0 1-1-1V2a.9.9 0 0 1 1-1h3a.9.9 0 0 1 1 1v3a.9.9 0 0 1-1 1zm10-6h-3a2 2 0 0 0-2 2v3a2 2 0 0 0 2 2h3a1.7 1.7 0 0 0 1-.3V10a.9.9 0 0 1-1 1h-2v1h2a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm0 6h-3a.9.9 0 0 1-1-1V2a.9.9 0 0 1 1-1h3a.9.9 0 0 1 1 1v3a.9.9 0 0 1-1 1z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/strikethrough.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="195" height="140" viewBox="0 0 19.5 14"><path d="M5.8 6.2H9C7.2 5.7 6.3 5 6.3 3.8a2.2 2.2 0 0 1 .9-1.9 4.3 4.3 0 0 1 2.5-.7 4.3 4.3 0 0 1 2.5.7 3.1 3.1 0 0 1 1.1 1.6.7.7 0 0 0 .6.4h.3a.7.7 0 0 0 .4-.8A3.6 3.6 0 0 0 13.1 1a6.7 6.7 0 0 0-6-.5 3.1 3.1 0 0 0-1.7 1.3 3.6 3.6 0 0 0-.6 2 2.9 2.9 0 0 0 1 2.3zm7 2.5a2 2 0 0 1 .6 1.4 2.4 2.4 0 0 1-1 1.9 3.7 3.7 0 0 1-2.5.7 4.6 4.6 0 0 1-3-.8 3.7 3.7 0 0 1-1.2-2 .6.6 0 0 0-.6-.5h-.2a.7.7 0 0 0-.5.8 4.1 4.1 0 0 0 1.5 2.5A6 6 0 0 0 9.8 14a7.5 7.5 0 0 0 2.6-.5 4.9 4.9 0 0 0 1.8-1.4 4.3 4.3 0 0 0 .6-2.2 5 5 0 0 0-.2-1.2zM.4 7.9a.7.7 0 0 1-.4-.5.4.4 0 0 1 .4-.4h18.8a.4.4 0 0 1 .3.6c0 .1-.1.2-.2.3z"/></svg>

+ 0 - 1
apps/app/public/images/icons/editor/table.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="203" height="160" viewBox="0 0 20.3 16"><path d="M19.1 16H1.2A1.2 1.2 0 0 1 0 14.8V1.2A1.2 1.2 0 0 1 1.2 0h17.9a1.2 1.2 0 0 1 1.2 1.2v13.6a1.2 1.2 0 0 1-1.2 1.2zm-5.2-4.3v3.2h5.3v-3.2zm-6.4 0v3.2h5.3v-3.2zm-6.4 0v3.2h5.3v-3.2zm12.8-4.2v3.2h5.3V7.5zm-6.4 0v3.2h5.3V7.5zm-6.4 0v3.2h5.3V7.5zm12.8-4.3v3.2h5.3V3.2zm-6.4 0v3.2h5.3V3.2zm-6.4 0v3.2h5.3V3.2z"/></svg>

+ 8 - 0
apps/app/public/static/locales/en_US/translation.json

@@ -425,6 +425,12 @@
     }
   },
   "duplicated_pages": "{{fromPath}} has been duplicated",
+  "modal_granted_groups_inheritance_select": {
+    "select_granted_groups": "Select groups that can access page",
+    "inherit_all_granted_groups_from_parent": "Inherit all groups that can access page from parent",
+    "only_inherit_related_groups": "Only inherit groups that you belong to from parent",
+    "create_page": "Create Page"
+  },
   "modal_putback": {
     "label": {
       "Put Back Page": "Put back page",
@@ -561,6 +567,8 @@
     "delete_completely": "Delete completely",
     "include_certain_path": "Include {{pathToInclude}} path ",
     "delete_all_selected_page": "Delete All",
+    "select_all": "Select all",
+    "delete_selected_pages": "Delete selected pages",
     "currently_not_implemented": "This is not currently implemented",
     "search_again": "Search again",
     "number_of_list_to_display": "Display",

+ 2 - 0
apps/app/public/static/locales/fr_FR/translation.json

@@ -561,6 +561,8 @@
     "delete_completely": "Supprimer définitivement",
     "include_certain_path": "Inclure le chemin {{pathToInclude}} ",
     "delete_all_selected_page": "Tout supprimer",
+    "select_all": "Tout sélectionner",
+    "delete_selected_pages": "Supprimer les pages sélectionnées",
     "currently_not_implemented": "Non implémenté",
     "search_again": "Rechercher",
     "number_of_list_to_display": "Afficher",

+ 8 - 0
apps/app/public/static/locales/ja_JP/translation.json

@@ -458,6 +458,12 @@
     }
   },
   "duplicated_pages": "{{fromPath}} を複製しました",
+  "modal_granted_groups_inheritance_select": {
+    "select_granted_groups": "閲覧権限のあるグループを選択",
+    "inherit_all_granted_groups_from_parent": "閲覧権限のあるグループを親ページから全て引き継ぐ",
+    "only_inherit_related_groups": "自分が所属するグループのみを親ページから引き継ぐ",
+    "create_page": "ページ作成"
+  },
   "modal_putback": {
     "label": {
       "Put Back Page": "ページを元に戻す",
@@ -594,6 +600,8 @@
     "delete_completely": "完全に削除する",
     "include_certain_path": "{{pathToInclude}}下を含む ",
     "delete_all_selected_page": "一括削除",
+    "select_all": "全件選択",
+    "delete_selected_pages": "選択したページを削除",
     "currently_not_implemented": "現在未実装の機能です",
     "search_again": "再検索",
     "number_of_list_to_display": "表示件数",

+ 8 - 0
apps/app/public/static/locales/zh_CN/translation.json

@@ -415,6 +415,12 @@
     }
   },
   "duplicated_pages": "{{fromPath}} 已重复",
+  "modal_granted_groups_inheritance_select": {
+    "select_granted_groups": "Select groups that can access page",
+    "inherit_all_granted_groups_from_parent": "Inherit all groups that can access page from parent",
+    "only_inherit_related_groups": "Only inherit groups that you belong to from parent",
+    "create_page": "Create Page"
+  },
   "modal_putback": {
     "label": {
       "Put Back Page": "Put back page",
@@ -564,6 +570,8 @@
     "delete_completely": "完全删除",
     "include_certain_path": "包含 {{pathToInclude}} 路径 ",
     "delete_all_selected_page": "删除所有",
+    "select_all": "选择所有",
+    "delete_selected_pages": "删除选定页面",
     "currently_not_implemented": "这是当前未实现的功能",
     "search_again": "再次搜索",
     "number_of_list_to_display": "显示器的数量",

+ 0 - 147
apps/app/src/client/models/MarkdownTable.js

@@ -1,147 +0,0 @@
-import csvToMarkdown from 'csv-to-markdown-table';
-import { markdownTable } from 'markdown-table';
-import stringWidth from 'string-width';
-
-// https://github.com/markdown-it/markdown-it/blob/d29f421927e93e88daf75f22089a3e732e195bd2/lib/rules_block/table.js#L83
-// https://regex101.com/r/7BN2fR/7
-const tableAlignmentLineRE = /^[-:|][-:|\s]*$/;
-const tableAlignmentLineNegRE = /^[^-:]*$/; // it is need to check to ignore empty row which is matched above RE
-const linePartOfTableRE = /^\|[^\r\n]*|[^\r\n]*\|$|([^|\r\n]+\|[^|\r\n]*)+/; // own idea
-
-const defaultOptions = { stringLength: stringWidth };
-
-/**
- * markdown table class for markdown-table module
- *   ref. https://github.com/wooorm/markdown-table
- */
-export default class MarkdownTable {
-
-  constructor(table, options) {
-    this.table = table || [];
-    this.options = Object.assign(options || {}, defaultOptions);
-
-    this.toString = this.toString.bind(this);
-  }
-
-  toString() {
-    return markdownTable(this.table, this.options);
-  }
-
-  /**
-   * returns cloned Markdowntable instance
-   * (This method clones only the table field.)
-   */
-  clone() {
-    const newTable = [];
-    for (let i = 0; i < this.table.length; i++) {
-      newTable.push([].concat(this.table[i]));
-    }
-    return new MarkdownTable(newTable, this.options);
-  }
-
-  /**
-   * normalize all cell data(trim & convert the newline character to space or pad '' if cell data is null)
-   */
-  normalizeCells() {
-    for (let i = 0; i < this.table.length; i++) {
-      for (let j = 0; j < this.table[i].length; j++) {
-        if (this.table[i][j] != null) {
-          this.table[i][j] = this.table[i][j].trim().replace(/\r?\n/g, ' ');
-        }
-        else {
-          this.table[i][j] = '';
-        }
-      }
-    }
-
-    return this;
-  }
-
-  /**
-   * return a MarkdownTable instance made from a string of HTML table tag
-   *
-   * If a parser error occurs, an error object with an error message is thrown.
-   * The error message is a innerHTML, so must not assign it into element.innerHTML because it can lead to Mutation-based XSS
-   */
-  static fromHTMLTableTag(str) {
-    // set up DOMParser
-    const domParser = new (window.DOMParser)();
-
-    // use DOMParser to prevent DOM based XSS (https://developer.mozilla.org/en-US/docs/Web/API/DOMParser)
-    const dom = domParser.parseFromString(str, 'application/xml');
-
-    if (dom.querySelector('parsererror')) {
-      throw new Error(dom.documentElement.innerHTML);
-    }
-
-    const tableElement = dom.querySelector('table');
-    const trElements = tableElement.querySelectorAll('tr');
-
-    const table = [];
-    let maxRowSize = 0;
-    for (let i = 0; i < trElements.length; i++) {
-      const row = [];
-      const cellElements = trElements[i].querySelectorAll('th,td');
-      for (let j = 0; j < cellElements.length; j++) {
-        row.push(cellElements[j].innerHTML);
-      }
-      table.push(row);
-
-      if (maxRowSize < row.length) maxRowSize = row.length;
-    }
-
-    const align = [];
-    for (let i = 0; i < maxRowSize; i++) {
-      align.push('');
-    }
-
-    return new MarkdownTable(table, { align });
-  }
-
-  /**
-   * return a MarkdownTable instance made from a string of delimiter-separated values
-   */
-  static fromDSV(str, delimiter) {
-    return MarkdownTable.fromMarkdownString(csvToMarkdown(str, delimiter, true));
-  }
-
-  /**
-   * return a MarkdownTable instance
-   *   ref. https://github.com/wooorm/markdown-table
-   * @param {string} str markdown string
-   */
-  static fromMarkdownString(str) {
-    const arrMDTableLines = str.split(/(\r\n|\r|\n)/);
-    const contents = [];
-    let aligns = [];
-    for (let n = 0; n < arrMDTableLines.length; n++) {
-      const line = arrMDTableLines[n];
-
-      if (tableAlignmentLineRE.test(line) && !tableAlignmentLineNegRE.test(line)) {
-        // parse line which described alignment
-        const alignRuleRE = [
-          { align: 'c', regex: /^:-+:$/ },
-          { align: 'l', regex: /^:-+$/ },
-          { align: 'r', regex: /^-+:$/ },
-        ];
-        let lineText = '';
-        lineText = line.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
-        lineText = lineText.replace(/\s*/g, '');
-        aligns = lineText.split(/\|/).map((col) => {
-          const rule = alignRuleRE.find((rule) => { return col.match(rule.regex) });
-          return (rule != null) ? rule.align : '';
-        });
-      }
-      else if (linePartOfTableRE.test(line)) {
-        // parse line whether header or body
-        let lineText = '';
-        lineText = line.replace(/\s*\|\s*/g, '|');
-        lineText = lineText.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
-        const row = lineText.split(/\|/);
-        contents.push(row);
-      }
-    }
-    return (new MarkdownTable(contents, { align: aligns }));
-  }
-
-}

+ 1 - 2
apps/app/src/client/services/create-page/index.ts

@@ -1,3 +1,2 @@
-export * from './create-page';
-export * from './use-create-page-and-transit';
+export * from './use-create-page';
 export * from './use-create-template-page';

+ 0 - 112
apps/app/src/client/services/create-page/use-create-page-and-transit.tsx

@@ -1,112 +0,0 @@
-import { useCallback, useState } from 'react';
-
-import { useRouter } from 'next/router';
-
-import { exist } from '~/client/services/page-operation';
-import type { IApiv3PageCreateParams } from '~/interfaces/apiv3';
-import { useCurrentPagePath } from '~/stores/page';
-import { EditorMode, useEditorMode } from '~/stores/ui';
-import loggerFactory from '~/utils/logger';
-
-import { createPage } from './create-page';
-
-const logger = loggerFactory('growi:Navbar:GrowiContextualSubNavigation');
-
-/**
- * Invoked when creation and transition has finished
- */
-type OnCreated = () => void;
-/**
- * Invoked when either creation or transition has aborted
- */
-type OnAborted = () => void;
-/**
- * Always invoked after processing is terminated
- */
-type OnTerminated = () => void;
-
-type CreatePageAndTransitOpts = {
-  shouldCheckPageExists?: boolean,
-  onCreationStart?: OnCreated,
-  onCreated?: OnCreated,
-  onAborted?: OnAborted,
-  onTerminated?: OnTerminated,
-}
-
-type CreatePageAndTransit = (
-  params: IApiv3PageCreateParams,
-  opts?: CreatePageAndTransitOpts,
-) => Promise<void>;
-
-type UseCreatePageAndTransit = () => {
-  isCreating: boolean,
-  createAndTransit: CreatePageAndTransit,
-};
-
-export const useCreatePageAndTransit: UseCreatePageAndTransit = () => {
-
-  const router = useRouter();
-
-  const { data: currentPagePath } = useCurrentPagePath();
-  const { mutate: mutateEditorMode } = useEditorMode();
-
-  const [isCreating, setCreating] = useState(false);
-
-  const createAndTransit: CreatePageAndTransit = useCallback(async(params, opts = {}) => {
-    const {
-      shouldCheckPageExists,
-      onCreationStart, onCreated, onAborted, onTerminated,
-    } = opts;
-
-    // check the page existence
-    if (shouldCheckPageExists && params.path != null) {
-      const pagePath = params.path;
-
-      try {
-        const { isExist } = await exist(pagePath);
-
-        if (isExist) {
-          // routing
-          if (pagePath !== currentPagePath) {
-            await router.push(`${pagePath}#edit`);
-          }
-          mutateEditorMode(EditorMode.Editor);
-          onAborted?.();
-          return;
-        }
-      }
-      catch (err) {
-        throw err;
-      }
-      finally {
-        onTerminated?.();
-      }
-    }
-
-    // create and transit
-    try {
-      setCreating(true);
-      onCreationStart?.();
-
-      const response = await createPage(params);
-
-      await router.push(`/${response.page._id}#edit`);
-      mutateEditorMode(EditorMode.Editor);
-
-      onCreated?.();
-    }
-    catch (err) {
-      throw err;
-    }
-    finally {
-      onTerminated?.();
-      setCreating(false);
-    }
-
-  }, [currentPagePath, mutateEditorMode, router]);
-
-  return {
-    isCreating,
-    createAndTransit,
-  };
-};

+ 138 - 0
apps/app/src/client/services/create-page/use-create-page.tsx

@@ -0,0 +1,138 @@
+import { useCallback, useState } from 'react';
+
+import { useRouter } from 'next/router';
+import { useTranslation } from 'react-i18next';
+
+import { exist, getIsNonUserRelatedGroupsGranted } from '~/client/services/page-operation';
+import { toastWarning } from '~/client/util/toastr';
+import type { IApiv3PageCreateParams } from '~/interfaces/apiv3';
+import { useGrantedGroupsInheritanceSelectModal } from '~/stores/modal';
+import { useCurrentPagePath } from '~/stores/page';
+import { EditorMode, useEditorMode } from '~/stores/ui';
+
+import { createPage } from './create-page';
+
+/**
+ * Invoked when creation and transition has finished
+ */
+type OnCreated = () => void;
+/**
+ * Invoked when either creation or transition has aborted
+ */
+type OnAborted = () => void;
+/**
+ * Always invoked after processing is terminated
+ */
+type OnTerminated = () => void;
+
+export type CreatePageOpts = {
+  skipPageExistenceCheck?: boolean,
+  skipTransition?: boolean,
+  onCreationStart?: OnCreated,
+  onCreated?: OnCreated,
+  onAborted?: OnAborted,
+  onTerminated?: OnTerminated,
+}
+
+type CreatePage = (
+  params: IApiv3PageCreateParams,
+  opts?: CreatePageOpts,
+) => Promise<void>;
+
+type UseCreatePage = () => {
+  isCreating: boolean,
+  create: CreatePage,
+};
+
+export const useCreatePage: UseCreatePage = () => {
+
+  const router = useRouter();
+  const { t } = useTranslation();
+
+  const { data: currentPagePath } = useCurrentPagePath();
+  const { mutate: mutateEditorMode } = useEditorMode();
+  const { open: openGrantedGroupsInheritanceSelectModal, close: closeGrantedGroupsInheritanceSelectModal } = useGrantedGroupsInheritanceSelectModal();
+
+  const [isCreating, setCreating] = useState(false);
+
+  const create: CreatePage = useCallback(async(params, opts = {}) => {
+    const {
+      onCreationStart, onCreated, onAborted, onTerminated,
+    } = opts;
+    const skipPageExistenceCheck = opts.skipPageExistenceCheck ?? false;
+    const skipTransition = opts.skipTransition ?? false;
+
+    // check the page existence
+    if (!skipPageExistenceCheck && params.path != null) {
+      const pagePath = params.path;
+
+      try {
+        const { isExist } = await exist(pagePath);
+
+        if (isExist) {
+          if (!skipTransition) {
+            // routing
+            if (pagePath !== currentPagePath) {
+              await router.push(`${pagePath}#edit`);
+            }
+            mutateEditorMode(EditorMode.Editor);
+          }
+          else {
+            toastWarning(t('duplicated_page_alert.same_page_name_exists', { pageName: pagePath }));
+          }
+          onAborted?.();
+          return;
+        }
+      }
+      catch (err) {
+        throw err;
+      }
+      finally {
+        onTerminated?.();
+      }
+    }
+
+    const _create = async(onlyInheritUserRelatedGrantedGroups?: boolean) => {
+      try {
+        setCreating(true);
+        onCreationStart?.();
+
+        params.onlyInheritUserRelatedGrantedGroups = onlyInheritUserRelatedGrantedGroups;
+        const response = await createPage(params);
+
+        closeGrantedGroupsInheritanceSelectModal();
+
+        if (!skipTransition) {
+          await router.push(`/${response.page._id}#edit`);
+          mutateEditorMode(EditorMode.Editor);
+        }
+
+        onCreated?.();
+      }
+      catch (err) {
+        throw err;
+      }
+      finally {
+        onTerminated?.();
+        setCreating(false);
+      }
+    };
+
+    // If parent page is granted to non-user-related groups, let the user select whether or not to inherit them.
+    if (params.parentPath != null) {
+      const { isNonUserRelatedGroupsGranted } = await getIsNonUserRelatedGroupsGranted(params.parentPath);
+      if (isNonUserRelatedGroupsGranted) {
+        // create and transit request will be made from modal
+        openGrantedGroupsInheritanceSelectModal(_create);
+        return;
+      }
+    }
+
+    await _create();
+  }, [currentPagePath, mutateEditorMode, router, openGrantedGroupsInheritanceSelectModal, closeGrantedGroupsInheritanceSelectModal, t]);
+
+  return {
+    isCreating,
+    create,
+  };
+};

+ 7 - 6
apps/app/src/client/services/create-page/use-create-template-page.ts

@@ -8,7 +8,7 @@ import type { LabelType } from '~/interfaces/template';
 import { useCurrentPagePath } from '~/stores/page';
 
 
-import { useCreatePageAndTransit } from './use-create-page-and-transit';
+import { useCreatePage } from './use-create-page';
 
 type UseCreateTemplatePage = () => {
   isCreatable: boolean,
@@ -20,17 +20,18 @@ export const useCreateTemplatePage: UseCreateTemplatePage = () => {
 
   const { data: currentPagePath, isLoading: isLoadingPagePath } = useCurrentPagePath();
 
-  const { isCreating, createAndTransit } = useCreatePageAndTransit();
+  const { isCreating, create } = useCreatePage();
   const isCreatable = currentPagePath != null && isCreatablePage(normalizePath(`${currentPagePath}/_template`));
 
   const createTemplate = useCallback(async(label: LabelType) => {
     if (isLoadingPagePath || !isCreatable) return;
 
-    return createAndTransit(
-      { path: normalizePath(`${currentPagePath}/${label}`), wip: false, origin: Origin.View },
-      { shouldCheckPageExists: true },
+    return create(
+      {
+        path: normalizePath(`${currentPagePath}/${label}`), parentPath: currentPagePath, wip: false, origin: Origin.View,
+      },
     );
-  }, [currentPagePath, isCreatable, isLoadingPagePath, createAndTransit]);
+  }, [currentPagePath, isCreatable, isLoadingPagePath, create]);
 
   return {
     isCreatable,

+ 9 - 0
apps/app/src/client/services/page-operation.ts

@@ -156,6 +156,15 @@ export const exist = async(path: string): Promise<PageExistResponse> => {
   return res.data;
 };
 
+interface NonUserRelatedGroupsGrantedResponse {
+  isNonUserRelatedGroupsGranted: boolean,
+}
+
+export const getIsNonUserRelatedGroupsGranted = async(path: string): Promise<NonUserRelatedGroupsGrantedResponse> => {
+  const res = await apiv3Get<NonUserRelatedGroupsGrantedResponse>('/page/non-user-related-groups-granted', { path });
+  return res.data;
+};
+
 export const publish = async(pageId: string): Promise<IPageHasId> => {
   const res = await apiv3Put(`/page/${pageId}/publish`);
   return res.data;

+ 1 - 1
apps/app/src/client/services/side-effects/handsontable-modal-launcher-for-view.ts

@@ -3,8 +3,8 @@ import { useCallback, useEffect } from 'react';
 import type EventEmitter from 'events';
 
 import { Origin } from '@growi/core';
+import type { MarkdownTable } from '@growi/editor';
 
-import type MarkdownTable from '~/client/models/MarkdownTable';
 import { extractRemoteRevisionDataFromErrorObj, updatePage as _updatePage } from '~/client/services/update-page';
 import { getMarkdownTableFromLine, replaceMarkdownTableInMarkdown } from '~/components/Page/markdown-table-util-for-view';
 import { useShareLinkId } from '~/stores/context';

+ 3 - 1
apps/app/src/components/Admin/App/MaskedInput.module.scss

@@ -1,3 +1,5 @@
+/* stylelint-disable selector-class-pattern */
+
 .MaskedInput {
   position: relative;
   display: flex;
@@ -5,7 +7,7 @@
 
 .PasswordReveal {
   position: absolute;
-  top: 0rem;
+  top: 0;
   right: 0.5rem;
   left: auto;
   font-size: 1.4rem;

+ 2 - 2
apps/app/src/components/Admin/Customize/CustomizeThemeOptions.tsx

@@ -30,7 +30,7 @@ const CustomizeThemeOptions = (props: Props): JSX.Element => {
       {/* Light and Dark Themes */}
       <div>
         <h3 className="mb-3">{t('customize_settings.theme_desc.light_and_dark')}</h3>
-        <div className="hstack gap-3">
+        <div className="hstack gap-3 flex-wrap">
           {lightNDarkThemes.map((theme) => {
             return (
               <ThemeColorBox
@@ -47,7 +47,7 @@ const CustomizeThemeOptions = (props: Props): JSX.Element => {
       {/* Only one mode Theme */}
       <div className="mt-3">
         <h3 className="mb-3">{t('customize_settings.theme_desc.unique')}</h3>
-        <div className="hstack gap-3">
+        <div className="hstack gap-3 align-items-start flex-wrap">
           {oneModeThemes.map((theme) => {
             return (
               <ThemeColorBox

+ 1 - 1
apps/app/src/components/Admin/Customize/ThemeColorBox.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 // layout
 .theme-option-container :global {

+ 2 - 1
apps/app/src/components/Admin/UserManagement.module.scss

@@ -1,9 +1,10 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 // styles for admin user search
 .search-typeahead :global {
   position: relative;
   width: 100%;
+
   // corner radius
   border-top-right-radius: bs.$border-radius;
   border-bottom-right-radius: bs.$border-radius;

+ 1 - 1
apps/app/src/components/AuthorInfo/AuthorInfo.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 $author-font-size: 12px;
 $date-font-size: 11px;

+ 1 - 2
apps/app/src/components/Common/CopyDropdown/CopyDropdown.module.scss

@@ -1,5 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '@growi/ui/scss/atoms/btn-muted';
 
 .grw-copy-dropdown :global {

+ 1 - 3
apps/app/src/components/Common/DrawerToggler/DrawerToggler.module.scss

@@ -1,5 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '~/styles/variables' as var;
 
 
@@ -7,7 +6,6 @@
   .btn {
     --bs-btn-color: rgba(var(--bs-tertiary-color-rgb), 0.5);
     --bs-btn-bg: transparent;
-
     --bs-btn-hover-color: rgba(var(--bs-tertiary-color-rgb), 0.7);
 
     width: var.$grw-sidebar-nav-width;

+ 1 - 1
apps/app/src/components/Common/PagePathHierarchicalLink/CollapsedParentsDropdown.module.scss

@@ -1,5 +1,5 @@
 
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .collapsed-parents-dropdown-menu {
   --bs-dropdown-zindex: #{bs.$zindex-fixed};

+ 1 - 2
apps/app/src/components/Common/PagePathNav/PagePathNav.module.scss

@@ -1,5 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '@growi/ui/scss/atoms/btn-muted';
 
 .grw-mx-02em {

+ 3 - 2
apps/app/src/components/Common/PageViewLayout.module.scss

@@ -1,5 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '~/styles/mixins';
 @use '~/styles/variables' as var;
 
@@ -9,6 +8,7 @@ $page-view-layout-margin-top: 32px;
 
 .page-view-layout :global {
   $page-content-footer-min-heigh: 130px;
+
   min-height: calc(100vh - #{$subnavigation-height + $page-view-layout-margin-top + $page-content-footer-min-heigh});
 }
 
@@ -42,6 +42,7 @@ $page-view-layout-margin-top: 32px;
     position: sticky;
 
     $page-path-nav-height: 99px;
+
     top: calc($subnavigation-height + $page-view-layout-margin-top + $page-path-nav-height + 4px);
   }
 }

+ 2 - 2
apps/app/src/components/CustomNavigation/CustomNav.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .grw-custom-nav-tab :global {
   .nav-title {
@@ -10,7 +10,7 @@
   }
 
   .grw-nav-slide-hr {
-    border-top: 0rem;
+    border-top: 0;
     border-bottom: 3px solid;
     transition: 0.3s ease-in-out;
   }

+ 2 - 2
apps/app/src/components/DescendantsPageListModal.module.scss

@@ -1,7 +1,7 @@
 .grw-descendants-page-list-modal :global {
   .modal-header {
     button.btn-close {
-      margin: auto 0rem auto auto;
+      margin: auto 0 auto auto;
     }
   }
 
@@ -13,6 +13,6 @@
     max-height: calc(100vh - 100px);
   }
   ul.pagination {
-    margin-bottom: 0rem;
+    margin-bottom: 0;
   }
 }

+ 69 - 0
apps/app/src/components/GrantedGroupsInheritanceSelectModal.tsx

@@ -0,0 +1,69 @@
+import { useState } from 'react';
+
+import { useTranslation } from 'react-i18next';
+import {
+  Modal, ModalHeader, ModalBody, ModalFooter,
+} from 'reactstrap';
+
+import { useGrantedGroupsInheritanceSelectModal } from '~/stores/modal';
+
+const GrantedGroupsInheritanceSelectModal = (): JSX.Element => {
+  const { t } = useTranslation();
+  const { data: modalData, close: closeModal } = useGrantedGroupsInheritanceSelectModal();
+  const [onlyInheritUserRelatedGrantedGroups, setOnlyInheritUserRelatedGrantedGroups] = useState(false);
+
+  const onCreateBtnClick = async() => {
+    await modalData?.onCreateBtnClick?.(onlyInheritUserRelatedGrantedGroups);
+    setOnlyInheritUserRelatedGrantedGroups(false); // reset to false after create request
+  };
+  const isOpened = modalData?.isOpened ?? false;
+
+  return (
+    <Modal
+      isOpen={isOpened}
+      toggle={() => closeModal()}
+    >
+      <ModalHeader tag="h4" toggle={() => closeModal()}>
+        {t('modal_granted_groups_inheritance_select.select_granted_groups')}
+      </ModalHeader>
+      <ModalBody>
+        <div className="px-3 pt-3">
+          <div className="form-check radio-primary mb-3">
+            <input
+              type="radio"
+              id="inheritAllGroupsRadio"
+              className="form-check-input"
+              form="formImageType"
+              checked={!onlyInheritUserRelatedGrantedGroups}
+              onChange={() => { setOnlyInheritUserRelatedGrantedGroups(false) }}
+            />
+            <label className="form-check-label" htmlFor="inheritAllGroupsRadio">
+              {t('modal_granted_groups_inheritance_select.inherit_all_granted_groups_from_parent')}
+            </label>
+          </div>
+          <div className="form-check radio-primary">
+            <input
+              type="radio"
+              id="onlyInheritRelatedGroupsRadio"
+              className="form-check-input"
+              form="formImageType"
+              checked={onlyInheritUserRelatedGrantedGroups}
+              onChange={() => { setOnlyInheritUserRelatedGrantedGroups(true) }}
+            />
+            <label className="form-check-label" htmlFor="onlyInheritRelatedGroupsRadio">
+              {t('modal_granted_groups_inheritance_select.only_inherit_related_groups')}
+            </label>
+          </div>
+        </div>
+      </ModalBody>
+      <ModalFooter className="grw-modal-footer">
+        <button type="button" className="me-2 btn btn-secondary" onClick={() => closeModal()}>{t('Cancel')}</button>
+        <button className="btn btn-primary" type="button" onClick={onCreateBtnClick}>
+          {t('modal_granted_groups_inheritance_select.create_page')}
+        </button>
+      </ModalFooter>
+    </Modal>
+  );
+};
+
+export default GrantedGroupsInheritanceSelectModal;

+ 1 - 1
apps/app/src/components/Icons/GrowiLogo.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/growi-official-colors';
+@use '@growi/core-styles/scss/variables/growi-official-colors';
 
 // == Colors
 .grw-logo :global {

+ 4 - 0
apps/app/src/components/ItemsTree/ItemsTree.module.scss

@@ -0,0 +1,4 @@
+/* stylelint-disable-next-line block-no-empty */
+.items-tree :global {
+
+}

+ 2 - 0
apps/app/src/components/ItemsTree/ItemsTreeContentSkeleton.module.scss

@@ -2,10 +2,12 @@
 
 .text-skeleton-level1 {
   @include mixins.grw-skeleton-text($font-size:16px, $line-height: 40px);
+
   padding-left: 12px;
 }
 
 .text-skeleton-level2 {
   @extend .text-skeleton-level1;
+
   padding-left: 12px + 10px * 2;
 }

+ 4 - 2
apps/app/src/components/Layout/Admin.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as *;
+@use '@growi/core-styles/scss/bootstrap/init' as *;
 @use '~/styles/mixins';
 
 $slack-work-space-name-card-background: #fff5ff;
@@ -114,6 +114,7 @@ $slack-work-space-name-card-border: #efc1f6;
       border-width: 2px;
     }
   }
+
   // TODO: change to utility class on Bootstrap 5
   .slack-connection-log {
     .slack-connection-log-title {
@@ -173,6 +174,7 @@ $slack-work-space-name-card-border: #efc1f6;
       &.with-proxy {
         .hr-container {
           margin-top: 40px;
+
           @include media-breakpoint-up(lg) {
             margin-top: 65px;
           }
@@ -189,7 +191,7 @@ $slack-work-space-name-card-border: #efc1f6;
   //// TODO: migrate to Bootstrap 4
   //// omit all .btn-toggle and use Switches
   //// https://getbootstrap.com/docs/4.2/components/forms/#switches
-  //
+
   // Toggle Twitter Bootstrap button class when active
   // https://jsfiddle.net/ms040m01/3/
   // @mixin active-color($color, $bg-color, $border-color) {

+ 28 - 0
apps/app/src/components/Layout/BasicLayout.module.scss

@@ -0,0 +1,28 @@
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
+@use '~/styles/mixins';
+
+
+// for react-toastify
+.grw-basic-layout :global {
+  .Toastify .Toastify__toast-container {
+    top: 2.5em;
+
+    @include bs.media-breakpoint-down(md) {
+      top: 6.5em;
+    }
+  }
+}
+
+.grw-basic-layout {
+  @include mixins.with-editing() {
+    .Toastify .Toastify__toast-container {
+      top: 5em;
+
+      @include bs.media-breakpoint-down(md) {
+        top: 7em;
+      }
+    }
+  }
+}
+
+

+ 9 - 1
apps/app/src/components/Layout/BasicLayout.tsx

@@ -9,6 +9,12 @@ import { Sidebar } from '../Sidebar';
 
 import { RawLayout } from './RawLayout';
 
+
+import styles from './BasicLayout.module.scss';
+
+const moduleClass = styles['grw-basic-layout'] ?? '';
+
+
 const AlertSiteUrlUndefined = dynamic(() => import('../AlertSiteUrlUndefined').then(mod => mod.AlertSiteUrlUndefined), { ssr: false });
 const DeleteAttachmentModal = dynamic(() => import('../PageAttachment/DeleteAttachmentModal').then(mod => mod.DeleteAttachmentModal), { ssr: false });
 const HotkeysManager = dynamic(() => import('../Hotkeys/HotkeysManager'), { ssr: false });
@@ -23,6 +29,7 @@ const PageDeleteModal = dynamic(() => import('../PageDeleteModal'), { ssr: false
 const PageRenameModal = dynamic(() => import('../PageRenameModal'), { ssr: false });
 const PagePresentationModal = dynamic(() => import('../PagePresentationModal'), { ssr: false });
 const PageAccessoriesModal = dynamic(() => import('../PageAccessoriesModal').then(mod => mod.PageAccessoriesModal), { ssr: false });
+const GrantedGroupsInheritanceSelectModal = dynamic(() => import('../GrantedGroupsInheritanceSelectModal'), { ssr: false });
 const DeleteBookmarkFolderModal = dynamic(() => import('../DeleteBookmarkFolderModal').then(mod => mod.DeleteBookmarkFolderModal), { ssr: false });
 const SearchModal = dynamic(() => import('../../features/search/client/components/SearchModal'), { ssr: false });
 
@@ -35,7 +42,7 @@ type Props = {
 
 export const BasicLayout = ({ children, className }: Props): JSX.Element => {
   return (
-    <RawLayout className={`${className ?? ''}`}>
+    <RawLayout className={`${moduleClass} ${className ?? ''}`}>
       <DndProvider backend={HTML5Backend}>
 
         <div className="page-wrapper flex-row">
@@ -66,6 +73,7 @@ export const BasicLayout = ({ children, className }: Props): JSX.Element => {
       <HotkeysManager />
 
       <ShortcutsModal />
+      <GrantedGroupsInheritanceSelectModal />
       <SystemVersion showShortcutsButton />
     </RawLayout>
   );

+ 17 - 13
apps/app/src/components/Layout/NoLoginLayout.module.scss

@@ -1,10 +1,17 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-@use '@growi/core/scss/growi-official-colors' as var;
+/* stylelint-disable scss/no-global-function-names */
+
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/variables/growi-official-colors' as var;
 
 
 .nologin :global {
   height: 100vh;
 
+  .nologin-header,
+  .nologin-dialog {
+    max-width: 480px;
+  }
+
   // layout
   .main {
     width: 100vw;
@@ -54,11 +61,6 @@
     }
   }
 
-  .nologin-header,
-  .nologin-dialog {
-    max-width: 480px;
-  }
-
 }
 
 .link-switch {
@@ -80,9 +82,10 @@
   .nologin :global {
     // background color
     $color-gradient: #3c465c;
-    background: linear-gradient(45deg, darken($color-gradient, 30%) 0%, hsla(340, 100%, 55%, 0) 70%),
-      linear-gradient(135deg, var.$growi-green 10%, hsla(225, 95%, 50%, 0) 70%), linear-gradient(225deg, var.$growi-blue 10%, hsla(140, 90%, 50%, 0) 80%),
-      linear-gradient(315deg, darken($color-gradient, 25%) 100%, hsla(35, 95%, 55%, 0) 70%);
+
+    background: linear-gradient(45deg, darken($color-gradient, 30%) 0%, hsla(340deg, 100%, 55%, 0%) 70%),
+      linear-gradient(135deg, var.$growi-green 10%, hsla(225deg, 95%, 50%, 0%) 70%), linear-gradient(225deg, var.$growi-blue 10%, hsla(140deg, 90%, 50%, 0%) 80%),
+      linear-gradient(315deg, darken($color-gradient, 25%) 100%, hsla(35deg, 95%, 55%, 0%) 70%);
 
     .nologin-header {
       background-color: rgba(white, 0.3);
@@ -134,9 +137,10 @@
   .nologin :global {
     // background color
     $color-gradient: #3c465c;
-    background: linear-gradient(45deg, darken($color-gradient, 30%) 0%, hsla(340, 100%, 55%, 0) 70%),
-      linear-gradient(135deg, var.$growi-green 10%, hsla(225, 95%, 50%, 0) 70%), linear-gradient(225deg, var.$growi-blue 10%, hsla(140, 90%, 50%, 0) 80%),
-      linear-gradient(315deg, darken($color-gradient, 25%) 100%, hsla(35, 95%, 55%, 0) 70%);
+
+    background: linear-gradient(45deg, darken($color-gradient, 30%) 0%, hsla(340deg, 100%, 55%, 0%) 70%),
+      linear-gradient(135deg, var.$growi-green 10%, hsla(225deg, 95%, 50%, 0%) 70%), linear-gradient(225deg, var.$growi-blue 10%, hsla(140deg, 90%, 50%, 0%) 80%),
+      linear-gradient(315deg, darken($color-gradient, 25%) 100%, hsla(35deg, 95%, 55%, 0%) 70%);
 
     .nologin-header {
       background-color: rgba(black, 0.3);

+ 1 - 1
apps/app/src/components/Layout/SearchResultLayout.module.scss

@@ -1,5 +1,5 @@
 @use '~/styles/variables' as var;
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .on-search :global {
   .page-wrapper {

+ 3 - 4
apps/app/src/components/LoginForm/LoginForm.module.scss

@@ -1,5 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '~/styles/atoms/placeholders/buttons';
 
 .login-form :global {
@@ -24,8 +23,8 @@
   }
 
   .text-line {
-    &:before,
-    &:after {
+    &::before,
+    &::after {
       flex-grow: 1;
       height: 1px;
       margin:0 1em;

+ 0 - 2
apps/app/src/components/Me/ColorModeSettings.tsx

@@ -4,8 +4,6 @@ import { useTranslation } from 'react-i18next';
 
 import { Themes, useNextThemes } from '~/stores/use-next-themes';
 
-// import styles from './ColorModeSettings.module.scss';
-
 
 type ColorModeSettingsButtonProps = {
   isActive: boolean,

+ 1 - 1
apps/app/src/components/Me/UISettings.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .grw-sidebar-mode-icon {
   display: flex;

+ 2 - 2
apps/app/src/components/Navbar/GrowiContextualSubNavigation.module.scss

@@ -1,5 +1,5 @@
 @use '~/styles/mixins';
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .grw-contextual-sub-navigation {
   @include bs.media-breakpoint-down(md) {
@@ -9,7 +9,7 @@
   }
 }
 
-@include mixins.editing() {
+@include mixins.at-editing() {
   .grw-contextual-sub-navigation {
     position: fixed;
     right: 0;

+ 1 - 0
apps/app/src/components/Navbar/GrowiNavbarBottom.module.scss

@@ -4,6 +4,7 @@
 .grw-navbar-bottom :global {
   // apply transition
   transition-property: bottom;
+
   @include mixins.apply-navigation-transition();
 
   .navbar {

+ 3 - 1
apps/app/src/components/Navbar/PageEditorModeManager.module.scss

@@ -1,5 +1,5 @@
 // @mixin page-editor-mode-manager($textColor, $borderColor, $bgColorHoverAndActive, $bgColor: white) {
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '~/styles/mixins';
 
 .grw-page-editor-mode-manager :global {
@@ -20,6 +20,7 @@
 .grw-page-editor-mode-manager-skeleton :global {
   width: 90px;
   height: 38px;
+
   @include bs.media-breakpoint-up(md) {
     width: 179px;
     height: 30px;
@@ -47,6 +48,7 @@
     }
   }
 }
+
 @include bs.color-mode(dark) {
   .grw-page-editor-mode-manager :global {
     .btn {

+ 9 - 6
apps/app/src/components/Navbar/PageEditorModeManager.tsx

@@ -1,9 +1,10 @@
 import React, { type ReactNode, useCallback, useMemo } from 'react';
 
 import { Origin } from '@growi/core';
+import { normalizePath } from '@growi/core/dist/utils/path-utils';
 import { useTranslation } from 'next-i18next';
 
-import { useCreatePageAndTransit } from '~/client/services/create-page';
+import { useCreatePage } from '~/client/services/create-page';
 import { toastError } from '~/client/util/toastr';
 import { useIsNotFound } from '~/stores/page';
 import { EditorMode, useEditorMode, useIsDeviceLargerThanMd } from '~/stores/ui';
@@ -67,7 +68,7 @@ export const PageEditorModeManager = (props: Props): JSX.Element => {
   const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
   const { data: currentPageYjsData } = useCurrentPageYjsData();
 
-  const { isCreating, createAndTransit } = useCreatePageAndTransit();
+  const { isCreating, create } = useCreatePage();
 
   const editButtonClickedHandler = useCallback(async() => {
     if (isNotFound == null || isNotFound === false) {
@@ -76,15 +77,17 @@ export const PageEditorModeManager = (props: Props): JSX.Element => {
     }
 
     try {
-      await createAndTransit(
-        { path, wip: shouldCreateWipPage(path), origin: Origin.View },
-        { shouldCheckPageExists: true },
+      const parentPath = path != null ? normalizePath(path.split('/').slice(0, -1).join('/')) : undefined; // does not have to exist
+      await create(
+        {
+          path, parentPath, wip: shouldCreateWipPage(path), origin: Origin.View,
+        },
       );
     }
     catch (err) {
       toastError(t('toaster.create_failed', { target: path }));
     }
-  }, [createAndTransit, isNotFound, mutateEditorMode, path, t]);
+  }, [create, isNotFound, mutateEditorMode, path, t]);
 
   const _isBtnDisabled = isCreating || isBtnDisabled;
 

+ 1 - 1
apps/app/src/components/Page/markdown-table-util-for-view.ts

@@ -1,4 +1,4 @@
-import MarkdownTable from '~/client/models/MarkdownTable';
+import { MarkdownTable } from '@growi/editor';
 
 export const getMarkdownTableFromLine = (markdown: string, bol: number, eol: number): MarkdownTable => {
   const tableLines = markdown.split(/\r\n|\r|\n/).slice(bol - 1, eol).join('\n');

+ 2 - 2
apps/app/src/components/PageAccessoriesModal/PageAccessoriesModal.module.scss

@@ -1,7 +1,7 @@
 .grw-page-accessories-modal :global {
   .modal-header {
     button.btn-close {
-      margin: auto 0rem auto auto;
+      margin: auto 0 auto auto;
     }
   }
 
@@ -13,6 +13,6 @@
     max-height: calc(100vh - 100px);
   }
   ul.pagination {
-    margin-bottom: 0rem;
+    margin-bottom: 0;
   }
 }

+ 2 - 2
apps/app/src/components/PageAlert/FixPageGrantAlert.tsx

@@ -9,7 +9,7 @@ import {
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { toastError, toastSuccess } from '~/client/util/toastr';
 import { UserGroupPageGrantStatus, type IPageGrantData } from '~/interfaces/page';
-import type { PopulatedGrantedGroup, IRecordApplicableGrant, IResIsGrantNormalizedGrantData } from '~/interfaces/page-grant';
+import type { PopulatedGrantedGroup, IRecordApplicableGrant, IResGrantData } from '~/interfaces/page-grant';
 import { useCurrentUser } from '~/stores/context';
 import { useSWRxApplicableGrant, useSWRxCurrentGrantData, useSWRxCurrentPage } from '~/stores/page';
 
@@ -17,7 +17,7 @@ type ModalProps = {
   isOpen: boolean
   pageId: string
   dataApplicableGrant: IRecordApplicableGrant
-  currentAndParentPageGrantData: IResIsGrantNormalizedGrantData
+  currentAndParentPageGrantData: IResGrantData
   close(): void
 }
 

+ 1 - 1
apps/app/src/components/PageComment.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .page-comment-styles :global {
   .page-comments {

+ 6 - 7
apps/app/src/components/PageComment/Comment.module.scss

@@ -1,14 +1,12 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '../../styles/variables' as var;
-@use './_comment-inheritance';
+@use './comment-inheritance';
 
 .comment-styles :global {
 
   .page-comment {
     position: relative;
     pointer-events: none;
-
     scroll-margin-top: var.$grw-scroll-margin-top-in-view;
 
     // background
@@ -49,8 +47,9 @@
     }
 
     // older comments
-    &.page-comment-older {
-    }
+    // &.page-comment-older {
+    // }
+
     // newer comments
     &.page-comment-newer {
       opacity: 0.7;
@@ -71,7 +70,6 @@
     .page-comment-meta {
       display: flex;
       justify-content: flex-end;
-
       font-size: 0.9em;
       color: bs.$gray-400;
     }
@@ -84,6 +82,7 @@
     height: 66px;
     padding: 1em;
     margin-left: 4.5em;
+
     @include bs.media-breakpoint-down(xs) {
       margin-left: 3.5em;
     }

+ 2 - 3
apps/app/src/components/PageComment/CommentEditor.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use './comment-inheritance';
 @use '../PageEditor/page-editor-inheritance';
 
@@ -31,8 +31,7 @@
     min-height: comment-inheritance.$codemirror-default-height !important;
   }
   .comment-preview-container {
-    min-height: page-editor-inheritance.$navbar-editor-height
-      + comment-inheritance.$codemirror-default-height;
+    min-height: page-editor-inheritance.$navbar-editor-height + comment-inheritance.$codemirror-default-height;
     padding-top: 0.5em;
   }
 }

+ 3 - 2
apps/app/src/components/PageComment/CommentEditor.tsx

@@ -4,9 +4,10 @@ import React, {
   useMemo,
 } from 'react';
 
+import { GlobalCodeMirrorEditorKey } from '@growi/editor';
 import {
-  CodeMirrorEditorComment, GlobalCodeMirrorEditorKey, useCodeMirrorEditorIsolated, useResolvedThemeForEditor,
-} from '@growi/editor';
+  CodeMirrorEditorComment, useCodeMirrorEditorIsolated, useResolvedThemeForEditor,
+} from '@growi/editor/dist/client';
 import { UserPicture } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';

+ 1 - 0
apps/app/src/components/PageComment/CommentPreview.module.scss

@@ -1,2 +1,3 @@
+/* stylelint-disable-next-line block-no-empty */
 .grw-comment-preview {
 }

+ 1 - 0
apps/app/src/components/PageComment/DeleteCommentModal.module.scss

@@ -3,6 +3,7 @@
   .modal-content .modal-body {
     .comment-body {
       max-height: 13em;
+
       // scrollable
       overflow-y: auto;
     }

+ 2 - 1
apps/app/src/components/PageComment/SwitchingButtonGroup.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 
 .btn-group-switching :global {
@@ -31,6 +31,7 @@
     }
   }
 }
+
 @include bs.color-mode(dark) {
   .btn-group-switching :global {
     .btn {

+ 4 - 4
apps/app/src/components/PageComment/_comment-inheritance.scss

@@ -1,11 +1,11 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 %comment-section {
   position: relative;
   padding: 1em;
 
   // speech balloon
-  &:before {
+  &::before {
     position: absolute;
     top: 1.5em;
     left: -1em;
@@ -32,8 +32,8 @@ $codemirror-default-height: 300px;
 @include bs.color-mode(light) {
   %bg-comment {
     background-color: rgba( bs.$gray-200, 0.5 );
-    border: 1px solid bs.$gray-200;
     backdrop-filter: blur(10px);
+    border: 1px solid bs.$gray-200;
   }
 }
 
@@ -41,7 +41,7 @@ $codemirror-default-height: 300px;
 @include bs.color-mode(dark) {
   %bg-comment {
     background-color: rgba( bs.$gray-800, 0.3 );
-    border: 1px solid bs.$gray-700;
     backdrop-filter: blur(10px);
+    border: 1px solid bs.$gray-700;
   }
 }

+ 2 - 1
apps/app/src/components/PageContentFooter.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .page-content-footer :global {
   border-top: solid 1px transparent;
@@ -6,6 +6,7 @@
     font-size: 0.95em;
   }
 }
+
 // TODO: Should Soft Coding see: https://github.com/weseek/growi/pull/6404
 .page-content-footer-skeleton :global {
   width: 300px;

+ 3 - 3
apps/app/src/components/PageControls/BookmarkButtons.module.scss

@@ -1,7 +1,5 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '@growi/ui/scss/atoms/btn-muted';
-
 @use './button-styles';
 
 .btn-group-bookmark :global {
@@ -13,12 +11,14 @@
   }
   .total-counts {
     @extend %btn-total-counts-basis;
+
     padding-left: 5px;
   }
 }
 
 // == Colors
 .btn-group-bookmark :global {
+  /* stylelint-disable-next-line no-descending-specificity */
   .btn-bookmark {
     @include btn-muted.colorize(bs.$orange);
   }

+ 2 - 3
apps/app/src/components/PageControls/LikeButtons.module.scss

@@ -1,7 +1,5 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '@growi/ui/scss/atoms/btn-muted';
-
 @use './button-styles';
 
 .btn-group-like :global {
@@ -13,6 +11,7 @@
   }
   .total-counts {
     @extend %btn-total-counts-basis;
+
     padding-left: 5px;
   }
 }

+ 1 - 3
apps/app/src/components/PageControls/PageControls.module.scss

@@ -1,7 +1,5 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '@growi/ui/scss/atoms/btn-muted';
-
 @use './button-styles';
 
 // PageItemControl styles

+ 18 - 19
apps/app/src/components/PageControls/PageControls.tsx

@@ -10,13 +10,12 @@ import {
 } from '@growi/core';
 import { useRect } from '@growi/ui/dist/utils';
 import { useTranslation } from 'next-i18next';
-import { DropdownItem } from 'reactstrap';
 
 import {
   toggleLike, toggleSubscribe,
 } from '~/client/services/page-operation';
 import { toastError } from '~/client/util/toastr';
-import { useIsGuestUser, useIsReadOnlyUser } from '~/stores/context';
+import { useIsGuestUser, useIsReadOnlyUser, useIsSearchPage } from '~/stores/context';
 import { useTagEditModal, type IPageForPageDuplicateModal } from '~/stores/modal';
 import {
   EditorMode, useEditorMode, useIsDeviceLargerThanMd, usePageControlsX,
@@ -66,7 +65,7 @@ const Tags = (props: TagsProps): JSX.Element => {
 };
 
 type WideViewMenuItemProps = AdditionalMenuItemsRendererProps & {
-  onClickMenuItem: (newValue: boolean) => void,
+  onChange: () => void,
   expandContentWidth?: boolean,
 }
 
@@ -74,27 +73,24 @@ const WideViewMenuItem = (props: WideViewMenuItemProps): JSX.Element => {
   const { t } = useTranslation();
 
   const {
-    onClickMenuItem, expandContentWidth,
+    onChange, expandContentWidth,
   } = props;
 
   return (
-    <DropdownItem
-      onClick={() => onClickMenuItem(!(expandContentWidth))}
-      className="grw-page-control-dropdown-item"
-    >
-      <div className="form-check form-switch ms-1">
+    <div className="grw-page-control-dropdown-item dropdown-item">
+      <div className="form-check form-switch ms-1 flex-fill d-flex">
         <input
-          id="switchContentWidth"
+          id="wide-view-checkbox"
           className="form-check-input"
           type="checkbox"
-          checked={expandContentWidth}
-          onChange={() => {}}
+          defaultChecked={expandContentWidth}
+          onChange={onChange}
         />
-        <label className="form-label form-check-label" htmlFor="switchContentWidth">
+        <label className="form-check-label flex-grow-1 ms-2" htmlFor="wide-view-checkbox">
           { t('wide_view') }
         </label>
       </div>
-    </DropdownItem>
+    </div>
   );
 };
 
@@ -133,6 +129,7 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
   const { data: isReadOnlyUser } = useIsReadOnlyUser();
   const { data: editorMode } = useEditorMode();
   const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
+  const { data: isSearchPage } = useIsSearchPage();
 
   const { mutate: mutatePageInfo } = useSWRxPageInfo(pageId, shareLinkId);
 
@@ -224,7 +221,9 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
     onClickDeleteMenuItem(pageToDelete);
   }, [onClickDeleteMenuItem, pageId, pageInfo, path, revisionId]);
 
-  const switchContentWidthClickHandler = useCallback(async(newValue: boolean) => {
+  const switchContentWidthClickHandler = useCallback(() => {
+
+    const newValue = !expandContentWidth;
     if (onClickSwitchContentWidth == null || (isGuestUser ?? true) || (isReadOnlyUser ?? true)) {
       logger.warn('Could not switch content width', {
         onClickSwitchContentWidth: onClickSwitchContentWidth == null ? 'null' : 'not null',
@@ -242,7 +241,7 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
     catch (err) {
       toastError(err);
     }
-  }, [isGuestUser, isReadOnlyUser, onClickSwitchContentWidth, pageId, pageInfo]);
+  }, [expandContentWidth, isGuestUser, isReadOnlyUser, onClickSwitchContentWidth, pageId, pageInfo]);
 
   const additionalMenuItemOnTopRenderer = useMemo(() => {
     if (!isIPageInfoForEntity(pageInfo)) {
@@ -250,7 +249,7 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
     }
     const wideviewMenuItemRenderer = (props: WideViewMenuItemProps) => {
 
-      return <WideViewMenuItem {...props} onClickMenuItem={switchContentWidthClickHandler} expandContentWidth={expandContentWidth} />;
+      return <WideViewMenuItem {...props} onChange={switchContentWidthClickHandler} expandContentWidth={expandContentWidth} />;
     };
     return wideviewMenuItemRenderer;
   }, [pageInfo, switchContentWidthClickHandler, expandContentWidth]);
@@ -274,7 +273,7 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
 
   return (
     <div className={`${styles['grw-page-controls']} hstack gap-2`} ref={pageControlsRef}>
-      { isViewMode && isDeviceLargerThanMd && (
+      { isViewMode && isDeviceLargerThanMd && !isSearchPage && !isSearchPage && (
         <SearchButton />
       )}
 
@@ -307,7 +306,7 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
               bookmarkCount={pageInfo.bookmarkCount}
             />
           )}
-          {revisionId != null && (
+          {revisionId != null && !isSearchPage && (
             <SeenUserInfo
               seenUsers={seenUsers}
               sumOfSeenUsers={sumOfSeenUsers}

+ 1 - 3
apps/app/src/components/PageControls/SearchButton.module.scss

@@ -1,7 +1,5 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '@growi/ui/scss/atoms/btn-muted';
-
 @use './button-styles';
 
 .btn-search :global {

+ 1 - 3
apps/app/src/components/PageControls/SeenUserInfo.module.scss

@@ -1,7 +1,5 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '@growi/ui/scss/atoms/btn-muted';
-
 @use './button-styles';
 
 .grw-seen-user-info :global {

+ 1 - 3
apps/app/src/components/PageControls/SubscribeButton.module.scss

@@ -1,7 +1,5 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
-
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '@growi/ui/scss/atoms/btn-muted';
-
 @use './button-styles';
 
 .btn-subscribe :global {

+ 1 - 1
apps/app/src/components/PageControls/_button-styles.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 %btn-basis {
   --bs-btn-padding-x: 6px;

+ 0 - 3
apps/app/src/components/PageCreateModal.module.scss

@@ -2,9 +2,6 @@
   .page-today-input1 {
     width: 60px;
   }
-  .page-today-input2 {
-  }
-
   .grw-btn-create-page {
     min-width: 90px;
   }

+ 12 - 9
apps/app/src/components/PageCreateModal.tsx

@@ -12,7 +12,7 @@ import {
 import { debounce } from 'throttle-debounce';
 
 import { useCreateTemplatePage } from '~/client/services/create-page';
-import { useCreatePageAndTransit } from '~/client/services/create-page/use-create-page-and-transit';
+import { useCreatePage } from '~/client/services/create-page/use-create-page';
 import { useToastrOnError } from '~/client/services/use-toastr-on-error';
 import { useCurrentUser, useIsSearchServiceReachable } from '~/stores/context';
 import { usePageCreateModal } from '~/stores/modal';
@@ -36,7 +36,7 @@ const PageCreateModal: React.FC = () => {
   const path = pageCreateModalData?.path;
   const isOpened = pageCreateModalData?.isOpened ?? false;
 
-  const { createAndTransit } = useCreatePageAndTransit();
+  const { create } = useCreatePage();
   const { createTemplate } = useCreateTemplatePage();
 
   const { data: isReachable } = useIsSearchServiceReachable();
@@ -94,25 +94,28 @@ const PageCreateModal: React.FC = () => {
    */
   const createTodayPage = useCallback(async() => {
     const joinedPath = [todaysParentPath, todayInput].join('/');
-    return createAndTransit(
-      { path: joinedPath, wip: true, origin: Origin.View },
-      { shouldCheckPageExists: true, onTerminated: closeCreateModal },
+    return create(
+      {
+        path: joinedPath, parentPath: todaysParentPath, wip: true, origin: Origin.View,
+      },
+      { onTerminated: closeCreateModal },
     );
-  }, [closeCreateModal, createAndTransit, todayInput, todaysParentPath]);
+  }, [closeCreateModal, create, todayInput, todaysParentPath]);
 
   /**
    * access input page
    */
   const createInputPage = useCallback(async() => {
-    return createAndTransit(
+    return create(
       {
         path: pageNameInput,
+        parentPath: pathname,
         wip: true,
         origin: Origin.View,
       },
-      { shouldCheckPageExists: true, onTerminated: closeCreateModal },
+      { onTerminated: closeCreateModal },
     );
-  }, [closeCreateModal, createAndTransit, pageNameInput]);
+  }, [closeCreateModal, create, pageNameInput, pathname]);
 
   /**
    * access template page

+ 3 - 2
apps/app/src/components/PageEditor/ConflictDiffModal.tsx

@@ -3,9 +3,10 @@ import React, {
 } from 'react';
 
 import type { IUser } from '@growi/core';
+import { GlobalCodeMirrorEditorKey } from '@growi/editor';
 import {
-  MergeViewer, CodeMirrorEditorDiff, GlobalCodeMirrorEditorKey, useCodeMirrorEditorIsolated,
-} from '@growi/editor';
+  MergeViewer, CodeMirrorEditorDiff, useCodeMirrorEditorIsolated,
+} from '@growi/editor/dist/client';
 import { UserPicture } from '@growi/ui/dist/components';
 import { format } from 'date-fns/format';
 import { useTranslation } from 'next-i18next';

+ 1 - 2
apps/app/src/components/PageEditor/DrawioModal.tsx

@@ -4,8 +4,7 @@ import React, {
   useMemo,
 } from 'react';
 
-import { useCodeMirrorEditorIsolated } from '@growi/editor';
-import { useDrawioModalForEditor } from '@growi/editor/src/stores/use-drawio';
+import { useCodeMirrorEditorIsolated, useDrawioModalForEditor } from '@growi/editor/dist/client';
 import { LoadingSpinner } from '@growi/ui/dist/components';
 import {
   Modal,

+ 2 - 1
apps/app/src/components/PageEditor/EditorNavbar/EditorNavbar.module.scss

@@ -1,7 +1,8 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .editor-navbar :global {
   min-height: 72px;
+
   @include bs.media-breakpoint-down(sm) {
     min-height: 96px;
   }

+ 2 - 2
apps/app/src/components/PageEditor/EditorNavbarBottom.module.scss

@@ -1,8 +1,8 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 @use '~/styles/variables' as var;
 @use '~/styles/mixins';
 
-@include mixins.editing() {
+@include mixins.at-editing() {
   .grw-editor-navbar-bottom :global {
     .grw-grant-selector {
       max-width: 250px;

+ 6 - 5
apps/app/src/components/PageEditor/GridEditModal.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/core/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
 
 .grw-grid-edit-modal :global {
   .desktop-preview,
@@ -6,13 +6,13 @@
   .mobile-preview {
     .row {
       height: 140px;
-      margin: 0px;
+      margin: 0;
     }
   }
   .desktop-preview {
     .row {
       div {
-        padding: 0px;
+        padding: 0;
       }
     }
   }
@@ -20,7 +20,7 @@
   .tablet-preview {
     .row {
       div {
-        padding: 0px;
+        padding: 0;
       }
     }
   }
@@ -29,13 +29,14 @@
     width: 75%;
     .row {
       div {
-        padding: 0px;
+        padding: 0;
       }
     }
   }
 
   .grid-division-menu {
     width: 60vw;
+
     @include bs.media-breakpoint-down(lg) {
       width: 80vw;
     }

+ 1 - 1
apps/app/src/components/PageEditor/HandsontableModal.module.scss

@@ -35,7 +35,7 @@
       padding-right: 35px;
       padding-left: 10px;
 
-      i:before {
+      i::before {
         position: absolute;
         top: 6px;
         right: 8px;

+ 2 - 2
apps/app/src/components/PageEditor/HandsontableModal.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
 
-import { useHandsontableModalForEditor } from '@growi/editor/src/stores/use-handsontable';
+import { MarkdownTable } from '@growi/editor';
+import { useHandsontableModalForEditor } from '@growi/editor/dist/client';
 import { HotTable } from '@handsontable/react';
 import type Handsontable from 'handsontable';
 import { useTranslation } from 'next-i18next';
@@ -10,7 +11,6 @@ import {
 } from 'reactstrap';
 import { debounce } from 'throttle-debounce';
 
-import MarkdownTable from '~/client/models/MarkdownTable';
 import { replaceFocusedMarkdownTableWithEditor, getMarkdownTable } from '~/components/PageEditor/markdown-table-util-for-editor';
 import { useHandsontableModal } from '~/stores/modal';
 

+ 2 - 2
apps/app/src/components/PageEditor/LinkEditModal.tsx

@@ -2,8 +2,8 @@ import React, { useEffect, useState, useCallback } from 'react';
 
 import path from 'path';
 
-import Linker from '@growi/editor/src/services/link-util/Linker';
-import { useLinkEditModal } from '@growi/editor/src/stores/use-link-edit-modal';
+import { Linker } from '@growi/editor';
+import { useLinkEditModal } from '@growi/editor/dist/client';
 import { useTranslation } from 'next-i18next';
 import {
   Modal,

+ 2 - 2
apps/app/src/components/PageEditor/LinkEditPreview.module.scss

@@ -1,8 +1,8 @@
 .linkedit-preview {
   .page-editor-preview-body {
     max-height: 70vh;
-    padding-top: 0px;
-    margin: 0px -10px 0px -10px;
+    padding-top: 0;
+    margin: 0 -10px;
     .wiki {
       overflow-y: scroll;
       font-size: 0.5rem;

+ 1 - 1
apps/app/src/components/PageEditor/MarkdownTableDataImportForm.tsx

@@ -1,12 +1,12 @@
 import React, { useState } from 'react';
 
+import { MarkdownTable } from '@growi/editor';
 import { useTranslation } from 'next-i18next';
 import {
   Button,
   Collapse,
 } from 'reactstrap';
 
-import MarkdownTable from '~/client/models/MarkdownTable';
 
 type MarkdownTableDataImportFormProps = {
   onCancel: () => void,

+ 8 - 5
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -9,10 +9,11 @@ import nodePath from 'path';
 
 import { type IPageHasId, Origin } from '@growi/core';
 import { pathUtils } from '@growi/core/dist/utils';
+import { GlobalCodeMirrorEditorKey } from '@growi/editor';
 import {
-  CodeMirrorEditorMain, GlobalCodeMirrorEditorKey,
+  CodeMirrorEditorMain,
   useCodeMirrorEditorIsolated, useResolvedThemeForEditor,
-} from '@growi/editor';
+} from '@growi/editor/dist/client';
 import { useRect } from '@growi/ui/dist/utils';
 import detectIndent from 'detect-indent';
 import { useTranslation } from 'next-i18next';
@@ -68,6 +69,7 @@ declare global {
 export type SaveOptions = {
   wip: boolean,
   slackChannels: string,
+  isSlackEnabled: boolean,
   overwriteScopesOfDescendants?: boolean
 }
 export type Save = (
@@ -149,7 +151,10 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     // set to ref
     initialValueRef.current = initialValue;
   }, [initialValue]);
-  const [markdownToPreview, setMarkdownToPreview] = useState<string>(initialValue);
+
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+
+  const [markdownToPreview, setMarkdownToPreview] = useState<string>(codeMirrorEditor?.getDoc() ?? '');
   const setMarkdownPreviewWithDebounce = useMemo(() => debounce(100, throttle(150, (value: string) => {
     setMarkdownToPreview(value);
   })), []);
@@ -159,8 +164,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   }, [setMarkdownPreviewWithDebounce]);
 
 
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
-
   const { scrollEditorHandler, scrollPreviewHandler } = useScrollSync(GlobalCodeMirrorEditorKey.MAIN, previewRef);
 
   const scrollEditorHandlerThrottle = useMemo(() => throttle(25, scrollEditorHandler), [scrollEditorHandler]);

+ 2 - 1
apps/app/src/components/PageEditor/PageEditorReadOnly.tsx

@@ -1,6 +1,7 @@
 import react, { useMemo, useRef } from 'react';
 
-import { CodeMirrorEditorReadOnly, GlobalCodeMirrorEditorKey } from '@growi/editor';
+import { GlobalCodeMirrorEditorKey } from '@growi/editor';
+import { CodeMirrorEditorReadOnly } from '@growi/editor/dist/client';
 import { throttle } from 'throttle-debounce';
 
 import { useShouldExpandContent } from '~/client/services/layout';

+ 1 - 1
apps/app/src/components/PageEditor/Preview.module.scss

@@ -3,7 +3,7 @@
 .page-editor-preview-body :global {
   .wiki {
     max-width: 980px;
-    padding: 0px 15px;
+    padding: 0 15px;
     margin: 0 auto;
   }
 }

+ 2 - 1
apps/app/src/components/PageEditor/ScrollSyncHelper.tsx

@@ -1,6 +1,7 @@
 import { useCallback, type RefObject, useRef } from 'react';
 
-import { useCodeMirrorEditorIsolated, type GlobalCodeMirrorEditorKey } from '@growi/editor';
+import type { GlobalCodeMirrorEditorKey } from '@growi/editor';
+import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client';
 
 let defaultTop = 0;
 const padding = 5;

+ 2 - 1
apps/app/src/components/PageEditor/conflict.tsx

@@ -2,7 +2,8 @@ import { useCallback, useEffect } from 'react';
 
 import { Origin } from '@growi/core';
 import { useGlobalSocket } from '@growi/core/dist/swr';
-import { GlobalCodeMirrorEditorKey, useCodeMirrorEditorIsolated } from '@growi/editor';
+import { GlobalCodeMirrorEditorKey } from '@growi/editor';
+import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client';
 import { useTranslation } from 'react-i18next';
 
 import { useUpdateStateAfterSave } from '~/client/services/page-operation';

+ 1 - 2
apps/app/src/components/PageEditor/markdown-table-util-for-editor.ts

@@ -1,6 +1,5 @@
 import type { EditorView } from '@codemirror/view';
-
-import MarkdownTable from '~/client/models/MarkdownTable';
+import { MarkdownTable } from '@growi/editor';
 
 // https://regex101.com/r/7BN2fR/10
 const linePartOfTableRE = /^([^\r\n|]*)\|(([^\r\n|]*\|)+)$/;

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott