diff --git a/apps/settings/js/vue-0.js b/apps/settings/js/vue-0.js index fcde0ca0109b9cc6b58b956ae8b2bc4fbcdde43c..28f2200005a471311f3564ab67d306bb709fdbe2 100644 Binary files a/apps/settings/js/vue-0.js and b/apps/settings/js/vue-0.js differ diff --git a/apps/settings/js/vue-0.js.map b/apps/settings/js/vue-0.js.map index 62fbb2626040a9a38e2bebe07a963a4a8fba51e9..75c688c9b4a61ae6d0ce61d70f868d6f9af6cb71 100644 Binary files a/apps/settings/js/vue-0.js.map and b/apps/settings/js/vue-0.js.map differ diff --git a/apps/settings/js/vue-5.js b/apps/settings/js/vue-5.js index 6cbeee85c2f33c8fab66ddeca6d4b64fd37f26bb..720d67996797a754e47efb99663c155093de2549 100644 Binary files a/apps/settings/js/vue-5.js and b/apps/settings/js/vue-5.js differ diff --git a/apps/settings/js/vue-5.js.map b/apps/settings/js/vue-5.js.map index 64c961724e5f430c9c048291dd7b85051e438f93..fd1326a34ee30b7fa706d22f5eae60ef98c835fc 100644 Binary files a/apps/settings/js/vue-5.js.map and b/apps/settings/js/vue-5.js.map differ diff --git a/apps/settings/js/vue-6.js b/apps/settings/js/vue-6.js index 029a4c98051b3d70c3a31408049f70560414f9bb..e61347ba9aa1fc573db09a0d6407183323f11990 100644 Binary files a/apps/settings/js/vue-6.js and b/apps/settings/js/vue-6.js differ diff --git a/apps/settings/js/vue-6.js.map b/apps/settings/js/vue-6.js.map index 7ffe92acf4e04f96b7ef7cf53066c325b11087d6..69b317c20f75d743b448954c470a9a270c8ee8e3 100644 Binary files a/apps/settings/js/vue-6.js.map and b/apps/settings/js/vue-6.js.map differ diff --git a/apps/settings/js/vue-7.js b/apps/settings/js/vue-7.js index 54064b4f955daf46948160a8c699e046bf304106..891e9d1e649a744210049e8911be43650a0be161 100644 Binary files a/apps/settings/js/vue-7.js and b/apps/settings/js/vue-7.js differ diff --git a/apps/settings/js/vue-7.js.map b/apps/settings/js/vue-7.js.map index 1727dc9ae8ecc763c235c7dc14c07eda5d233832..b862fc91c55e02bab5af1f6f622cbb2df4815626 100644 Binary files a/apps/settings/js/vue-7.js.map and b/apps/settings/js/vue-7.js.map differ diff --git a/apps/settings/js/vue-8.js b/apps/settings/js/vue-8.js index 13ce0123f1acef8a5d1ef0491c127a2b678f0fdd..23d421d5fdca52b27bcd7d7bd4a69170c0ab61be 100644 Binary files a/apps/settings/js/vue-8.js and b/apps/settings/js/vue-8.js differ diff --git a/apps/settings/js/vue-8.js.map b/apps/settings/js/vue-8.js.map index b014a2007ba3672e4d3ab3c844d49fc6a383487b..9518a47ffa4e867485f8f748cb5a30d911aa4e1b 100644 Binary files a/apps/settings/js/vue-8.js.map and b/apps/settings/js/vue-8.js.map differ diff --git a/apps/settings/js/vue-settings-admin-security.js b/apps/settings/js/vue-settings-admin-security.js index d54953ea212c3eeef4ae2fdc663fde67e0518590..02ef0b717212f09ecc596050cd9196e556378266 100644 Binary files a/apps/settings/js/vue-settings-admin-security.js and b/apps/settings/js/vue-settings-admin-security.js differ diff --git a/apps/settings/js/vue-settings-admin-security.js.map b/apps/settings/js/vue-settings-admin-security.js.map index b69ee63802e08311bfc04c00e100ce9c25c95fd4..9156e8b4fe9242d202322d90225019162cc9f4f4 100644 Binary files a/apps/settings/js/vue-settings-admin-security.js.map and b/apps/settings/js/vue-settings-admin-security.js.map differ diff --git a/apps/settings/js/vue-settings-apps-users-management.js b/apps/settings/js/vue-settings-apps-users-management.js index a8525ee16e18349f03a568fb5601764bee832754..f403a44425b991bbc5958118578c7e2f6fd5a87e 100644 Binary files a/apps/settings/js/vue-settings-apps-users-management.js and b/apps/settings/js/vue-settings-apps-users-management.js differ diff --git a/apps/settings/js/vue-settings-apps-users-management.js.map b/apps/settings/js/vue-settings-apps-users-management.js.map index 9f7bdde46d4213d940438cbf10c479197d1c5652..534503e2cd80fdbf3df73624658eec82347907c9 100644 Binary files a/apps/settings/js/vue-settings-apps-users-management.js.map and b/apps/settings/js/vue-settings-apps-users-management.js.map differ diff --git a/apps/settings/js/vue-settings-personal-security.js b/apps/settings/js/vue-settings-personal-security.js index af6cf7741c7750137d5a320148cc7895127821f1..11847a435b1b38902475f8f688b44264dd4cccfe 100644 Binary files a/apps/settings/js/vue-settings-personal-security.js and b/apps/settings/js/vue-settings-personal-security.js differ diff --git a/apps/settings/js/vue-settings-personal-security.js.map b/apps/settings/js/vue-settings-personal-security.js.map index b99b3714e089fddaedb6b8ba31150b17f557ccc6..cb2ef4a1eb8c95a59949cfd1e0440e4b775e7e10 100644 Binary files a/apps/settings/js/vue-settings-personal-security.js.map and b/apps/settings/js/vue-settings-personal-security.js.map differ diff --git a/apps/settings/lib/Controller/AppSettingsController.php b/apps/settings/lib/Controller/AppSettingsController.php index 7dbbaca1a45409d4ddf468050750ad9355e1603b..4d22e90f6458fe5ad59b19a83edea246f97e30fa 100644 --- a/apps/settings/lib/Controller/AppSettingsController.php +++ b/apps/settings/lib/Controller/AppSettingsController.php @@ -250,6 +250,7 @@ class AppSettingsController extends Controller { $appstoreData = $appData['appstoreData']; $appData['screenshot'] = isset($appstoreData['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/' . base64_encode($appstoreData['screenshots'][0]['url']) : ''; $appData['category'] = $appstoreData['categories']; + $appData['releases'] = $appstoreData['releases']; } $newVersion = $this->installer->isUpdateAvailable($appData['id']); diff --git a/apps/settings/src/components/AppDetails.vue b/apps/settings/src/components/AppDetails.vue index 55519bf9f8054df9fced182b1b632a2130567b6e..d79f799fbb9e67425201f2da472d53a6b0eb7458 100644 --- a/apps/settings/src/components/AppDetails.vue +++ b/apps/settings/src/components/AppDetails.vue @@ -139,24 +139,23 @@ target="_blank" rel="noreferrer noopener">{{ t('settings', 'Developer documentation') }} ↗</a> </p> - - <div class="app-details__description" v-html="renderMarkdown" /> + <Markdown class="app-details__description" :text="app.description" /> </div> </template> <script> import { Multiselect } from '@nextcloud/vue' -import marked from 'marked' -import dompurify from 'dompurify' import AppManagement from '../mixins/AppManagement' import PrefixMixin from './PrefixMixin' +import Markdown from './Markdown' export default { name: 'AppDetails', components: { Multiselect, + Markdown, }, mixins: [AppManagement, PrefixMixin], @@ -204,66 +203,6 @@ export default { .filter(group => group.id !== 'disabled') .sort((a, b) => a.name.localeCompare(b.name)) }, - renderMarkdown() { - const renderer = new marked.Renderer() - renderer.link = function(href, title, text) { - let prot - try { - prot = decodeURIComponent(unescape(href)) - .replace(/[^\w:]/g, '') - .toLowerCase() - } catch (e) { - return '' - } - - if (prot.indexOf('http:') !== 0 && prot.indexOf('https:') !== 0) { - return '' - } - - let out = '<a href="' + href + '" rel="noreferrer noopener"' - if (title) { - out += ' title="' + title + '"' - } - out += '>' + text + '</a>' - return out - } - renderer.image = function(href, title, text) { - if (text) { - return text - } - return title - } - renderer.blockquote = function(quote) { - return quote - } - return dompurify.sanitize( - marked(this.app.description.trim(), { - renderer, - gfm: false, - highlight: false, - tables: false, - breaks: false, - pedantic: false, - sanitize: true, - smartLists: true, - smartypants: false, - }), - { - SAFE_FOR_JQUERY: true, - ALLOWED_TAGS: [ - 'strong', - 'p', - 'a', - 'ul', - 'ol', - 'li', - 'em', - 'del', - 'blockquote', - ], - } - ) - }, }, mounted() { if (this.app.groups.length > 0) { diff --git a/apps/settings/src/components/Markdown.vue b/apps/settings/src/components/Markdown.vue new file mode 100644 index 0000000000000000000000000000000000000000..74c333d839858ec50c89ac182a71f9b2c253d9a0 --- /dev/null +++ b/apps/settings/src/components/Markdown.vue @@ -0,0 +1,197 @@ +<!-- + - @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + - + - @author Julius Härtl <jus@bitgrid.net> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div class="settings-markdown" v-html="renderMarkdown" /> +</template> + +<script> +import marked from 'marked' +import dompurify from 'dompurify' + +export default { + name: 'Markdown', + props: { + text: { + type: String, + default: '', + }, + }, + computed: { + renderMarkdown() { + const renderer = new marked.Renderer() + renderer.link = function(href, title, text) { + let prot + try { + prot = decodeURIComponent(unescape(href)) + .replace(/[^\w:]/g, '') + .toLowerCase() + } catch (e) { + return '' + } + + if (prot.indexOf('http:') !== 0 && prot.indexOf('https:') !== 0) { + return '' + } + + let out = '<a href="' + href + '" rel="noreferrer noopener"' + if (title) { + out += ' title="' + title + '"' + } + out += '>' + text + '</a>' + return out + } + renderer.image = function(href, title, text) { + if (text) { + return text + } + return title + } + renderer.blockquote = function(quote) { + return quote + } + return dompurify.sanitize( + marked(this.text.trim(), { + renderer, + gfm: false, + highlight: false, + tables: false, + breaks: false, + pedantic: false, + sanitize: true, + smartLists: true, + smartypants: false, + }), + { + SAFE_FOR_JQUERY: true, + ALLOWED_TAGS: [ + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'strong', + 'p', + 'a', + 'ul', + 'ol', + 'li', + 'em', + 'del', + 'blockquote', + ], + } + ) + }, + }, +} +</script> + +<style scoped lang="scss"> + .settings-markdown::v-deep { + + h1, + h2, + h3, + h4, + h5, + h6 { + font-weight: 600; + line-height: 120%; + margin-top: 24px; + margin-bottom: 12px; + color: var(--color-main-text); + } + + h1 { + font-size: 36px; + margin-top: 48px; + } + + h2 { + font-size: 28px; + margin-top: 48px; + } + + h3 { + font-size: 24px; + } + + h4 { + font-size: 21px; + } + + h5 { + font-size: 17px; + } + + h6 { + font-size: 14px; + } + + pre { + white-space: pre; + overflow-x: auto; + background-color: var(--color-background-dark); + border-radius: var(--border-radius); + padding: 1em 1.3em; + margin-bottom: 1em; + } + + p code { + background-color: var(--color-background-dark); + border-radius: var(--border-radius); + padding: .1em .3em; + } + + li { + position: relative; + } + + ul, ol { + padding-left: 10px; + margin-left: 10px; + } + + ul li { + list-style-type: disc; + } + + ul > li > ul > li { + list-style-type: circle; + } + + ul > li > ul > li ul li { + list-style-type: square; + } + + blockquote { + padding-left: 1em; + border-left: 4px solid var(--color-primary-element); + color: var(--color-text-maxcontrast); + margin-left: 0; + margin-right: 0; + } + + } +</style> diff --git a/apps/settings/src/views/Apps.vue b/apps/settings/src/views/Apps.vue index 313c58afbd96077768d60a0d12de9614663219e9..a95127b77d63f6d5397b4d072adc3e3f6a7e8bf3 100644 --- a/apps/settings/src/views/Apps.vue +++ b/apps/settings/src/views/Apps.vue @@ -119,7 +119,23 @@ </template> <!-- Tab content --> - <AppDetails :app="app" /> + + <AppSidebarTab id="desc" + icon="icon-category-office" + :name="t('settings', 'Details')" + :order="0"> + <AppDetails :app="app" /> + </AppSidebarTab> + <AppSidebarTab v-if="app.appstoreData && app.releases[0].translations.en.changelog" + id="desca" + icon="icon-category-organization" + :name="t('settings', 'Changelog')" + :order="1"> + <div v-for="release in app.releases" :key="release.version" class="app-sidebar-tabs__release"> + <h2>{{ release.version }}</h2> + <Markdown v-if="changelog(release)" :text="changelog(release)" /> + </div> + </AppSidebarTab> </AppSidebar> </Content> </template> @@ -131,6 +147,7 @@ import AppNavigationCounter from '@nextcloud/vue/dist/Components/AppNavigationCo import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem' import AppNavigationSpacer from '@nextcloud/vue/dist/Components/AppNavigationSpacer' import AppSidebar from '@nextcloud/vue/dist/Components/AppSidebar' +import AppSidebarTab from '@nextcloud/vue/dist/Components/AppSidebarTab' import Content from '@nextcloud/vue/dist/Components/Content' import Vue from 'vue' import VueLocalStorage from 'vue-localstorage' @@ -139,6 +156,7 @@ import AppList from '../components/AppList' import AppDetails from '../components/AppDetails' import AppManagement from '../mixins/AppManagement' import AppScore from '../components/AppList/AppScore' +import Markdown from '../components/Markdown' Vue.use(VueLocalStorage) @@ -155,7 +173,9 @@ export default { AppNavigationSpacer, AppScore, AppSidebar, + AppSidebarTab, Content, + Markdown, }, mixins: [AppManagement], @@ -228,6 +248,9 @@ export default { } }, + changelog() { + return (release) => release.translations.en.changelog + }, }, watch: { @@ -326,4 +349,19 @@ export default { } } + .app-sidebar-tabs__release { + h2 { + border-bottom: 1px solid var(--color-border); + } + + // Overwrite changelog heading styles + ::v-deep { + h3 { + font-size: 20px; + } + h4 { + font-size: 17px; + } + } + } </style>