mirror of
https://github.com/nextcloud/server.git
synced 2026-06-12 18:21:40 -04:00
Merge pull request #48852 from nextcloud/fix/app-store-markdown
fix(app-store): Correctly render Markdown in app description
This commit is contained in:
commit
8bdf8bc7f3
7 changed files with 80 additions and 54 deletions
58
apps/settings/src/components/Markdown.cy.ts
Normal file
58
apps/settings/src/components/Markdown.cy.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*!
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import Markdown from './Markdown.vue'
|
||||
|
||||
describe('Markdown component', () => {
|
||||
it('renders links', () => {
|
||||
cy.mount(Markdown, {
|
||||
propsData: {
|
||||
text: 'This is [a link](http://example.com)!',
|
||||
},
|
||||
})
|
||||
|
||||
cy.contains('This is')
|
||||
.find('a')
|
||||
.should('exist')
|
||||
.and('have.attr', 'href', 'http://example.com')
|
||||
.and('contain.text', 'a link')
|
||||
})
|
||||
|
||||
it('renders headings', () => {
|
||||
cy.mount(Markdown, {
|
||||
propsData: {
|
||||
text: '# level 1\nText\n## level 2\nText\n### level 3\nText\n#### level 4\nText\n##### level 5\nText\n###### level 6\nText\n',
|
||||
},
|
||||
})
|
||||
|
||||
for (let level = 1; level <= 6; level++) {
|
||||
cy.contains(`h${level}`, `level ${level}`)
|
||||
.should('be.visible')
|
||||
}
|
||||
})
|
||||
|
||||
it('can limit headings', () => {
|
||||
cy.mount(Markdown, {
|
||||
propsData: {
|
||||
text: '# level 1\nText\n## level 2\nText\n### level 3\nText\n#### level 4\nText\n##### level 5\nText\n###### level 6\nText\n',
|
||||
minHeading: 4,
|
||||
},
|
||||
})
|
||||
|
||||
cy.get('h1').should('not.exist')
|
||||
cy.get('h2').should('not.exist')
|
||||
cy.get('h3').should('not.exist')
|
||||
cy.get('h4')
|
||||
.should('exist')
|
||||
.and('contain.text', 'level 1')
|
||||
cy.get('h5')
|
||||
.should('exist')
|
||||
.and('contain.text', 'level 2')
|
||||
cy.contains('h6', 'level 3').should('exist')
|
||||
cy.contains('h6', 'level 4').should('exist')
|
||||
cy.contains('h6', 'level 5').should('exist')
|
||||
cy.contains('h6', 'level 6').should('exist')
|
||||
})
|
||||
})
|
||||
|
|
@ -27,7 +27,7 @@ export default {
|
|||
computed: {
|
||||
renderMarkdown() {
|
||||
const renderer = new marked.Renderer()
|
||||
renderer.link = function(href, title, text) {
|
||||
renderer.link = function({ href, title, text }) {
|
||||
let prot
|
||||
try {
|
||||
prot = decodeURIComponent(unescape(href))
|
||||
|
|
@ -48,18 +48,18 @@ export default {
|
|||
out += '>' + text + '</a>'
|
||||
return out
|
||||
}
|
||||
renderer.heading = (text, level) => {
|
||||
level = Math.min(6, level + (this.minHeading - 1))
|
||||
return `<h${level}>${text}</h${level}>`
|
||||
renderer.heading = ({ text, depth }) => {
|
||||
depth = Math.min(6, depth + (this.minHeading - 1))
|
||||
return `<h${depth}>${text}</h${depth}>`
|
||||
}
|
||||
renderer.image = function(href, title, text) {
|
||||
renderer.image = ({ title, text }) => {
|
||||
if (text) {
|
||||
return text
|
||||
}
|
||||
return title
|
||||
}
|
||||
renderer.blockquote = function(quote) {
|
||||
return quote
|
||||
renderer.blockquote = ({ text }) => {
|
||||
return `<blockquote>${text}</blockquote>`
|
||||
}
|
||||
return dompurify.sanitize(
|
||||
marked(this.text.trim(), {
|
||||
|
|
@ -100,45 +100,13 @@ export default {
|
|||
</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: var(--default-font-size);
|
||||
.settings-markdown::v-deep {
|
||||
a {
|
||||
text-decoration: underline;
|
||||
&::after {
|
||||
content: '↗';
|
||||
padding-inline: calc(var(--default-grid-baseline) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
|
|
@ -183,6 +151,5 @@ export default {
|
|||
color: var(--color-text-maxcontrast);
|
||||
margin-inline: 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ export default defineConfig({
|
|||
},
|
||||
|
||||
component: {
|
||||
specPattern: ['core/**/*.cy.ts', 'apps/**/*.cy.ts'],
|
||||
devServer: {
|
||||
framework: 'vue',
|
||||
bundler: 'webpack',
|
||||
|
|
|
|||
4
dist/settings-apps-view-4529.js
vendored
4
dist/settings-apps-view-4529.js
vendored
File diff suppressed because one or more lines are too long
2
dist/settings-apps-view-4529.js.map
vendored
2
dist/settings-apps-view-4529.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue