diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 3b4b7ae9..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,12 +0,0 @@ - - -### Actual behavior - -### Expected behavior - -### Steps to reproduce the behavior - - - - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 680ec362..90c15174 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,9 +3,6 @@ contact_links: - name: Help / Questions url: https://github.com/Requarks/wiki/discussions/categories/help-questions about: Ask the community for help on using or setting up Wiki.js - - name: Report a Security Issue - url: https://github.com/Requarks/wiki/security/policy - about: Privately report security issues so they can be addressed quickly. - name: Errors / Bug Reports url: https://github.com/Requarks/wiki/discussions/categories/error-bug-report about: Create a discussion around the bug / error you're getting. If validated, a proper GitHub issue will be created so that it can be worked on. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d38dea8e..19b3a7d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: packages: write steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set Build Variables run: | @@ -42,20 +42,20 @@ jobs: cat package.json - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v2.1.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker images - uses: docker/build-push-action@v2.9.0 + uses: docker/build-push-action@v4.0.0 with: context: . file: dev/build/Dockerfile @@ -77,7 +77,7 @@ jobs: find _dist/wiki/ -printf "%P\n" | tar -czf wiki-js.tar.gz --no-recursion -C _dist/wiki/ -T - - name: Upload a Build Artifact - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v3.1.2 with: name: drop path: wiki-js.tar.gz @@ -92,7 +92,7 @@ jobs: dbtype: [postgres, mysql, mariadb, mssql, sqlite] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set Test Variables run: | @@ -129,7 +129,7 @@ jobs: docker: armv7 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set Version Variables run: | @@ -142,26 +142,26 @@ jobs: fi - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2.1.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2.4.0 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v2.1.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Download a Build Artifact - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v3.0.2 with: name: drop path: drop @@ -172,11 +172,12 @@ jobs: tar -xzf $GITHUB_WORKSPACE/drop/wiki-js.tar.gz -C $GITHUB_WORKSPACE/build --exclude=node_modules - name: Build and push Docker images - uses: docker/build-push-action@v2.9.0 + uses: docker/build-push-action@v4.0.0 with: context: . file: dev/build-arm/Dockerfile platforms: ${{ matrix.platform }} + provenance: false push: true tags: | requarks/wiki:canary-${{ matrix.docker }}-${{ env.REL_VERSION_STRICT }} @@ -189,12 +190,12 @@ jobs: steps: - name: Setup Node.js environment - uses: actions/setup-node@v2.5.1 + uses: actions/setup-node@v3.6.0 with: - node-version: 12.x + node-version: 18.x - name: Download a Build Artifact - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v3.0.2 with: name: drop path: drop @@ -202,17 +203,25 @@ jobs: - name: Extract Build run: | mkdir -p win - tar -xzf $env:GITHUB_WORKSPACE\drop\wiki-js.tar.gz -C $env:GITHUB_WORKSPACE\win --exclude=node_modules + tar -xzf $env:GITHUB_WORKSPACE\drop\wiki-js.tar.gz -C $env:GITHUB_WORKSPACE\win + Copy-Item win\node_modules\extract-files\package.json patch-extractfile.json -Force + Remove-Item -Path win\node_modules -Force -Recurse - name: Install Dependencies - run: yarn --production --frozen-lockfile --non-interactive + run: | + yarn --production --frozen-lockfile --non-interactive + yarn patch-package working-directory: win + - name: Fix patched packages + run: | + Copy-Item patch-extractfile.json win\node_modules\extract-files\package.json -Force + - name: Create Bundle run: tar -czf wiki-js-windows.tar.gz -C $env:GITHUB_WORKSPACE\win . - name: Upload a Build Artifact - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v3.1.2 with: name: drop-win path: wiki-js-windows.tar.gz @@ -232,13 +241,13 @@ jobs: echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v2.1.0 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -273,13 +282,13 @@ jobs: echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v2.1.0 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -319,13 +328,13 @@ jobs: docker manifest push -p ghcr.io/requarks/wiki:latest - name: Download Linux Build - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v3.0.2 with: name: drop path: drop - name: Download Windows Build - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v3.0.2 with: name: drop-win path: drop-win @@ -339,15 +348,16 @@ jobs: writeToFile: false - name: Update GitHub Release - uses: ncipollo/release-action@v1 + uses: ncipollo/release-action@v1.12.0 with: allowUpdates: true draft: false + makeLatest: true name: ${{ github.ref_name }} body: ${{ steps.changelog.outputs.changes }} token: ${{ github.token }} artifacts: 'drop/wiki-js.tar.gz,drop-win/wiki-js-windows.tar.gz' - + - name: Notify Slack Releases Channel uses: slackapi/slack-github-action@v1.18.0 with: @@ -358,7 +368,7 @@ jobs: env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - + - name: Notify Telegram Channel uses: appleboy/telegram-action@v0.1.1 with: @@ -369,7 +379,7 @@ jobs: message: | Wiki.js *${{ github.ref_name }}* has been released! See [release notes](https://github.com/requarks/wiki/releases) for details. - + - name: Notify Discord Channel uses: sebastianpopp/discord-action@v1.0 with: @@ -382,7 +392,7 @@ jobs: needs: [release] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set Version Variables run: | diff --git a/.nvmrc b/.nvmrc index 0c6886ca..860cc500 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v12.16.3 +v18.17.1 diff --git a/README.md b/README.md index b2cb4690..40fac120 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@
-Wiki.js + + + Wiki.js + [![Release](https://img.shields.io/github/release/Requarks/wiki.svg?style=flat&maxAge=3600)](https://github.com/Requarks/wiki/releases) [![License](https://img.shields.io/badge/license-AGPLv3-blue.svg?style=flat)](https://github.com/requarks/wiki/blob/master/LICENSE) @@ -10,8 +13,7 @@ [![Build + Publish](https://github.com/Requarks/wiki/actions/workflows/build.yml/badge.svg)](https://github.com/Requarks/wiki/actions/workflows/build.yml) [![Huntr](https://img.shields.io/badge/security%20bounty-disclose-brightgreen.svg?style=flat&logo=cachet&logoColor=white)](https://huntr.dev/bounties/disclose) [![GitHub Sponsors](https://img.shields.io/github/sponsors/ngpixel?logo=github&color=ea4aaa)](https://github.com/users/NGPixel/sponsorship) -[![Open Collective backers and sponsors](https://img.shields.io/opencollective/all/wikijs?label=backers&color=218bff&logo=opencollective&logoColor=white)](https://opencollective.com/wikijs) -[![Subscribe to Newsletter](https://img.shields.io/badge/newsletter-subscribe-yellow.svg?style=flat&logo=mailchimp&logoColor=white)](https://blog.js.wiki/subscribe) +[![Open Collective backers and sponsors](https://img.shields.io/opencollective/all/wikijs?label=backers&color=218bff&logo=opencollective&logoColor=white)](https://opencollective.com/wikijs) [![Chat on Slack](https://img.shields.io/badge/slack-requarks-CC2B5E.svg?style=flat&logo=slack)](https://wiki.requarks.io/slack) [![Follow on Twitter](https://img.shields.io/badge/twitter-%40requarks-blue.svg?style=flat&logo=twitter&logoColor=white)](https://twitter.com/requarks) [![Follow on Telegram](https://img.shields.io/badge/telegram-%40wiki__js-blue.svg?style=flat&logo=telegram)](https://t.me/wiki_js) @@ -82,11 +84,6 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - - - - - @@ -96,6 +93,11 @@ Support this project by becoming a sponsor. Your name will show up in the Contri + + + + - - - + + + + + + + + +
+ + + + Alexander Casassovici
(@alexksso) @@ -116,6 +118,13 @@ Support this project by becoming a sponsor. Your name will show up in the Contri
+ + + +
Jay Daley
(@JayDaley) @@ -126,14 +135,22 @@ Support this project by becoming a sponsor. Your name will show up in the Contri Oleksii
(@idokka)
+ + + + + + + + + @@ -155,9 +172,11 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - Cloud Data Hosting LLC ([@CloudDataHostingLLC](https://github.com/CloudDataHostingLLC)) - Cole Manning ([@RVRX](https://github.com/RVRX)) - CrazyMarvin ([@CrazyMarvin](https://github.com/CrazyMarvin)) +- Daniel Horner ([@danhorner](https://github.com/danhorner)) - David Christian Holin ([@SirGibihm](https://github.com/SirGibihm)) - Dragan Espenschied ([@despens](https://github.com/despens)) - Elijah Zobenko ([@he110](https://github.com/he110)) +- Emerson-Perna ([@Emerson-Perna](https://github.com/Emerson-Perna)) - Ernie ([@iamernie](https://github.com/iamernie)) - Fabio Ferrari ([@devxops](https://github.com/devxops)) - Finsa S.p.A. ([@finsaspa](https://github.com/finsaspa)) @@ -173,12 +192,12 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - MaFarine ([@MaFarine](https://github.com/MaFarine)) - Marcilio Leite Neto ([@marclneto](https://github.com/marclneto)) - Mattias Johnson ([@mattiasJohnson](https://github.com/mattiasJohnson)) +- Max Ricketts-Uy ([@MaxRickettsUy](https://github.com/MaxRickettsUy)) +- Mickael Asseline ([@PAPAMICA](https://github.com/PAPAMICA)) - -- Max Ricketts-Uy ([@MaxRickettsUy](https://github.com/MaxRickettsUy)) -- Mickael Asseline ([@PAPAMICA](https://github.com/PAPAMICA)) + - Mitchell Rowton ([@mrowton](https://github.com/mrowton)) - M. Scott Ford ([@mscottford](https://github.com/mscottford)) - Nick Halase ([@nhalase](https://github.com/nhalase)) @@ -186,6 +205,7 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - Nina Reynolds ([@cutecycle](https://github.com/cutecycle)) - Noel Cower ([@nilium](https://github.com/nilium)) - Oleksandr Koltsov ([@crambo](https://github.com/crambo)) +- Phi Zeroth ([@phizeroth](https://github.com/phizeroth)) - Philipp Schmitt ([@pschmitt](https://github.com/pschmitt)) - Robert Lanzke ([@winkelement](https://github.com/winkelement)) - Ruizhe Li ([@liruizhe1995](https://github.com/liruizhe1995)) @@ -196,9 +216,14 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - Tyler Denman ([@tylerguy](https://github.com/tylerguy)) - Victor Bilgin ([@vbilgin](https://github.com/vbilgin)) - VMO Solutions ([@vmosolutions](https://github.com/vmosolutions)) +- YazMogg35 ([@YazMogg35](https://github.com/YazMogg35)) +- Yu Yongwoo ([@uyu423](https://github.com/uyu423)) +- ameyrakheja ([@ameyrakheja](https://github.com/ameyrakheja)) - aniketpanjwani ([@aniketpanjwani](https://github.com/aniketpanjwani)) - aytaa ([@aytaa](https://github.com/aytaa)) +- cesar ([@cesarnr21](https://github.com/cesarnr21)) - chaee ([@chaee](https://github.com/chaee)) +- lwileczek ([@lwileczek](https://github.com/lwileczek)) - magicpotato ([@fortheday](https://github.com/fortheday)) - motoacs ([@motoacs](https://github.com/motoacs)) - muzian666 ([@muzian666](https://github.com/muzian666)) @@ -352,6 +377,23 @@ Support this project by becoming a sponsor. Your logo will show up in the Contri
+ + + + + + + + + +
@@ -364,16 +406,21 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re
+- Aeternum - Al Romano - Alex Balabanov +- Alex Milanov - Alex Zen - Arti Zirk - Ave - Brandon Curtis +- Damien Hottelier +- Daniel T. Holtzclaw - Dave 'Sri' Seah - djagoo - dz - Douglas Lassance +- Ergoflix - Ernie Reid - Etienne - Flemis Jurgenheimer @@ -383,26 +430,34 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re - Hope - Ian - Imari Childress +- Iskander Callos -- Iskander Callos - Josh Stewart - Justin Dunsworth - Keir - Loïc CRAMPON - Ludgeir Ibanez +- Lyn Matten +- Mads Rosendahl - Mark Mansur - Matt Gedigian +- Mike Ditton - Nate Figz - Patryk +- Paul O'Fallon - Philipp Schürch - Tracey Duffy +- Quaxim - Richeir +- Sergio Navarro Fernández - Shad Narcher +- ShadowVoyd - SmartNET.works - Stepan Sokolovskyi +- Zach Crawford - Zach Maynard - 张白驹 @@ -434,9 +489,15 @@ This project exists thanks to all the people who contribute. [[Contribute]](http ![Icons8](https://static.requarks.io/logo/icons8-text-h40.png) [Icons8](https://icons8.com/) for providing access to their beautiful icon sets. +![Localazy](https://static.requarks.io/logo/localazy-h40.png) +[Localazy](https://localazy.com/) for providing access to their great localization service. + ![Lokalise](https://static.requarks.io/logo/lokalise-text-h40.png) [Lokalise](https://lokalise.com/) for providing access to their great localization tool. +![MacStadium](https://static.requarks.io/logo/macstadium-h40.png) +[MacStadium](https://www.macstadium.com) for providing access to their Mac hardware in the cloud. + ![Netlify](https://js.wiki/legacy/logo_netlify.png) [Netlify](https://www.netlify.com) for providing hosting for our website. diff --git a/client/components/admin.vue b/client/components/admin.vue index f6e3722a..1d0762f3 100644 --- a/client/components/admin.vue +++ b/client/components/admin.vue @@ -65,15 +65,6 @@ v-list-item(to='/comments') v-list-item-avatar(size='24', tile): v-icon mdi-comment-text-outline v-list-item-title {{ $t('admin:comments.title') }} - v-list-item(to='/editor', disabled) - v-list-item-avatar(size='24', tile): v-icon(color='grey lighten-2') mdi-playlist-edit - v-list-item-title {{ $t('admin:editor.title') }} - v-list-item(to='/extensions') - v-list-item-avatar(size='24', tile): v-icon mdi-chip - v-list-item-title {{ $t('admin:extensions.title') }} - v-list-item(to='/logging', disabled) - v-list-item-avatar(size='24', tile): v-icon(color='grey lighten-2') mdi-script-text-outline - v-list-item-title {{ $t('admin:logging.title') }} v-list-item(to='/rendering', color='primary') v-list-item-avatar(size='24', tile): v-icon mdi-cogs v-list-item-title {{ $t('admin:rendering.title') }} @@ -104,9 +95,6 @@ v-list-item(to='/utilities', color='primary', v-if='hasPermission(`manage:system`)') v-list-item-avatar(size='24', tile): v-icon mdi-wrench-outline v-list-item-title {{ $t('admin:utilities.title') }} - v-list-item(to='/webhooks', v-if='hasPermission(`manage:system`)', disabled) - v-list-item-avatar(size='24', tile): v-icon(color='grey lighten-2') mdi-webhook - v-list-item-title {{ $t('admin:webhooks.title') }} v-list-group( to='/dev' no-action diff --git a/client/components/admin/admin-contribute.vue b/client/components/admin/admin-contribute.vue index e13507fa..e3d85851 100644 --- a/client/components/admin/admin-contribute.vue +++ b/client/components/admin/admin-contribute.vue @@ -184,7 +184,7 @@ v-list-item-title Netlify v-list-item-subtitle Deploy modern static websites with Netlify. Get CDN, Continuous deployment, 1-click HTTPS, and all the services you need. v-list-item-action - v-btn(icon, href='https://wwwnetlify.com', target='_blank') + v-btn(icon, href='https://www.netlify.com', target='_blank') v-icon(color='grey') mdi-earth diff --git a/client/components/admin/admin-general.vue b/client/components/admin/admin-general.vue index 8804ee39..07596074 100644 --- a/client/components/admin/admin-general.vue +++ b/client/components/admin/admin-general.vue @@ -82,6 +82,15 @@ :return-object='false' :hint='$t(`admin:general.contentLicenseHint`)' persistent-hint + ) + v-text-field.mt-3( + outlined + :label='$t(`admin:general.footerOverride`)' + v-model='config.footerOverride' + prepend-icon='mdi-page-layout-footer' + append-icon='mdi-language-markdown' + persistent-hint + :hint='$t(`admin:general.footerOverrideHint`)' ) v-divider .overline.grey--text.pa-4 SEO @@ -280,6 +289,7 @@ export default { analyticsId: '', company: '', contentLicense: '', + footerOverride: '', logoUrl: '', featureAnalytics: false, featurePageRatings: false, @@ -308,6 +318,7 @@ export default { logoUrl: sync('site/logoUrl'), company: sync('site/company'), contentLicense: sync('site/contentLicense'), + footerOverride: sync('site/footerOverride'), activeModal: sync('editor/activeModal'), contentLicenses () { return [ @@ -346,6 +357,7 @@ export default { $analyticsId: String $company: String $contentLicense: String + $footerOverride: String $logoUrl: String $pageExtensions: String $featurePageRatings: Boolean @@ -369,6 +381,7 @@ export default { analyticsId: $analyticsId company: $company contentLicense: $contentLicense + footerOverride: $footerOverride logoUrl: $logoUrl pageExtensions: $pageExtensions featurePageRatings: $featurePageRatings @@ -401,6 +414,7 @@ export default { analyticsId: _.get(this.config, 'analyticsId', ''), company: _.get(this.config, 'company', ''), contentLicense: _.get(this.config, 'contentLicense', ''), + footerOverride: _.get(this.config, 'footerOverride', ''), logoUrl: _.get(this.config, 'logoUrl', ''), pageExtensions: _.get(this.config, 'pageExtensions', ''), featurePageRatings: _.get(this.config, 'featurePageRatings', false), @@ -426,6 +440,7 @@ export default { this.siteTitle = this.config.title this.company = this.config.company this.contentLicense = this.config.contentLicense + this.footerOverride = this.config.footerOverride this.logoUrl = this.config.logoUrl } catch (err) { this.$store.commit('pushGraphError', err) @@ -461,6 +476,7 @@ export default { analyticsId company contentLicense + footerOverride logoUrl pageExtensions featurePageRatings diff --git a/client/components/admin/admin-pages-visualize.vue b/client/components/admin/admin-pages-visualize.vue index 116b38a9..3c9b20eb 100644 --- a/client/components/admin/admin-pages-visualize.vue +++ b/client/components/admin/admin-pages-visualize.vue @@ -104,7 +104,7 @@ export default { const truncatePath = path => _.take(path.split('/'), depth).join('/') const descendantsByChild = Object.entries(_.groupBy(descendants, page => truncatePath(page.path))) - .map(([childPath, descendantsGroup]) => [getPage(childPath), descendantsGroup]) + .map(([childPath, descendantsGroup]) => [getPage(childPath), _.sortBy(descendantsGroup, child => child.path)]) .map(([child, descendantsGroup]) => [child, _.filter(descendantsGroup, d => d.path !== child.path)]) return { diff --git a/client/components/admin/admin-security.vue b/client/components/admin/admin-security.vue index 7a8d305b..8c062c52 100644 --- a/client/components/admin/admin-security.vue +++ b/client/components/admin/admin-security.vue @@ -265,7 +265,7 @@ export default { securityOpenRedirect: true, securityIframe: true, securityReferrerPolicy: true, - securityTrustProxy: true, + securityTrustProxy: false, securitySRI: true, securityHSTS: false, securityHSTSDuration: 0, diff --git a/client/components/admin/admin-theme.vue b/client/components/admin/admin-theme.vue index 802a7eed..a9e4d9be 100644 --- a/client/components/admin/admin-theme.vue +++ b/client/components/admin/admin-theme.vue @@ -55,20 +55,16 @@ v-card.mt-3.animated.fadeInUp.wait-p1s v-toolbar(color='primary', dark, dense, flat) v-toolbar-title.subtitle-1 {{$t(`admin:theme.options`)}} - v-spacer - v-chip(label, color='white', small).primary--text coming soon v-card-text v-select( - :items='[]' + :items='tocPositions' outlined prepend-icon='mdi-border-vertical' - v-model='config.iconset' + v-model='config.tocPosition' label='Table of Contents Position' persistent-hint hint='Select whether the table of contents is shown on the left, right or not at all.' - disabled ) - v-flex(lg6 xs12) //- v-card.animated.fadeInUp.wait-p2s //- v-toolbar(color='teal', dark, dense, flat) @@ -156,6 +152,7 @@ export default { theme: 'default', darkMode: false, iconset: '', + tocPosition: 'left', injectCSS: '', injectHead: '', injectBody: '' @@ -185,6 +182,13 @@ export default { width: 100 } ] + }, + tocPositions () { + return [ + { text: 'Left (default)', value: 'left' }, + { text: 'Right', value: 'right' }, + { text: 'Hidden', value: 'off' } + ] } }, watch: { @@ -210,6 +214,7 @@ export default { theme: this.config.theme, iconset: this.config.iconset, darkMode: this.darkMode, + tocPosition: this.config.tocPosition, injectCSS: this.config.injectCSS, injectHead: this.config.injectHead, injectBody: this.config.injectBody diff --git a/client/components/editor.vue b/client/components/editor.vue index 15311e9b..7cd577b1 100644 --- a/client/components/editor.vue +++ b/client/components/editor.vue @@ -77,6 +77,7 @@ export default { editorApi: () => import(/* webpackChunkName: "editor-api", webpackMode: "lazy" */ './editor/editor-api.vue'), editorCode: () => import(/* webpackChunkName: "editor-code", webpackMode: "lazy" */ './editor/editor-code.vue'), editorCkeditor: () => import(/* webpackChunkName: "editor-ckeditor", webpackMode: "lazy" */ './editor/editor-ckeditor.vue'), + editorAsciidoc: () => import(/* webpackChunkName: "editor-asciidoc", webpackMode: "lazy" */ './editor/editor-asciidoc.vue'), editorMarkdown: () => import(/* webpackChunkName: "editor-markdown", webpackMode: "lazy" */ './editor/editor-markdown.vue'), editorRedirect: () => import(/* webpackChunkName: "editor-redirect", webpackMode: "lazy" */ './editor/editor-redirect.vue'), editorModalEditorselect: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-editorselect.vue'), diff --git a/client/components/editor/markdown/fold.js b/client/components/editor/common/cmFold.js similarity index 92% rename from client/components/editor/markdown/fold.js rename to client/components/editor/common/cmFold.js index 1bc56ef5..52267303 100644 --- a/client/components/editor/markdown/fold.js +++ b/client/components/editor/common/cmFold.js @@ -7,7 +7,13 @@ const maxDepth = 100 const codeBlockStartMatch = /^`{3}[a-zA-Z0-9]+$/ const codeBlockEndMatch = /^`{3}$/ -CodeMirror.registerHelper('fold', 'markdown', function (cm, start) { +export default { + register(lang) { + CodeMirror.registerHelper('fold', lang, foldHandler) + } +} + +function foldHandler (cm, start) { const firstLine = cm.getLine(start.line) const lastLineNo = cm.lastLine() let end @@ -59,4 +65,4 @@ CodeMirror.registerHelper('fold', 'markdown', function (cm, start) { from: CodeMirror.Pos(start.line, firstLine.length), to: CodeMirror.Pos(end, cm.getLine(end).length) } -}) +} diff --git a/client/components/editor/editor-asciidoc.vue b/client/components/editor/editor-asciidoc.vue new file mode 100644 index 00000000..296b2414 --- /dev/null +++ b/client/components/editor/editor-asciidoc.vue @@ -0,0 +1,707 @@ + + + + + diff --git a/client/components/editor/editor-markdown.vue b/client/components/editor/editor-markdown.vue index 6134524d..4ca6e192 100644 --- a/client/components/editor/editor-markdown.vue +++ b/client/components/editor/editor-markdown.vue @@ -124,44 +124,19 @@ span {{$t('editor:markup.insertAssets')}} v-tooltip(right, color='teal') template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p2s(icon, tile, v-on='on', dark, disabled, @click='toggleModal(`editorModalBlocks`)').mx-0 - v-icon(:color='activeModal === `editorModalBlocks` ? `teal` : ``') mdi-view-dashboard-outline - span {{$t('editor:markup.insertBlock')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p3s(icon, tile, v-on='on', dark, disabled).mx-0 - v-icon mdi-code-braces - span {{$t('editor:markup.insertCodeBlock')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p4s(icon, tile, v-on='on', dark, disabled).mx-0 - v-icon mdi-movie - span {{$t('editor:markup.insertVideoAudio')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p5s(icon, tile, v-on='on', dark, @click='toggleModal(`editorModalDrawio`)').mx-0 + v-btn.mt-3.animated.fadeInLeft.wait-p2s(icon, tile, v-on='on', dark, @click='toggleModal(`editorModalDrawio`)').mx-0 v-icon mdi-chart-multiline span {{$t('editor:markup.insertDiagram')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p6s(icon, tile, v-on='on', dark, disabled).mx-0 - v-icon mdi-function-variant - span {{$t('editor:markup.insertMathExpression')}} - v-tooltip(right, color='teal') - template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p7s(icon, tile, v-on='on', dark, disabled).mx-0 - v-icon mdi-table-plus - span {{$t('editor:markup.tableHelper')}} template(v-if='$vuetify.breakpoint.mdAndUp') v-spacer v-tooltip(right, color='teal') template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p8s(icon, tile, v-on='on', dark, @click='toggleFullscreen').mx-0 + v-btn.mt-3.animated.fadeInLeft.wait-p3s(icon, tile, v-on='on', dark, @click='toggleFullscreen').mx-0 v-icon mdi-arrow-expand-all span {{$t('editor:markup.distractionFreeMode')}} v-tooltip(right, color='teal') template(v-slot:activator='{ on }') - v-btn.mt-3.animated.fadeInLeft.wait-p9s(icon, tile, v-on='on', dark, @click='toggleHelp').mx-0 + v-btn.mt-3.animated.fadeInLeft.wait-p4s(icon, tile, v-on='on', dark, @click='toggleHelp').mx-0 v-icon(:color='helpShown ? `teal` : ``') mdi-help-circle span {{$t('editor:markup.markdownFormattingHelp')}} .editor-markdown-editor @@ -220,12 +195,12 @@ import 'codemirror/addon/hint/show-hint.js' import 'codemirror/addon/fold/foldcode.js' import 'codemirror/addon/fold/foldgutter.js' import 'codemirror/addon/fold/foldgutter.css' -import './markdown/fold' // Markdown-it import MarkdownIt from 'markdown-it' import mdAttrs from 'markdown-it-attrs' -import mdEmoji from 'markdown-it-emoji' +import mdDecorate from 'markdown-it-decorate' +import { full as mdEmoji } from 'markdown-it-emoji' import mdTaskLists from 'markdown-it-task-lists' import mdExpandTabs from 'markdown-it-expand-tabs' import mdAbbr from 'markdown-it-abbr' @@ -250,6 +225,7 @@ import mermaid from 'mermaid' // Helpers import katexHelper from './common/katex' import tabsetHelper from './markdown/tabset' +import cmFold from './common/cmFold' // ======================================== // INIT @@ -288,6 +264,7 @@ const md = new MarkdownIt({ .use(mdAttrs, { allowedAttributes: ['id', 'class', 'target'] }) + .use(mdDecorate) .use(underline) .use(mdEmoji) .use(mdTaskLists, { label: false, labelAfter: false }) @@ -335,6 +312,7 @@ md.renderer.rules.paragraph_open = injectLineNumbers md.renderer.rules.heading_open = injectLineNumbers md.renderer.rules.blockquote_open = injectLineNumbers +cmFold.register('markdown') // ======================================== // PLANTUML // ======================================== @@ -346,11 +324,12 @@ plantuml.init(md, {}) // KATEX // ======================================== +const macros = {} md.inline.ruler.after('escape', 'katex_inline', katexHelper.katexInline) md.renderer.rules.katex_inline = (tokens, idx) => { try { return katex.renderToString(tokens[idx].content, { - displayMode: false + displayMode: false, macros }) } catch (err) { console.warn(err) @@ -363,7 +342,7 @@ md.block.ruler.after('blockquote', 'katex_block', katexHelper.katexBlock, { md.renderer.rules.katex_block = (tokens, idx) => { try { return `

` + katex.renderToString(tokens[idx].content, { - displayMode: true + displayMode: true, macros }) + `

` } catch (err) { console.warn(err) diff --git a/client/components/editor/editor-modal-editorselect.vue b/client/components/editor/editor-modal-editorselect.vue index b5ce35f5..df2adf96 100644 --- a/client/components/editor/editor-modal-editorselect.vue +++ b/client/components/editor/editor-modal-editorselect.vue @@ -6,57 +6,7 @@ .subtitle-1.white--text {{$t('editor:select.title')}} v-container(grid-list-lg, fluid) v-layout(row, wrap, justify-center) - v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.primary.animated.fadeInUp( - hover - light - ripple - ) - v-card-text.text-center(@click='') - img(src='/_assets/svg/editor-icon-api.svg', alt='API', style='width: 36px; opacity: .5;') - .body-2.blue--text.mt-2.text--lighten-2 API Docs - .caption.blue--text.text--lighten-1 REST / GraphQL - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='primary' - opacity='.8' - ) - .body-2.mt-7 Coming Soon - v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.primary.animated.fadeInUp.wait-p1s( - hover - light - ripple - ) - v-card-text.text-center(@click='') - img(src='/_assets/svg/editor-icon-wikitext.svg', alt='WikiText', style='width: 36px; opacity: .5;') - .body-2.blue--text.mt-2.text--lighten-2 Blog - .caption.blue--text.text--lighten-1 Timeline of Posts - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='primary' - opacity='.8' - ) - .body-2.mt-7 Coming Soon - v-flex(xs4) - v-card.radius-7.animated.fadeInUp.wait-p2s( - hover - light - ripple - ) - v-card-text.text-center(@click='selectEditor("code")') - img(src='/_assets/svg/editor-icon-code.svg', alt='Code', style='width: 36px;') - .body-2.primary--text.mt-2 Code - .caption.grey--text Raw HTML - v-flex(xs4) + v-flex(xs6) v-card.radius-7.animated.fadeInUp.wait-p1s( hover light @@ -66,28 +16,8 @@ img(src='/_assets/svg/editor-icon-markdown.svg', alt='Markdown', style='width: 36px;') .body-2.primary--text.mt-2 Markdown .caption.grey--text Plain Text Formatting - v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.primary.animated.fadeInUp.wait-p2s( - hover - light - ripple - ) - v-card-text.text-center(@click='') - img(src='/_assets/svg/editor-icon-tabular.svg', alt='Tabular', style='width: 36px; opacity: .5;') - .body-2.blue--text.mt-2.text--lighten-2 Tabular - .caption.blue--text.text--lighten-1 Excel-like - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='primary' - opacity='.8' - ) - .body-2.mt-7 Coming Soon - v-flex(xs4) - v-card.radius-7.animated.fadeInUp.wait-p3s( + v-flex(xs6) + v-card.radius-7.animated.fadeInUp.wait-p2s( hover light ripple @@ -96,85 +26,36 @@ img(src='/_assets/svg/editor-icon-ckeditor.svg', alt='Visual Editor', style='width: 36px;') .body-2.mt-2.primary--text Visual Editor .caption.grey--text Rich-text WYSIWYG - //- .caption.blue--text.text--lighten-2 {{$t('editor:select.cannotChange')}} - - v-card.radius-7.mt-2(color='teal darken-3', dark) - v-card-text.text-center.py-4 - .subtitle-1.white--text {{$t('editor:select.customView')}} - v-container(grid-list-lg, fluid) - v-layout(row, wrap, justify-center) v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.animated.fadeInUp( - hover - light - ripple - ) - v-card-text.text-center(@click='fromTemplate') - img(src='/_assets/svg/icon-cube.svg', alt='From Template', style='width: 42px; opacity: .5;') - .body-2.mt-1.teal--text From Template - .caption.grey--text Use an existing page... + v-card.radius-7.animated.fadeInUp.wait-p3s( + hover + light + ripple + ) + v-card-text.text-center(@click='selectEditor("asciidoc")') + img(src='/_assets/svg/editor-icon-asciidoc.svg', alt='AsciiDoc', style='width: 36px;') + .body-2.primary--text.mt-2 AsciiDoc + .caption.grey--text Plain Text Formatting v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.teal.animated.fadeInUp.wait-p1s( - hover - light - ripple - ) - //- v-card-text.text-center(@click='selectEditor("redirect")') - v-card-text.text-center(@click='') - img(src='/_assets/svg/icon-route.svg', alt='Redirection', style='width: 42px; opacity: .5;') - .body-2.mt-1.teal--text.text--lighten-2 Redirection - .caption.teal--text.text--lighten-1 Redirect the user to... + v-card.radius-7.animated.fadeInUp.wait-p4s( + hover + light + ripple + ) + v-card-text.text-center(@click='selectEditor("code")') + img(src='/_assets/svg/editor-icon-code.svg', alt='Code', style='width: 36px;') + .body-2.primary--text.mt-2 Code + .caption.grey--text Raw HTML v-flex(xs4) - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.teal.animated.fadeInUp.wait-p2s( - hover - light - ripple - ) - v-card-text.text-center(@click='') - img(src='/_assets/svg/icon-sewing-patch.svg', alt='Code', style='width: 42px; opacity: .5;') - .body-2.mt-1.teal--text.text--lighten-2 Embed - .caption.teal--text.text--lighten-1 Include external pages - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='teal' - opacity='.8' - ) - .body-2.mt-7 Coming Soon - v-hover - template(v-slot:default='{ hover }') - v-card.radius-7.mt-2(color='indigo darken-3', dark) - v-toolbar(dense, flat, color='light-green darken-3') - v-spacer - .caption.mr-1 or convert from - v-btn.mx-1.animated.fadeInUp(depressed, color='light-green darken-2', @click='', disabled) - v-icon(left) mdi-alpha-a-circle - .body-2.text-none AsciiDoc - v-btn.mx-1.animated.fadeInUp.wait-p1s(depressed, color='light-green darken-2', @click='', disabled) - v-icon(left) mdi-alpha-c-circle - .body-2.text-none CREOLE - v-btn.mx-1.animated.fadeInUp.wait-p2s(depressed, color='light-green darken-2', @click='', disabled) - v-icon(left) mdi-alpha-t-circle - .body-2.text-none Textile - v-btn.mx-1.animated.fadeInUp.wait-p3s(depressed, color='light-green darken-2', @click='', disabled) - v-icon(left) mdi-alpha-w-circle - .body-2.text-none WikiText - v-spacer - v-fade-transition - v-overlay( - v-if='hover' - absolute - color='light-green darken-3' - opacity='.8' - ) - .body-2 Coming Soon + v-card.radius-7.animated.fadeInUp.wait-p5s( + hover + light + ripple + ) + v-card-text.text-center(@click='fromTemplate') + img(src='/_assets/svg/icon-cube.svg', alt='From Template', style='width: 42px; opacity: .5;') + .body-2.mt-1.teal--text From Template + .caption.grey--text Use an existing page... page-selector(mode='select', v-model='templateDialogIsShown', :open-handler='fromTemplateHandle', :path='path', :locale='locale', must-exist) diff --git a/client/components/source.vue b/client/components/source.vue index 6da6906a..2e6b8baa 100644 --- a/client/components/source.vue +++ b/client/components/source.vue @@ -20,8 +20,7 @@ v-card.grey.radius-7(flat, :class='$vuetify.theme.dark ? `darken-4` : `lighten-4`') v-card-text pre - code - slot + slot nav-footer notify diff --git a/client/components/tags.vue b/client/components/tags.vue index 3d717b38..56bc6cbb 100644 --- a/client/components/tags.vue +++ b/client/components/tags.vue @@ -98,6 +98,7 @@ :search='innerSearch' :loading='isLoading' :options.sync='pagination' + @page-count='pageTotal = $event' hide-default-footer ref='dude' ) @@ -183,6 +184,7 @@ export default { sortDesc: [false] }, pages: [], + pageTotal: 0, isLoading: true, scrollStyle: { vuescroll: {}, @@ -214,9 +216,6 @@ export default { tagsSelected () { return _.filter(this.tags, t => _.includes(this.selection, t.tag)) }, - pageTotal () { - return Math.ceil(this.pages.length / this.pagination.itemsPerPage) - }, orderByItems () { return [ { text: this.$t('tags:orderByField.creationDate'), value: 'createdAt' }, diff --git a/client/graph/admin/theme/theme-mutation-save.gql b/client/graph/admin/theme/theme-mutation-save.gql index 856442ce..86853eba 100644 --- a/client/graph/admin/theme/theme-mutation-save.gql +++ b/client/graph/admin/theme/theme-mutation-save.gql @@ -1,6 +1,6 @@ -mutation($theme: String!, $iconset: String!, $darkMode: Boolean!, $injectCSS: String, $injectHead: String, $injectBody: String) { +mutation($theme: String!, $iconset: String!, $darkMode: Boolean!, $tocPosition: String, $injectCSS: String, $injectHead: String, $injectBody: String) { theming { - setConfig(theme: $theme, iconset: $iconset, darkMode: $darkMode, injectCSS: $injectCSS, injectHead: $injectHead, injectBody: $injectBody) { + setConfig(theme: $theme, iconset: $iconset, darkMode: $darkMode, tocPosition: $tocPosition, injectCSS: $injectCSS, injectHead: $injectHead, injectBody: $injectBody) { responseResult { succeeded errorCode diff --git a/client/graph/admin/theme/theme-query-config.gql b/client/graph/admin/theme/theme-query-config.gql index 360cb2fa..5009fe06 100644 --- a/client/graph/admin/theme/theme-query-config.gql +++ b/client/graph/admin/theme/theme-query-config.gql @@ -4,6 +4,7 @@ query { theme iconset darkMode + tocPosition injectCSS injectHead injectBody diff --git a/client/static/svg/editor-icon-asciidoc.svg b/client/static/svg/editor-icon-asciidoc.svg new file mode 100644 index 00000000..d0c954b1 --- /dev/null +++ b/client/static/svg/editor-icon-asciidoc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/store/site.js b/client/store/site.js index e26830e3..0e3369de 100644 --- a/client/store/site.js +++ b/client/store/site.js @@ -5,7 +5,9 @@ import { make } from 'vuex-pathify' const state = { company: siteConfig.company, contentLicense: siteConfig.contentLicense, + footerOverride: siteConfig.footerOverride, dark: siteConfig.darkMode, + tocPosition: siteConfig.tocPosition, mascot: true, title: siteConfig.title, logoUrl: siteConfig.logoUrl, diff --git a/client/themes/default/components/nav-footer.vue b/client/themes/default/components/nav-footer.vue index 08e44fcd..93368daa 100644 --- a/client/themes/default/components/nav-footer.vue +++ b/client/themes/default/components/nav-footer.vue @@ -1,7 +1,9 @@