Ver Fonte

Merge branch 'support/apply-nextjs-2' of https://github.com/weseek/growi into support/intallerPage-next-layout

Shunm634-source há 3 anos atrás
pai
commit
41a5c3a33b
45 ficheiros alterados com 689 adições e 728 exclusões
  1. 0 4
      .vscode/launch.json
  2. 2 2
      package.json
  3. 0 1
      packages/app/docker/Dockerfile
  4. 6 0
      packages/app/jest.config.js
  5. 1 1
      packages/app/package.json
  6. 0 3
      packages/app/resource/locales/en_US/sandbox.md
  7. 0 3
      packages/app/resource/locales/ja_JP/sandbox.md
  8. 0 3
      packages/app/resource/locales/zh_CN/sandbox.md
  9. 18 16
      packages/app/src/components/Layout/AdminLayout.tsx
  10. 15 1
      packages/app/src/components/Layout/RawLayout.tsx
  11. 3 2
      packages/app/src/components/Page/RevisionRenderer.tsx
  12. 12 1
      packages/app/src/components/Theme/ThemeAntarctic.module.scss
  13. 9 0
      packages/app/src/components/Theme/ThemeAntarctic.tsx
  14. 12 1
      packages/app/src/components/Theme/ThemeChristmas.module.scss
  15. 9 0
      packages/app/src/components/Theme/ThemeChristmas.tsx
  16. 12 5
      packages/app/src/components/Theme/ThemeHalloween.module.scss
  17. 9 0
      packages/app/src/components/Theme/ThemeHalloween.tsx
  18. 13 2
      packages/app/src/components/Theme/ThemeHufflepuff.module.scss
  19. 13 0
      packages/app/src/components/Theme/ThemeHufflepuff.tsx
  20. 8 1
      packages/app/src/components/Theme/ThemeIsland.module.scss
  21. 9 0
      packages/app/src/components/Theme/ThemeIsland.tsx
  22. 13 1
      packages/app/src/components/Theme/ThemeSpring.module.scss
  23. 9 0
      packages/app/src/components/Theme/ThemeSpring.tsx
  24. 13 1
      packages/app/src/components/Theme/ThemeWood.module.scss
  25. 9 0
      packages/app/src/components/Theme/ThemeWood.tsx
  26. 34 0
      packages/app/src/components/Theme/utils/ThemeImageProvider.tsx
  27. 1 1
      packages/app/src/pages/[[...path]].page.tsx
  28. 27 0
      packages/app/src/services/renderer/rehype-plugins/relative-links-by-pukiwiki-like-linker.ts
  29. 25 8
      packages/app/src/services/renderer/rehype-plugins/relative-links.ts
  30. 80 0
      packages/app/src/services/renderer/remark-plugins/pukiwiki-like-linker.ts
  31. 7 1
      packages/app/src/services/renderer/renderer.ts
  32. 92 0
      packages/app/test/unit/services/renderer/pukiwiki-like-linker.test.ts
  33. 0 1
      packages/plugin-pukiwiki-like-linker/.eslintignore
  34. 0 1
      packages/plugin-pukiwiki-like-linker/.gitignore
  35. 0 36
      packages/plugin-pukiwiki-like-linker/README.md
  36. 0 29
      packages/plugin-pukiwiki-like-linker/package.json
  37. 0 6
      packages/plugin-pukiwiki-like-linker/src/client-entry.js
  38. 0 8
      packages/plugin-pukiwiki-like-linker/src/index.js
  39. 0 22
      packages/plugin-pukiwiki-like-linker/src/resource/js/util/PreProcessor/PukiwikiLikeLinker.js
  40. 0 11
      packages/plugin-pukiwiki-like-linker/tsconfig.base.json
  41. 0 16
      packages/plugin-pukiwiki-like-linker/tsconfig.build.cjs.json
  42. 0 18
      packages/plugin-pukiwiki-like-linker/tsconfig.build.esm.json
  43. 0 3
      packages/plugin-pukiwiki-like-linker/tsconfig.json
  44. 1 0
      tsconfig.base.json
  45. 227 519
      yarn.lock

+ 0 - 4
.vscode/launch.json

@@ -76,10 +76,6 @@
             "url": "webpack://_n_e/plugin-attachment-refs",
             "url": "webpack://_n_e/plugin-attachment-refs",
             "path": "${workspaceFolder}/packages/plugin-attachment-refs"
             "path": "${workspaceFolder}/packages/plugin-attachment-refs"
           },
           },
-          {
-            "url": "webpack://_n_e/plugin-pukiwiki-like-linker",
-            "path": "${workspaceFolder}/packages/plugin-pukiwiki-like-linker"
-          },
           {
           {
             "url": "webpack://_n_e/plugin-lsx",
             "url": "webpack://_n_e/plugin-lsx",
             "path": "${workspaceFolder}/packages/plugin-lsx"
             "path": "${workspaceFolder}/packages/plugin-lsx"

+ 2 - 2
package.json

@@ -66,7 +66,7 @@
     "eslint-plugin-jest": "^26.5.3",
     "eslint-plugin-jest": "^26.5.3",
     "eslint-plugin-react": "^7.30.1",
     "eslint-plugin-react": "^7.30.1",
     "eslint-plugin-react-hooks": "^4.6.0",
     "eslint-plugin-react-hooks": "^4.6.0",
-    "jest": "^27.0.6",
+    "jest": "^28.1.3",
     "jest-date-mock": "^1.0.8",
     "jest-date-mock": "^1.0.8",
     "jest-localstorage-mock": "^2.4.14",
     "jest-localstorage-mock": "^2.4.14",
     "lerna": "^4.0.0",
     "lerna": "^4.0.0",
@@ -81,7 +81,7 @@
     "shipjs": "^0.24.1",
     "shipjs": "^0.24.1",
     "stylelint": "^14.2.0",
     "stylelint": "^14.2.0",
     "stylelint-config-recess-order": "^3.0.0",
     "stylelint-config-recess-order": "^3.0.0",
-    "ts-jest": "^27.0.4",
+    "ts-jest": "^28.0.7",
     "ts-node": "^10.9.1",
     "ts-node": "^10.9.1",
     "tsconfig-paths": "^3.9.0",
     "tsconfig-paths": "^3.9.0",
     "typescript": "~4.7",
     "typescript": "~4.7",

+ 0 - 1
packages/app/docker/Dockerfile

@@ -101,7 +101,6 @@ COPY packages/core packages/core
 COPY packages/codemirror-textlint packages/codemirror-textlint
 COPY packages/codemirror-textlint packages/codemirror-textlint
 COPY packages/plugin-attachment-refs packages/plugin-attachment-refs
 COPY packages/plugin-attachment-refs packages/plugin-attachment-refs
 COPY packages/plugin-lsx packages/plugin-lsx
 COPY packages/plugin-lsx packages/plugin-lsx
-COPY packages/plugin-pukiwiki-like-linker packages/plugin-pukiwiki-like-linker
 COPY packages/slack packages/slack
 COPY packages/slack packages/slack
 COPY packages/ui packages/ui
 COPY packages/ui packages/ui
 
 

+ 6 - 0
packages/app/jest.config.js

@@ -20,6 +20,11 @@ module.exports = {
 
 
       preset: 'ts-jest/presets/js-with-ts',
       preset: 'ts-jest/presets/js-with-ts',
 
 
+      // transform ESM to CJS
+      transformIgnorePatterns: [
+        '/node_modules/(?!remark-gfm)/',
+      ],
+
       rootDir: '.',
       rootDir: '.',
       roots: ['<rootDir>'],
       roots: ['<rootDir>'],
       testMatch: ['<rootDir>/test/unit/**/*.test.ts', '<rootDir>/test/unit/**/*.test.js'],
       testMatch: ['<rootDir>/test/unit/**/*.test.ts', '<rootDir>/test/unit/**/*.test.js'],
@@ -29,6 +34,7 @@ module.exports = {
       // Automatically clear mock calls and instances between every test
       // Automatically clear mock calls and instances between every test
       clearMocks: true,
       clearMocks: true,
       moduleNameMapper: MODULE_NAME_MAPPING,
       moduleNameMapper: MODULE_NAME_MAPPING,
+
     },
     },
     {
     {
       displayName: 'server',
       displayName: 'server',

+ 1 - 1
packages/app/package.json

@@ -67,7 +67,6 @@
     "@growi/core": "^5.1.3-RC.0",
     "@growi/core": "^5.1.3-RC.0",
     "@growi/plugin-attachment-refs": "^5.1.3-RC.0",
     "@growi/plugin-attachment-refs": "^5.1.3-RC.0",
     "@growi/plugin-lsx": "^5.1.3-RC.0",
     "@growi/plugin-lsx": "^5.1.3-RC.0",
-    "@growi/plugin-pukiwiki-like-linker": "^5.1.3-RC.0",
     "@growi/slack": "^5.1.3-RC.0",
     "@growi/slack": "^5.1.3-RC.0",
     "@promster/express": "^7.0.2",
     "@promster/express": "^7.0.2",
     "@promster/server": "^7.0.4",
     "@promster/server": "^7.0.4",
@@ -169,6 +168,7 @@
     "remark-emoji": "^3.0.2",
     "remark-emoji": "^3.0.2",
     "remark-gfm": "^3.0.1",
     "remark-gfm": "^3.0.1",
     "remark-math": "^5.1.1",
     "remark-math": "^5.1.1",
+    "remark-wiki-link": "^1.0.4",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",
     "socket.io": "^4.2.0",
     "socket.io": "^4.2.0",
     "stream-to-promise": "^3.0.0",
     "stream-to-promise": "^3.0.0",

+ 0 - 3
packages/app/resource/locales/en_US/sandbox.md

@@ -245,9 +245,6 @@ You can create links using `[Display text](URL)`.
 
 
 ## Pukiwiki like linker
 ## Pukiwiki like linker
 
 
-(available by [weseek/growi-plugin-pukiwiki-like-linker
-](https://github.com/weseek/growi-plugin-pukiwiki-like-linker) )
-
 This is the most flexible linker.
 This is the most flexible linker.
 Both the page description and link address can be displayed on the page.
 Both the page description and link address can be displayed on the page.
 
 

+ 0 - 3
packages/app/resource/locales/ja_JP/sandbox.md

@@ -244,9 +244,6 @@ ___
 
 
 ## Pukiwiki like linker
 ## Pukiwiki like linker
 
 
-(available by [weseek/growi-plugin-pukiwiki-like-linker
-](https://github.com/weseek/growi-plugin-pukiwiki-like-linker) )
-
 最も柔軟な Linker です。
 最も柔軟な Linker です。
 記述中のページを基点とした相対リンクと、表示テキストに対するリンクを同時に実現できます。
 記述中のページを基点とした相対リンクと、表示テキストに対するリンクを同時に実現できます。
 
 

+ 0 - 3
packages/app/resource/locales/zh_CN/sandbox.md

@@ -245,9 +245,6 @@ You can create links using `[Display text](URL)`.
 
 
 ## Pukiwiki like linker
 ## Pukiwiki like linker
 
 
-(available by [weseek/growi-plugin-pukiwiki-like-linker
-](https://github.com/weseek/growi-plugin-pukiwiki-like-linker) )
-
 This is the most flexible linker.
 This is the most flexible linker.
 Both the page description and link address can be displayed on the page.
 Both the page description and link address can be displayed on the page.
 
 

+ 18 - 16
packages/app/src/components/Layout/AdminLayout.tsx

@@ -29,26 +29,28 @@ const AdminLayout = ({
   const SystemVersion = dynamic(() => import('../SystemVersion'), { ssr: false });
   const SystemVersion = dynamic(() => import('../SystemVersion'), { ssr: false });
 
 
   return (
   return (
-    <RawLayout title={title} className={`admin-page ${styles['admin-page']}`}>
-      <GrowiNavbar />
-
-      <header className="py-0">
-        <h1 className="title">{title}</h1>
-      </header>
-      <div id="main" className="main">
-        <div className="container-fluid">
-          <div className="row">
-            <div className="col-lg-3">
-              <AdminNavigation selected={selectedNavOpt} />
-            </div>
-            <div className="col-lg-9">
-              {children}
+    <RawLayout title={title}>
+      <div className={`admin-page ${styles['admin-page']}`}>
+        <GrowiNavbar />
+
+        <header className="py-0 position-relative">
+          <h1 className="title">{title}</h1>
+        </header>
+        <div id="main" className="main">
+          <div className="container-fluid">
+            <div className="row">
+              <div className="col-lg-3">
+                <AdminNavigation selected={selectedNavOpt} />
+              </div>
+              <div className="col-lg-9">
+                {children}
+              </div>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>
-      </div>
 
 
-      <SystemVersion />
+        <SystemVersion />
+      </div>
     </RawLayout>
     </RawLayout>
   );
   );
 };
 };

+ 15 - 1
packages/app/src/components/Layout/RawLayout.tsx

@@ -1,10 +1,14 @@
-import React, { ReactNode, useEffect, useState } from 'react';
+import React, {
+  ReactNode, useCallback, useEffect, useState,
+} from 'react';
 
 
 import Head from 'next/head';
 import Head from 'next/head';
+import Image from 'next/image';
 
 
 import { useGrowiTheme } from '~/stores/context';
 import { useGrowiTheme } from '~/stores/context';
 import { Themes, useNextThemes } from '~/stores/use-next-themes';
 import { Themes, useNextThemes } from '~/stores/use-next-themes';
 
 
+import { getBackgroundImageSrc } from '../Theme/utils/ThemeImageProvider';
 import { ThemeProvider } from '../Theme/utils/ThemeProvider';
 import { ThemeProvider } from '../Theme/utils/ThemeProvider';
 
 
 type Props = {
 type Props = {
@@ -25,12 +29,19 @@ export const RawLayout = ({ children, title, className }: Props): JSX.Element =>
   const { resolvedTheme } = useNextThemes();
   const { resolvedTheme } = useNextThemes();
 
 
   const [colorScheme, setColorScheme] = useState<Themes|undefined>(undefined);
   const [colorScheme, setColorScheme] = useState<Themes|undefined>(undefined);
+  const [backgroundImageSrc, setBackgroundImageSrc] = useState<string | undefined>(undefined);
 
 
   // set colorScheme in CSR
   // set colorScheme in CSR
   useEffect(() => {
   useEffect(() => {
     setColorScheme(resolvedTheme as Themes);
     setColorScheme(resolvedTheme as Themes);
   }, [resolvedTheme]);
   }, [resolvedTheme]);
 
 
+  // set background image
+  useEffect(() => {
+    const imgSrc = getBackgroundImageSrc(growiTheme, colorScheme);
+    setBackgroundImageSrc(imgSrc);
+  }, [growiTheme, colorScheme]);
+
   return (
   return (
     <>
     <>
       <Head>
       <Head>
@@ -40,6 +51,9 @@ export const RawLayout = ({ children, title, className }: Props): JSX.Element =>
       </Head>
       </Head>
       <ThemeProvider theme={growiTheme}>
       <ThemeProvider theme={growiTheme}>
         <div className={classNames.join(' ')} data-color-scheme={colorScheme}>
         <div className={classNames.join(' ')} data-color-scheme={colorScheme}>
+          {backgroundImageSrc != null && <div className="grw-bg-image-wrapper">
+            <Image className='grw-bg-image' alt='background-image' src={backgroundImageSrc} layout='fill' quality="100" />
+          </div>}
           {children}
           {children}
         </div>
         </div>
       </ThemeProvider>
       </ThemeProvider>

+ 3 - 2
packages/app/src/components/Page/RevisionRenderer.tsx

@@ -95,7 +95,7 @@ type Props = {
   additionalClassName?: string,
   additionalClassName?: string,
 }
 }
 
 
-const RevisionRenderer = (props: Props): JSX.Element => {
+const RevisionRenderer = React.memo((props: Props): JSX.Element => {
 
 
   const {
   const {
     rendererOptions, markdown, pagePath, highlightKeywords, additionalClassName,
     rendererOptions, markdown, pagePath, highlightKeywords, additionalClassName,
@@ -246,6 +246,7 @@ const RevisionRenderer = (props: Props): JSX.Element => {
   //   />
   //   />
   // );
   // );
 
 
-};
+});
+RevisionRenderer.displayName = 'RevisionRenderer';
 
 
 export default RevisionRenderer;
 export default RevisionRenderer;

+ 12 - 1
packages/app/src/components/Theme/ThemeAntarctic.module.scss

@@ -16,7 +16,6 @@
 
 
 .growi:not(.login-page) {
 .growi:not(.login-page) {
   // add background-image
   // add background-image
-  #page-wrapper,
   .page-editor-preview-container {
   .page-editor-preview-container {
     background-image: url('/images/themes/antarctic/bg.svg');
     background-image: url('/images/themes/antarctic/bg.svg');
     background-attachment: fixed;
     background-attachment: fixed;
@@ -34,6 +33,18 @@
   }
   }
 }
 }
 
 
+.theme :global {
+  .grw-bg-image-wrapper {
+    position: fixed;
+    width: 100%;
+    height: 100%;
+  }
+
+  .grw-bg-image {
+    object-fit: cover;
+  }
+}
+
 $themecolor: #000080;
 $themecolor: #000080;
 $themelight: #f0f8ff;
 $themelight: #f0f8ff;
 $accentcolor: #ffd700;
 $accentcolor: #ffd700;

+ 9 - 0
packages/app/src/components/Theme/ThemeAntarctic.tsx

@@ -1,7 +1,16 @@
+import { Themes } from '~/stores/use-next-themes';
+
 import { ThemeInjector } from './utils/ThemeInjector';
 import { ThemeInjector } from './utils/ThemeInjector';
 
 
 import styles from './ThemeAntarctic.module.scss';
 import styles from './ThemeAntarctic.module.scss';
 
 
+export const getBackgroundImageSrc = (colorScheme: Themes): string => {
+  switch (colorScheme) {
+    default:
+      return '/images/themes/antarctic/bg.svg';
+  }
+};
+
 const ThemeAntarctic = ({ children }: { children: JSX.Element }): JSX.Element => {
 const ThemeAntarctic = ({ children }: { children: JSX.Element }): JSX.Element => {
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
 };
 };

+ 12 - 1
packages/app/src/components/Theme/ThemeChristmas.module.scss

@@ -27,7 +27,6 @@ $color-link-wiki-hover: lighten($color-link-wiki, 15%);
 
 
 .growi:not(.login-page) {
 .growi:not(.login-page) {
   // add background-image
   // add background-image
-  #page-wrapper,
   .page-editor-preview-container {
   .page-editor-preview-container {
     background-image: url('/images/themes/christmas/christmas.jpg');
     background-image: url('/images/themes/christmas/christmas.jpg');
     background-attachment: fixed;
     background-attachment: fixed;
@@ -36,6 +35,18 @@ $color-link-wiki-hover: lighten($color-link-wiki, 15%);
   }
   }
 }
 }
 
 
+.theme :global {
+  .grw-bg-image-wrapper {
+    position: fixed;
+    width: 100%;
+    height: 100%;
+  }
+
+  .grw-bg-image {
+    object-fit: cover;
+  }
+}
+
 //== Light Mode
 //== Light Mode
 //
 //
 .theme :global {
 .theme :global {

+ 9 - 0
packages/app/src/components/Theme/ThemeChristmas.tsx

@@ -1,7 +1,16 @@
+import { Themes } from '~/stores/use-next-themes';
+
 import { ThemeInjector } from './utils/ThemeInjector';
 import { ThemeInjector } from './utils/ThemeInjector';
 
 
 import styles from './ThemeChristmas.module.scss';
 import styles from './ThemeChristmas.module.scss';
 
 
+export const getBackgroundImageSrc = (colorScheme: Themes): string => {
+  switch (colorScheme) {
+    default:
+      return '/images/themes/christmas/christmas.jpg';
+  }
+};
+
 const ThemeChristmas = ({ children }: { children: JSX.Element }): JSX.Element => {
 const ThemeChristmas = ({ children }: { children: JSX.Element }): JSX.Element => {
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
 };
 };

+ 12 - 5
packages/app/src/components/Theme/ThemeHalloween.module.scss

@@ -21,17 +21,24 @@ $light: lighten($secondary, 10%);
 // $dark: #;
 // $dark: #;
 
 
 .growi:not(.login-page) {
 .growi:not(.login-page) {
-  #wrapper > .navbar {
-    background-image: url(/images/themes/halloween/halloween-navbar.jpg);
-  }
-
   // add background-image
   // add background-image
-  #page-wrapper,
   .page-editor-preview-container {
   .page-editor-preview-container {
     background-image: url('/images/themes/halloween/halloween.jpg');
     background-image: url('/images/themes/halloween/halloween.jpg');
   }
   }
 }
 }
 
 
+.theme :global {
+  .grw-bg-image-wrapper {
+    position: fixed;
+    width: 100%;
+    height: 100%;
+  }
+
+  .grw-navbar {
+    background-image: url('/images/themes/halloween/halloween-navbar.jpg') !important;
+  }
+}
+
 //== Light Mode
 //== Light Mode
 //
 //
 .theme :global {
 .theme :global {

+ 9 - 0
packages/app/src/components/Theme/ThemeHalloween.tsx

@@ -1,7 +1,16 @@
+import { Themes } from '~/stores/use-next-themes';
+
 import { ThemeInjector } from './utils/ThemeInjector';
 import { ThemeInjector } from './utils/ThemeInjector';
 
 
 import styles from './ThemeHalloween.module.scss';
 import styles from './ThemeHalloween.module.scss';
 
 
+export const getBackgroundImageSrc = (colorScheme: Themes): string => {
+  switch (colorScheme) {
+    default:
+      return '/images/themes/halloween/halloween.jpg';
+  }
+};
+
 const ThemeHalloween = ({ children }: { children: JSX.Element }): JSX.Element => {
 const ThemeHalloween = ({ children }: { children: JSX.Element }): JSX.Element => {
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
 };
 };

+ 13 - 2
packages/app/src/components/Theme/ThemeHufflepuff.module.scss

@@ -18,6 +18,19 @@
 //   border-bottom: $accentcolor 4px solid;
 //   border-bottom: $accentcolor 4px solid;
 // }
 // }
 
 
+.theme :global {
+  .grw-bg-image-wrapper {
+    position: fixed;
+    width: 100%;
+    height: 100%;
+  }
+
+  .grw-bg-image {
+    object-fit: cover;
+    object-position: bottom;
+  }
+}
+
 //== Light Mode
 //== Light Mode
 //
 //
 .theme[data-color-scheme='light'] :global {
 .theme[data-color-scheme='light'] :global {
@@ -107,7 +120,6 @@
 
 
   .growi:not(.login-page) {
   .growi:not(.login-page) {
     // add background-image
     // add background-image
-    #page-wrapper,
     .page-editor-preview-container {
     .page-editor-preview-container {
       background-image: url('/images/themes/hufflepuff/badger-light3.png');
       background-image: url('/images/themes/hufflepuff/badger-light3.png');
       background-attachment: fixed;
       background-attachment: fixed;
@@ -275,7 +287,6 @@
 
 
   .growi:not(.login-page) {
   .growi:not(.login-page) {
     // add background-image
     // add background-image
-    #page-wrapper,
     .page-editor-preview-container {
     .page-editor-preview-container {
       background-image: url('/images/themes/hufflepuff/badger-dark.jpg');
       background-image: url('/images/themes/hufflepuff/badger-dark.jpg');
       background-attachment: fixed;
       background-attachment: fixed;

+ 13 - 0
packages/app/src/components/Theme/ThemeHufflepuff.tsx

@@ -1,7 +1,20 @@
+import { Themes } from '~/stores/use-next-themes';
+
 import { ThemeInjector } from './utils/ThemeInjector';
 import { ThemeInjector } from './utils/ThemeInjector';
 
 
 import styles from './ThemeHufflepuff.module.scss';
 import styles from './ThemeHufflepuff.module.scss';
 
 
+export const getBackgroundImageSrc = (colorScheme: Themes): string => {
+  switch (colorScheme) {
+    case Themes.light:
+      return '/images/themes/hufflepuff/badger-light3.png';
+    case Themes.dark:
+      return '/images/themes/hufflepuff/badger-dark.jpg';
+    default:
+      return '/images/themes/hufflepuff/badger-light3.png';
+  }
+};
+
 const ThemeHufflepuff = ({ children }: { children: JSX.Element }): JSX.Element => {
 const ThemeHufflepuff = ({ children }: { children: JSX.Element }): JSX.Element => {
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
 };
 };

+ 8 - 1
packages/app/src/components/Theme/ThemeIsland.module.scss

@@ -6,6 +6,14 @@
 $color-primary: #97cbc3;
 $color-primary: #97cbc3;
 $color-themelight: rgba(183, 226, 219, 1);
 $color-themelight: rgba(183, 226, 219, 1);
 
 
+.theme :global {
+  .grw-bg-image-wrapper {
+    position: fixed;
+    width: 100%;
+    height: 100%;
+  }
+}
+
 .theme :global {
 .theme :global {
   $primary: $color-primary;
   $primary: $color-primary;
   // Background colors
   // Background colors
@@ -89,7 +97,6 @@ $color-themelight: rgba(183, 226, 219, 1);
     background: lighten($color-themelight, 5%);
     background: lighten($color-themelight, 5%);
   }
   }
 
 
-  #wrapper > #page-wrapper,
   .page-editor-preview-container {
   .page-editor-preview-container {
     background-image: url('/images/themes/island/island.png');
     background-image: url('/images/themes/island/island.png');
     background-attachment: fixed;
     background-attachment: fixed;

+ 9 - 0
packages/app/src/components/Theme/ThemeIsland.tsx

@@ -1,7 +1,16 @@
+import { Themes } from '~/stores/use-next-themes';
+
 import { ThemeInjector } from './utils/ThemeInjector';
 import { ThemeInjector } from './utils/ThemeInjector';
 
 
 import styles from './ThemeIsland.module.scss';
 import styles from './ThemeIsland.module.scss';
 
 
+export const getBackgroundImageSrc = (colorScheme: Themes): string => {
+  switch (colorScheme) {
+    default:
+      return '/images/themes/island/island.png';
+  }
+};
+
 const ThemeIsland = ({ children }: { children: JSX.Element }): JSX.Element => {
 const ThemeIsland = ({ children }: { children: JSX.Element }): JSX.Element => {
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
 };
 };

+ 13 - 1
packages/app/src/components/Theme/ThemeSpring.module.scss

@@ -25,6 +25,19 @@ $accentcolor: #e08dbc;
   border-bottom: $accentcolor 4px solid;
   border-bottom: $accentcolor 4px solid;
 }
 }
 
 
+.theme :global {
+  .grw-bg-image-wrapper {
+    position: fixed;
+    width: 100%;
+    height: 100%;
+  }
+
+  .grw-bg-image {
+    object-fit: cover;
+    object-position: bottom;
+  }
+}
+
 //== Light Mode
 //== Light Mode
 //
 //
 .theme :global {
 .theme :global {
@@ -107,7 +120,6 @@ $accentcolor: #e08dbc;
 
 
   .growi:not(.login-page) {
   .growi:not(.login-page) {
     // add background-image
     // add background-image
-    #page-wrapper,
     .page-editor-preview-container {
     .page-editor-preview-container {
       background-image: url('/images/themes/spring/spring02.svg');
       background-image: url('/images/themes/spring/spring02.svg');
       background-attachment: fixed;
       background-attachment: fixed;

+ 9 - 0
packages/app/src/components/Theme/ThemeSpring.tsx

@@ -1,7 +1,16 @@
+import { Themes } from '~/stores/use-next-themes';
+
 import { ThemeInjector } from './utils/ThemeInjector';
 import { ThemeInjector } from './utils/ThemeInjector';
 
 
 import styles from './ThemeSpring.module.scss';
 import styles from './ThemeSpring.module.scss';
 
 
+export const getBackgroundImageSrc = (colorScheme: Themes): string => {
+  switch (colorScheme) {
+    default:
+      return '/images/themes/spring/spring02.svg';
+  }
+};
+
 const ThemeSpring = ({ children }: { children: JSX.Element }): JSX.Element => {
 const ThemeSpring = ({ children }: { children: JSX.Element }): JSX.Element => {
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
 };
 };

+ 13 - 1
packages/app/src/components/Theme/ThemeWood.module.scss

@@ -14,7 +14,6 @@
 
 
 .growi:not(.login-page) {
 .growi:not(.login-page) {
   // add background-image
   // add background-image
-  #page-wrapper,
   .page-editor-preview-container {
   .page-editor-preview-container {
     background-image: url('/images/themes/wood/wood.jpg');
     background-image: url('/images/themes/wood/wood.jpg');
     background-attachment: fixed;
     background-attachment: fixed;
@@ -35,6 +34,19 @@
 $themecolor: #b9b177;
 $themecolor: #b9b177;
 $themelight: #f5f3ee;
 $themelight: #f5f3ee;
 
 
+.theme :global {
+  .grw-bg-image-wrapper {
+    position: fixed;
+    width: 100%;
+    height: 100%;
+  }
+
+  .grw-bg-image {
+    object-fit: cover;
+    object-position: center center;
+  }
+}
+
 //== Light Mode
 //== Light Mode
 //
 //
 .theme :global {
 .theme :global {

+ 9 - 0
packages/app/src/components/Theme/ThemeWood.tsx

@@ -1,7 +1,16 @@
+import { Themes } from '~/stores/use-next-themes';
+
 import { ThemeInjector } from './utils/ThemeInjector';
 import { ThemeInjector } from './utils/ThemeInjector';
 
 
 import styles from './ThemeWood.module.scss';
 import styles from './ThemeWood.module.scss';
 
 
+export const getBackgroundImageSrc = (colorScheme: Themes): string => {
+  switch (colorScheme) {
+    default:
+      return '/images/themes/wood/wood.jpg';
+  }
+};
+
 const ThemeWood = ({ children }: { children: JSX.Element }): JSX.Element => {
 const ThemeWood = ({ children }: { children: JSX.Element }): JSX.Element => {
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
   return <ThemeInjector className={styles.theme}>{children}</ThemeInjector>;
 };
 };

+ 34 - 0
packages/app/src/components/Theme/utils/ThemeImageProvider.tsx

@@ -0,0 +1,34 @@
+import { GrowiThemes } from '~/interfaces/theme';
+import { Themes } from '~/stores/use-next-themes';
+
+import { getBackgroundImageSrc as getAntarcticBackgroundImageSrc } from '../ThemeAntarctic';
+import { getBackgroundImageSrc as getChristmasBackgroundImageSrc } from '../ThemeChristmas';
+import { getBackgroundImageSrc as getHalloweenBackgroundImageSrc } from '../ThemeHalloween';
+import { getBackgroundImageSrc as getHuffulePuffBackgroundImageSrc } from '../ThemeHufflepuff';
+import { getBackgroundImageSrc as getIslandBackgroundImageSrc } from '../ThemeIsland';
+import { getBackgroundImageSrc as getSpringBackgroundImageSrc } from '../ThemeSpring';
+import { getBackgroundImageSrc as getWoodBackgroundImageSrc } from '../ThemeWood';
+
+export const getBackgroundImageSrc = (theme: GrowiThemes | undefined, colorScheme: Themes | undefined): string | undefined => {
+  if (theme == null || colorScheme == null) {
+    return undefined;
+  }
+  switch (theme) {
+    case GrowiThemes.ANTARCTIC:
+      return getAntarcticBackgroundImageSrc(colorScheme);
+    case GrowiThemes.CHRISTMAS:
+      return getChristmasBackgroundImageSrc(colorScheme);
+    case GrowiThemes.HALLOWEEN:
+      return getHalloweenBackgroundImageSrc(colorScheme);
+    case GrowiThemes.ISLAND:
+      return getIslandBackgroundImageSrc(colorScheme);
+    case GrowiThemes.HUFFLEPUFF:
+      return getHuffulePuffBackgroundImageSrc(colorScheme);
+    case GrowiThemes.SPRING:
+      return getSpringBackgroundImageSrc(colorScheme);
+    case GrowiThemes.WOOD:
+      return getWoodBackgroundImageSrc(colorScheme);
+    default:
+      return undefined;
+  }
+};

+ 1 - 1
packages/app/src/pages/[[...path]].page.tsx

@@ -283,7 +283,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
       </Head>
       </Head>
       {/* <BasicLayout title={useCustomTitle(props, t('GROWI'))} className={classNames.join(' ')}> */}
       {/* <BasicLayout title={useCustomTitle(props, t('GROWI'))} className={classNames.join(' ')}> */}
       <BasicLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')} expandContainer={props.isContainerFluid}>
       <BasicLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')} expandContainer={props.isContainerFluid}>
-        <header className="py-0">
+        <header className="py-0 position-relative">
           <GrowiContextualSubNavigation isLinkSharingDisabled={props.disableLinkSharing} />
           <GrowiContextualSubNavigation isLinkSharingDisabled={props.disableLinkSharing} />
         </header>
         </header>
         <div className="d-edit-none">
         <div className="d-edit-none">

+ 27 - 0
packages/app/src/services/renderer/rehype-plugins/relative-links-by-pukiwiki-like-linker.ts

@@ -0,0 +1,27 @@
+import { pathUtils } from '@growi/core';
+import { selectAll } from 'hast-util-select';
+import { Plugin } from 'unified';
+
+import {
+  IAnchorsSelector, IHrefResolver, relativeLinks, RelativeLinksPluginParams,
+} from './relative-links';
+
+const customAnchorsSelector: IAnchorsSelector = (node) => {
+  return selectAll('a[href].pukiwiki-like-linker', node);
+};
+
+const customHrefResolver: IHrefResolver = (relativeHref, basePath) => {
+  // generate relative pathname
+  const baseUrl = new URL(pathUtils.addTrailingSlash(basePath), 'https://example.com');
+  const relativeUrl = new URL(relativeHref, baseUrl);
+
+  return relativeUrl.pathname;
+};
+
+export const relativeLinksByPukiwikiLikeLinker: Plugin<[RelativeLinksPluginParams]> = (options = {}) => {
+  return relativeLinks.bind(this)({
+    ...options,
+    anchorsSelector: customAnchorsSelector,
+    hrefResolver: customHrefResolver,
+  });
+};

+ 25 - 8
packages/app/src/services/renderer/rehype-plugins/relative-links.ts

@@ -1,19 +1,40 @@
-import { selectAll, HastNode } from 'hast-util-select';
+import { selectAll, HastNode, Element } from 'hast-util-select';
 import isAbsolute from 'is-absolute-url';
 import isAbsolute from 'is-absolute-url';
 import { Plugin } from 'unified';
 import { Plugin } from 'unified';
 
 
-type RelativeLinksPluginParams = {
+export type IAnchorsSelector = (node: HastNode) => Element[];
+export type IHrefResolver = (relativeHref: string, basePath: string) => string;
+
+const defaultAnchorsSelector: IAnchorsSelector = (node) => {
+  return selectAll('a[href]', node);
+};
+
+const defaultHrefResolver: IHrefResolver = (relativeHref, basePath) => {
+  // generate relative pathname
+  const baseUrl = new URL(basePath, 'https://example.com');
+  const relativeUrl = new URL(relativeHref, baseUrl);
+
+  return relativeUrl.pathname;
+};
+
+
+export type RelativeLinksPluginParams = {
   pagePath?: string,
   pagePath?: string,
+  anchorsSelector?: IAnchorsSelector,
+  hrefResolver?: IHrefResolver,
 }
 }
 
 
 export const relativeLinks: Plugin<[RelativeLinksPluginParams]> = (options = {}) => {
 export const relativeLinks: Plugin<[RelativeLinksPluginParams]> = (options = {}) => {
+  const anchorsSelector = options.anchorsSelector ?? defaultAnchorsSelector;
+  const hrefResolver = options.hrefResolver ?? defaultHrefResolver;
+
   return (tree) => {
   return (tree) => {
     if (options.pagePath == null) {
     if (options.pagePath == null) {
       return;
       return;
     }
     }
 
 
     const pagePath = options.pagePath;
     const pagePath = options.pagePath;
-    const anchors = selectAll('a[href]', tree as HastNode);
+    const anchors = anchorsSelector(tree as HastNode);
 
 
     anchors.forEach((anchor) => {
     anchors.forEach((anchor) => {
       if (anchor.properties == null) {
       if (anchor.properties == null) {
@@ -25,11 +46,7 @@ export const relativeLinks: Plugin<[RelativeLinksPluginParams]> = (options = {})
         return;
         return;
       }
       }
 
 
-      // generate relative pathname
-      const baseUrl = new URL(pagePath, 'https://example.com');
-      const relativeUrl = new URL(href, baseUrl);
-
-      anchor.properties.href = relativeUrl.pathname;
+      anchor.properties.href = hrefResolver(href, pagePath);
     });
     });
   };
   };
 };
 };

+ 80 - 0
packages/app/src/services/renderer/remark-plugins/pukiwiki-like-linker.ts

@@ -0,0 +1,80 @@
+import { fromMarkdown, toMarkdown } from 'mdast-util-wiki-link';
+import { syntax } from 'micromark-extension-wiki-link';
+import { Plugin } from 'unified';
+
+
+type FromMarkdownExtension = {
+  enter: {
+    wikiLink: (token: string) => void,
+  },
+  exit: {
+    wikiLinkTarget: (token: string) => void,
+    wikiLinkAlias: (token: string) => void,
+    wikiLink: (token: string) => void,
+  }
+}
+
+type FromMarkdownData = {
+  value: string | null,
+  data: {
+    alias: string | null,
+    hProperties: Record<string, unknown>,
+  }
+}
+
+function swapTargetAndAlias(fromMarkdownExtension: FromMarkdownExtension): FromMarkdownExtension {
+  return {
+    enter: fromMarkdownExtension.enter,
+    exit: {
+      wikiLinkTarget: fromMarkdownExtension.exit.wikiLinkTarget,
+      wikiLinkAlias: fromMarkdownExtension.exit.wikiLinkAlias,
+      wikiLink(token: string) {
+        const wikiLink: FromMarkdownData = this.stack[this.stack.length - 1];
+
+        // swap target and alias
+        //    The default Wiki Link behavior: [[${target}${aliasDivider}${alias}]]
+        //    After swapping:                 [[${alias}${aliasDivider}${target}]]
+        const target = wikiLink.value;
+        const alias = wikiLink.data.alias;
+        if (target != null && alias != null) {
+          wikiLink.value = alias;
+          wikiLink.data.alias = target;
+        }
+
+        // invoke original wikiLink method
+        const orgWikiLink = fromMarkdownExtension.exit.wikiLink.bind(this);
+        orgWikiLink(token);
+      },
+    },
+  };
+}
+
+/**
+ * Implemented with reference to https://github.com/landakram/remark-wiki-link/blob/master/src/index.js
+ */
+export const pukiwikiLikeLinker: Plugin = function() {
+  const data = this.data();
+
+  function add(field: string, value) {
+    if (data[field] != null) {
+      const array = data[field];
+      if (Array.isArray(array)) {
+        array.push(value);
+      }
+    }
+    else {
+      data[field] = [value];
+    }
+  }
+
+  add('micromarkExtensions', syntax({
+    aliasDivider: '>',
+  }));
+  add('fromMarkdownExtensions', swapTargetAndAlias(fromMarkdown({
+    wikiLinkClassName: 'pukiwiki-like-linker',
+    newClassName: ' ',
+    pageResolver: value => [value],
+    hrefTemplate: permalink => permalink,
+  })));
+  add('toMarkdownExtensions', toMarkdown({}));
+};

+ 7 - 1
packages/app/src/services/renderer/renderer.ts

@@ -17,6 +17,8 @@ import loggerFactory from '~/utils/logger';
 
 
 import { addClass } from './rehype-plugins/add-class';
 import { addClass } from './rehype-plugins/add-class';
 import { relativeLinks } from './rehype-plugins/relative-links';
 import { relativeLinks } from './rehype-plugins/relative-links';
+import { relativeLinksByPukiwikiLikeLinker } from './rehype-plugins/relative-links-by-pukiwiki-like-linker';
+import { pukiwikiLikeLinker } from './remark-plugins/pukiwiki-like-linker';
 
 
 // import CsvToTable from './PreProcessor/CsvToTable';
 // import CsvToTable from './PreProcessor/CsvToTable';
 // import EasyGrid from './PreProcessor/EasyGrid';
 // import EasyGrid from './PreProcessor/EasyGrid';
@@ -217,9 +219,13 @@ export type RendererOptions = Partial<ReactMarkdownOptions>;
 
 
 const generateCommonOptions = (pagePath: string|undefined, config: RendererConfig): RendererOptions => {
 const generateCommonOptions = (pagePath: string|undefined, config: RendererConfig): RendererOptions => {
   return {
   return {
-    remarkPlugins: [gfm],
+    remarkPlugins: [
+      gfm,
+      pukiwikiLikeLinker,
+    ],
     rehypePlugins: [
     rehypePlugins: [
       slug,
       slug,
+      [relativeLinksByPukiwikiLikeLinker, { pagePath }],
       [relativeLinks, { pagePath }],
       [relativeLinks, { pagePath }],
       raw,
       raw,
       [sanitize, {
       [sanitize, {

+ 92 - 0
packages/app/test/unit/services/renderer/pukiwiki-like-linker.test.ts

@@ -0,0 +1,92 @@
+import { HastNode, selectAll } from 'hast-util-select';
+import parse from 'remark-parse';
+import rehype from 'remark-rehype';
+import { unified } from 'unified';
+import { visit } from 'unist-util-visit';
+
+import { relativeLinksByPukiwikiLikeLinker } from '../../../../src/services/renderer/rehype-plugins/relative-links-by-pukiwiki-like-linker';
+import { pukiwikiLikeLinker } from '../../../../src/services/renderer/remark-plugins/pukiwiki-like-linker';
+
+describe('pukiwikiLikeLinker', () => {
+
+  /* eslint-disable indent */
+  describe.each`
+    input                                   | expectedHref                | expectedValue
+    ${'[[/page]]'}                          | ${'/page'}                  | ${'/page'}
+    ${'[[./page]]'}                         | ${'./page'}                 | ${'./page'}
+    ${'[[Title>./page]]'}                   | ${'./page'}                 | ${'Title'}
+    ${'[[Title>https://example.com]]'}      | ${'https://example.com'}    | ${'Title'}
+  `('should parse correctly', ({ input, expectedHref, expectedValue }) => {
+  /* eslint-enable indent */
+
+    test(`when the input is '${input}'`, () => {
+      // setup:
+      const processor = unified()
+        .use(parse)
+        .use(pukiwikiLikeLinker);
+
+      // when:
+      const ast = processor.parse(input);
+
+      expect(ast).not.toBeNull();
+
+      visit(ast, 'wikiLink', (node: any) => {
+        expect(node.data.alias).toEqual(expectedValue);
+        expect(node.data.permalink).toEqual(expectedHref);
+        expect(node.data.hName).toEqual('a');
+        expect(node.data.hProperties.className.startsWith('pukiwiki-like-linker')).toBeTruthy();
+        expect(node.data.hProperties.href).toEqual(expectedHref);
+        expect(node.data.hChildren[0].value).toEqual(expectedValue);
+      });
+
+    });
+  });
+
+});
+
+
+describe('relativeLinksByPukiwikiLikeLinker', () => {
+
+  /* eslint-disable indent */
+  describe.each`
+    input                                   | expectedHref                | expectedValue
+    ${'[[/page]]'}                          | ${'/page'}                  | ${'/page'}
+    ${'[[./page]]'}                         | ${'/user/admin/page'}       | ${'./page'}
+    ${'[[Title>./page]]'}                   | ${'/user/admin/page'}       | ${'Title'}
+    ${'[[Title>https://example.com]]'}      | ${'https://example.com'}    | ${'Title'}
+  `('should convert relative links correctly', ({ input, expectedHref, expectedValue }) => {
+  /* eslint-enable indent */
+
+    test(`when the input is '${input}'`, () => {
+      // setup:
+      const processor = unified()
+        .use(parse)
+        .use(pukiwikiLikeLinker)
+        .use(rehype)
+        .use(relativeLinksByPukiwikiLikeLinker, { pagePath: '/user/admin' });
+
+      // when:
+      const mdast = processor.parse(input);
+      const hast = processor.runSync(mdast);
+
+      expect(hast).not.toBeNull();
+      expect((hast as any).children[0].type).toEqual('element');
+
+      const anchors = selectAll('a', hast as HastNode);
+
+      expect(anchors.length).toEqual(1);
+
+      const anchor = anchors[0];
+
+      expect(anchor.tagName).toEqual('a');
+      expect((anchor.properties as any).className.startsWith('pukiwiki-like-linker')).toBeTruthy();
+      expect(anchor.properties?.href).toEqual(expectedHref);
+
+      expect(anchor.children[0]).not.toBeNull();
+      expect(anchor.children[0].type).toEqual('text');
+      expect(anchor.children[0].value).toEqual(expectedValue);
+
+    });
+  });
+
+});

+ 0 - 1
packages/plugin-pukiwiki-like-linker/.eslintignore

@@ -1 +0,0 @@
-/dist/**

+ 0 - 1
packages/plugin-pukiwiki-like-linker/.gitignore

@@ -1 +0,0 @@
-/dist

+ 0 - 36
packages/plugin-pukiwiki-like-linker/README.md

@@ -1,36 +0,0 @@
-# growi-plugin-pukiwiki-like-linker
-[GROWI][growi] Plugin to add PukiwikiLikeLinker
-
-Overview
-----------
-
-Add the feature to use `[[alias>./relative/path]]` expression in markdown.
-
-### Replacement examples
-
-When you write at `/Level1/Level2` page:
-
-```html
-<!-- Markdown -->
-[[./Level3]]
-<!-- HTML -->
-<a href="/Level1/Level2/Level3">./Level3</a>
-
-
-<!-- Markdown -->
-[[../AnotherLevel2]]
-<!-- HTML -->
-<a href="/Level1/AnotherLevel2">../AnotherLevel2</a>
-
-
-<!-- Markdown -->
-Level 3 page is [[here>./Level3]]
-<!-- HTML -->
-Level 3 page is <a href="/Level1/Level2/Level3">here</a>
-
-
-<!-- Markdown -->
-[[example.com>https://example.com/]]
-<!-- HTML -->
-<a href="https://example.com/">example.com</a>
-```

+ 0 - 29
packages/plugin-pukiwiki-like-linker/package.json

@@ -1,29 +0,0 @@
-{
-  "name": "@growi/plugin-pukiwiki-like-linker",
-  "version": "5.1.3-RC.0",
-  "description": "GROWI plugin to add PukiwikiLikeLinker",
-  "license": "MIT",
-  "keywords": [
-    "growi",
-    "growi-plugin"
-  ],
-  "main": "dist/cjs/index.js",
-  "module": "dist/esm/index.js",
-  "files": [
-    "dist"
-  ],
-  "scripts": {
-    "build": "run-p build:*",
-    "build:cjs": "tsc -p tsconfig.build.cjs.json && tsc-alias -p tsconfig.build.cjs.json",
-    "build:esm": "tsc -p tsconfig.build.esm.json && tsc-alias -p tsconfig.build.esm.json",
-    "clean": "npx -y shx rm -rf dist",
-    "lint:js": "eslint **/*.{js,ts}",
-    "lint": "run-p lint:*",
-    "test": ""
-  },
-  "devDependencies": {
-    "browser-bunyan": "^1.6.3",
-    "eslint-plugin-regex": "^1.8.0",
-    "tsc-alias": "^1.2.9"
-  }
-}

+ 0 - 6
packages/plugin-pukiwiki-like-linker/src/client-entry.js

@@ -1,6 +0,0 @@
-import PukiwikiLikeLinker from './resource/js/util/PreProcessor/PukiwikiLikeLinker';
-
-export default () => {
-  // add preprocessor to head of array
-  window.growiRenderer.preProcessors.unshift(new PukiwikiLikeLinker());
-};

+ 0 - 8
packages/plugin-pukiwiki-like-linker/src/index.js

@@ -1,8 +0,0 @@
-module.exports = {
-  pluginSchemaVersion: 4,
-  serverEntries: [
-  ],
-  clientEntries: [
-    'src/client-entry.js',
-  ],
-};

+ 0 - 22
packages/plugin-pukiwiki-like-linker/src/resource/js/util/PreProcessor/PukiwikiLikeLinker.js

@@ -1,22 +0,0 @@
-const path = require('path');
-
-export default class PukiwikiLikeLinker {
-
-  process(markdown, context) {
-    const currentPath = context.pagePath ?? context.currentPathname;
-
-    return markdown
-      // see: https://regex101.com/r/k2dwz3/3
-      .replace(/\[\[(([^(\]\])]+)>)?(.+?)\]\]/g, (all, group1, group2, group3) => {
-        // create url
-        // use 'group3' as is if starts from 'http(s)', otherwise join to currentPath
-        const url = (group3.match(/^(\/|https?:\/\/)/)) ? group3 : path.join(currentPath, group3);
-        // determine alias string
-        // if 'group2' is undefined, use group3
-        const alias = group2 || group3;
-
-        return `<a href="${url}">${alias}</a>`;
-      });
-  }
-
-}

+ 0 - 11
packages/plugin-pukiwiki-like-linker/tsconfig.base.json

@@ -1,11 +0,0 @@
-{
-  "extends": "../../tsconfig.base.json",
-  "compilerOptions": {
-  },
-  "include": [
-    "src"
-  ],
-  "exclude": [
-    "src/test"
-  ]
-}

+ 0 - 16
packages/plugin-pukiwiki-like-linker/tsconfig.build.cjs.json

@@ -1,16 +0,0 @@
-{
-  "extends": "./tsconfig.base.json",
-  "compilerOptions": {
-    "rootDir": "./src",
-    "outDir": "dist/cjs",
-    "declaration": true,
-    "noResolve": false,
-    "preserveConstEnums": true,
-    "sourceMap": false,
-    "noEmit": false,
-
-    "baseUrl": ".",
-    "paths": {
-    }
-  }
-}

+ 0 - 18
packages/plugin-pukiwiki-like-linker/tsconfig.build.esm.json

@@ -1,18 +0,0 @@
-{
-  "extends": "./tsconfig.base.json",
-  "compilerOptions": {
-    "module": "esnext",
-
-    "rootDir": "./src",
-    "outDir": "dist/esm",
-    "declaration": true,
-    "noResolve": false,
-    "preserveConstEnums": true,
-    "sourceMap": false,
-    "noEmit": false,
-
-    "baseUrl": ".",
-    "paths": {
-    }
-  }
-}

+ 0 - 3
packages/plugin-pukiwiki-like-linker/tsconfig.json

@@ -1,3 +0,0 @@
-{
-  "extends": "../../tsconfig.base.json"
-}

+ 1 - 0
tsconfig.base.json

@@ -14,6 +14,7 @@
     /* Strict Type-Checking Options */
     /* Strict Type-Checking Options */
     // "strict": true,
     // "strict": true,
     "strictNullChecks": true,
     "strictNullChecks": true,
+    "strictBindCallApply": true,
     "noImplicitAny": false,
     "noImplicitAny": false,
     "noImplicitOverride": true,
     "noImplicitOverride": true,
 
 

Diff do ficheiro suprimidas por serem muito extensas
+ 227 - 519
yarn.lock


Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff