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..0ab452e1 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: 16.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 @@ -212,7 +213,7 @@ jobs: 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 +233,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 +274,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 +320,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 +340,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 +360,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 +371,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 +384,7 @@ jobs: needs: [release] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set Version Variables run: | diff --git a/README.md b/README.md index 6a9ab1e7..4263a36b 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) @@ -126,11 +129,28 @@ Support this project by becoming a sponsor. Your name will show up in the Contri Oleksii
(@idokka) - + @@ -151,12 +171,14 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - 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)) - Florian Moss ([@florianmoss](https://github.com/florianmoss)) - GoodCorporateCitizen ([@GoodCorporateCitizen](https://github.com/GoodCorporateCitizen)) - HeavenBay ([@HeavenBay](https://github.com/heavenbay)) +- HikaruEgashira ([@HikaruEgashira](https://github.com/HikaruEgashira)) - Ian Hyzy ([@ianhyzy](https://github.com/ianhyzy)) - Jaimyn Mayer ([@jabelone](https://github.com/jabelone)) - Jay Lee ([@polyglotm](https://github.com/polyglotm)) @@ -178,6 +200,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)) @@ -188,11 +211,13 @@ 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)) +- ameyrakheja ([@ameyrakheja](https://github.com/ameyrakheja)) - aniketpanjwani ([@aniketpanjwani](https://github.com/aniketpanjwani)) - aytaa ([@aytaa](https://github.com/aytaa)) - chaee ([@chaee](https://github.com/chaee)) - magicpotato ([@fortheday](https://github.com/fortheday)) - motoacs ([@motoacs](https://github.com/motoacs)) +- muzian666 ([@muzian666](https://github.com/muzian666)) - rburckner ([@rburckner](https://github.com/rburckner)) - scorpion ([@scorpion](https://github.com/scorpion)) - valantien ([@valantien](https://github.com/valantien)) @@ -343,6 +368,23 @@ Support this project by becoming a sponsor. Your logo will show up in the Contri + + + + + + + + + + + + + + + + +
@@ -357,14 +399,18 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re - 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 @@ -374,26 +420,34 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re - Hope - Ian - Imari Childress +- Iskander Callos +- Josh Stewart -- 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 - 张白驹 @@ -425,9 +479,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 85561381..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 @@ -144,7 +153,7 @@ //- ) //- v-divider.mt-3 - v-switch( + v-switch.mt-0( inset label='Comments' color='indigo' @@ -177,6 +186,76 @@ persistent-hint ) + v-card.mt-5.animated.fadeInUp.wait-p7s + v-toolbar(color='primary', dark, dense, flat) + v-toolbar-title.subtitle-1 {{$t('admin:general.editShortcuts')}} + v-card-text + v-switch.mt-0( + inset + :label='$t(`admin:general.editFab`)' + color='primary' + v-model='config.editFab' + persistent-hint + :hint='$t(`admin:general.editFabHint`)' + ) + v-divider + .overline.grey--text.pa-4 {{$t('admin:general.editMenuBar')}} + .px-3.pb-3 + v-switch.mt-0.ml-1( + inset + :label='$t(`admin:general.displayEditMenuBar`)' + color='primary' + v-model='config.editMenuBar' + persistent-hint + :hint='$t(`admin:general.displayEditMenuBarHint`)' + ) + v-switch.mt-4.ml-1( + v-if='config.editMenuBar' + inset + :label='$t(`admin:general.displayEditMenuBtn`)' + color='primary' + v-model='config.editMenuBtn' + persistent-hint + :hint='$t(`admin:general.displayEditMenuBtnHint`)' + ) + v-switch.mt-4.ml-1( + v-if='config.editMenuBar' + inset + :label='$t(`admin:general.displayEditMenuExternalBtn`)' + color='primary' + v-model='config.editMenuExternalBtn' + persistent-hint + :hint='$t(`admin:general.displayEditMenuExternalBtnHint`)' + ) + template(v-if='config.editMenuBar && config.editMenuExternalBtn') + v-divider + .overline.grey--text.pa-4 External Edit Button + .px-3.pb-3 + v-text-field( + outlined + :label='$t(`admin:general.editMenuExternalName`)' + v-model='config.editMenuExternalName' + prepend-icon='mdi-format-title' + :hint='$t(`admin:general.editMenuExternalNameHint`)' + persistent-hint + ) + v-text-field.mt-3( + outlined + :label='$t(`admin:general.editMenuExternalIcon`)' + v-model='config.editMenuExternalIcon' + prepend-icon='mdi-dice-5' + :hint='$t(`admin:general.editMenuExternalIconHint`)' + persistent-hint + ) + v-text-field.mt-3( + outlined + :label='$t(`admin:general.editMenuExternalUrl`)' + v-model='config.editMenuExternalUrl' + prepend-icon='mdi-near-me' + :hint='$t(`admin:general.editMenuExternalUrlHint`)' + persistent-hint + ) + component(:is='activeModal') @@ -210,13 +289,21 @@ export default { analyticsId: '', company: '', contentLicense: '', + footerOverride: '', logoUrl: '', featureAnalytics: false, featurePageRatings: false, featurePageComments: false, featurePersonalWikis: false, featureTinyPNG: false, - pageExtensions: '' + pageExtensions: '', + editFab: false, + editMenuBar: false, + editMenuBtn: false, + editMenuExternalBtn: false, + editMenuExternalName: '', + editMenuExternalIcon: '', + editMenuExternalUrl: '' }, metaRobots: [ { text: 'Index', value: 'index' }, @@ -231,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 [ @@ -269,11 +357,19 @@ export default { $analyticsId: String $company: String $contentLicense: String + $footerOverride: String $logoUrl: String $pageExtensions: String $featurePageRatings: Boolean $featurePageComments: Boolean $featurePersonalWikis: Boolean + $editFab: Boolean + $editMenuBar: Boolean + $editMenuBtn: Boolean + $editMenuExternalBtn: Boolean + $editMenuExternalName: String + $editMenuExternalIcon: String + $editMenuExternalUrl: String ) { site { updateConfig( @@ -285,11 +381,19 @@ export default { analyticsId: $analyticsId company: $company contentLicense: $contentLicense + footerOverride: $footerOverride logoUrl: $logoUrl pageExtensions: $pageExtensions featurePageRatings: $featurePageRatings featurePageComments: $featurePageComments featurePersonalWikis: $featurePersonalWikis + editFab: $editFab + editMenuBar: $editMenuBar + editMenuBtn: $editMenuBtn + editMenuExternalBtn: $editMenuExternalBtn + editMenuExternalName: $editMenuExternalName + editMenuExternalIcon: $editMenuExternalIcon + editMenuExternalUrl: $editMenuExternalUrl ) { responseResult { succeeded @@ -310,11 +414,19 @@ 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), featurePageComments: _.get(this.config, 'featurePageComments', false), - featurePersonalWikis: _.get(this.config, 'featurePersonalWikis', false) + featurePersonalWikis: _.get(this.config, 'featurePersonalWikis', false), + editFab: _.get(this.config, 'editFab', false), + editMenuBar: _.get(this.config, 'editMenuBar', false), + editMenuBtn: _.get(this.config, 'editMenuBtn', false), + editMenuExternalBtn: _.get(this.config, 'editMenuExternalBtn', false), + editMenuExternalName: _.get(this.config, 'editMenuExternalName', ''), + editMenuExternalIcon: _.get(this.config, 'editMenuExternalIcon', ''), + editMenuExternalUrl: _.get(this.config, 'editMenuExternalUrl', '') }, watchLoading (isLoading) { this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-update') @@ -328,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) @@ -363,11 +476,19 @@ export default { analyticsId company contentLicense + footerOverride logoUrl pageExtensions featurePageRatings featurePageComments featurePersonalWikis + editFab + editMenuBar + editMenuBtn + editMenuExternalBtn + editMenuExternalName + editMenuExternalIcon + editMenuExternalUrl } } } 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-theme.vue b/client/components/admin/admin-theme.vue index 83ec5fac..b5cd0e59 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) @@ -155,6 +151,7 @@ export default { theme: 'default', darkMode: false, iconset: '', + tocPosition: 'left', injectCSS: '', injectHead: '', injectBody: '' @@ -184,6 +181,13 @@ export default { width: 100 } ] + }, + tocPositions () { + return [ + { text: 'Left (default)', value: 'left' }, + { text: 'Right', value: 'right' }, + { text: 'Hidden', value: 'off' } + ] } }, watch: { @@ -209,6 +213,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/admin/admin-users-edit.vue b/client/components/admin/admin-users-edit.vue index 7b5acae6..a9e20070 100644 --- a/client/components/admin/admin-users-edit.vue +++ b/client/components/admin/admin-users-edit.vue @@ -499,9 +499,9 @@ export default { { text: '(GMT-03:00) Rothera', value: 'Antarctica/Rothera' }, { text: '(GMT-03:00) Salvador', value: 'America/Bahia' }, { text: '(GMT-03:00) Santiago', value: 'America/Santiago' }, + { text: '(GMT-03:00) Sao Paulo', value: 'America/Sao_Paulo' }, { text: '(GMT-03:00) Stanley', value: 'Atlantic/Stanley' }, { text: '(GMT-02:00) Noronha', value: 'America/Noronha' }, - { text: '(GMT-02:00) Sao Paulo', value: 'America/Sao_Paulo' }, { text: '(GMT-02:00) South Georgia', value: 'Atlantic/South_Georgia' }, { text: '(GMT-01:00) Azores', value: 'Atlantic/Azores' }, { text: '(GMT-01:00) Cape Verde', value: 'Atlantic/Cape_Verde' }, 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..04b5c6aa 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,11 +195,11 @@ 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 mdDecorate from 'markdown-it-decorate' import mdEmoji from 'markdown-it-emoji' import mdTaskLists from 'markdown-it-task-lists' import mdExpandTabs from 'markdown-it-expand-tabs' @@ -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/profile/profile.vue b/client/components/profile/profile.vue index 918cb6d3..345476d2 100644 --- a/client/components/profile/profile.vue +++ b/client/components/profile/profile.vue @@ -469,9 +469,9 @@ export default { { text: '(GMT-03:00) Rothera', value: 'Antarctica/Rothera' }, { text: '(GMT-03:00) Salvador', value: 'America/Bahia' }, { text: '(GMT-03:00) Santiago', value: 'America/Santiago' }, + { text: '(GMT-03:00) Sao Paulo', value: 'America/Sao_Paulo' }, { text: '(GMT-03:00) Stanley', value: 'Atlantic/Stanley' }, { text: '(GMT-02:00) Noronha', value: 'America/Noronha' }, - { text: '(GMT-02:00) Sao Paulo', value: 'America/Sao_Paulo' }, { text: '(GMT-02:00) South Georgia', value: 'Atlantic/South_Georgia' }, { text: '(GMT-01:00) Azores', value: 'Atlantic/Azores' }, { text: '(GMT-01:00) Cape Verde', value: 'Atlantic/Cape_Verde' }, 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/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/scss/base/base.scss b/client/scss/base/base.scss index f06afeea..03224354 100644 --- a/client/scss/base/base.scss +++ b/client/scss/base/base.scss @@ -30,6 +30,12 @@ html { } } +@media only screen and (min-width:960px) { + .v-application .v-footer { + padding-left: 272px + } +} + #root .v-application { .overline { line-height: 1rem; 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/page.js b/client/store/page.js index 0a72798e..92979647 100644 --- a/client/store/page.js +++ b/client/store/page.js @@ -41,7 +41,16 @@ const state = { manage: false } }, - commentsCount: 0 + commentsCount: 0, + editShortcuts: { + editFab: false, + editMenuBar: false, + editMenuBtn: false, + editMenuExternalBtn: false, + editMenuExternalName: '', + editMenuExternalIcon: '', + editMenuExternalUrl: '' + } } export default { 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 @@