Compare commits
3 commits
3db7b9d98f
...
416866a22c
| Author | SHA1 | Date | |
|---|---|---|---|
| 416866a22c | |||
| b4b3927ab1 | |||
| cdc29b795a |
7 changed files with 1776 additions and 24 deletions
|
|
@ -17,11 +17,9 @@ function fillElementForm(
|
|||
): void {
|
||||
cy.get('[data-cy="admin-element-title"]').clear().type(title)
|
||||
cy.get('[data-cy="admin-element-description"]').clear().type(description)
|
||||
cy.get('[data-cy="admin-element-rich-text"]').clear()
|
||||
clearRichText()
|
||||
if (richText !== '') {
|
||||
cy.get('[data-cy="admin-element-rich-text"]').type(richText, {
|
||||
parseSpecialCharSequences: false,
|
||||
})
|
||||
cy.get('[data-cy="admin-element-rich-text"]').type(richText)
|
||||
}
|
||||
cy.get('[data-cy="admin-element-youtube-url"]').clear()
|
||||
if (youtubeUrl !== '') {
|
||||
|
|
@ -29,6 +27,12 @@ function fillElementForm(
|
|||
}
|
||||
}
|
||||
|
||||
function clearRichText(): void {
|
||||
cy.get('[data-cy="admin-element-rich-text"]')
|
||||
.click()
|
||||
.type('{selectAll}{backspace}')
|
||||
}
|
||||
|
||||
describe('admin element editing', () => {
|
||||
it('does not show the edit link to logged-out users', () => {
|
||||
cy.visit('/element/1')
|
||||
|
|
@ -72,7 +76,6 @@ describe('admin element editing', () => {
|
|||
const originalDescription = 'a structured path for inner and outer growth'
|
||||
const updatedTitle = 'Baderech HaAvodah Updated'
|
||||
const updatedDescription = 'Updated admin description'
|
||||
const updatedRichText = '<p>Updated admin rich text</p>'
|
||||
|
||||
loginAsAdmin()
|
||||
cy.visit('/admin/element/1')
|
||||
|
|
@ -80,9 +83,28 @@ describe('admin element editing', () => {
|
|||
fillElementForm(
|
||||
updatedTitle,
|
||||
updatedDescription,
|
||||
updatedRichText,
|
||||
'',
|
||||
'',
|
||||
)
|
||||
cy.get('[data-cy="admin-element-rich-text"]')
|
||||
.should('have.attr', 'contenteditable', 'true')
|
||||
|
||||
cy.get('[data-cy="admin-rich-text-block-type"]').select('heading-2')
|
||||
cy.get('[data-cy="admin-element-rich-text"]')
|
||||
.type('Updated admin heading{enter}')
|
||||
cy.get('[data-cy="admin-rich-text-bold"]').click()
|
||||
cy.get('[data-cy="admin-element-rich-text"]').type('Strong admin text')
|
||||
cy.get('[data-cy="admin-rich-text-bold"]').click()
|
||||
cy.get('[data-cy="admin-element-rich-text"]').type('{enter}')
|
||||
cy.get('[data-cy="admin-rich-text-bullet-list"]').click()
|
||||
cy.get('[data-cy="admin-element-rich-text"]')
|
||||
.type('First saved item{enter}Second saved item')
|
||||
cy.get('[data-cy="admin-rich-text-bullet-list"]').click()
|
||||
cy.window().then((windowObject) => {
|
||||
cy.stub(windowObject, 'prompt').returns('https://example.com/rich-text')
|
||||
})
|
||||
cy.get('[data-cy="admin-rich-text-link"]').click()
|
||||
cy.get('[data-cy="admin-rich-text-insert-table"]').click()
|
||||
cy.get('[data-cy="admin-element-save"]').click()
|
||||
|
||||
cy.get('[data-cy="admin-element-status"]')
|
||||
|
|
@ -91,8 +113,16 @@ describe('admin element editing', () => {
|
|||
cy.contains('header.site-header a', 'View Element').click()
|
||||
cy.location('pathname').should('eq', '/element/1')
|
||||
cy.contains('h1', updatedTitle).should('be.visible')
|
||||
cy.get('[data-cy="element-rich-text"] h2')
|
||||
.should('contain.text', 'Updated admin heading')
|
||||
cy.get('[data-cy="element-rich-text"] strong')
|
||||
.should('contain.text', 'Strong admin text')
|
||||
cy.get('[data-cy="element-rich-text"]')
|
||||
.should('contain.text', 'Updated admin rich text')
|
||||
.should('contain.text', 'First saved item')
|
||||
.and('contain.text', 'Second saved item')
|
||||
cy.get('[data-cy="element-rich-text"] a')
|
||||
.should('have.attr', 'href', 'https://example.com/rich-text')
|
||||
cy.get('[data-cy="element-rich-text"] table').should('exist')
|
||||
|
||||
cy.visit('/admin/element/1')
|
||||
fillElementForm(
|
||||
|
|
@ -105,6 +135,8 @@ describe('admin element editing', () => {
|
|||
cy.get('[data-cy="admin-element-status"]')
|
||||
.should('be.visible')
|
||||
.and('contain.text', 'Saved')
|
||||
cy.contains('header.site-header a', 'View Element').click()
|
||||
cy.get('[data-cy="element-rich-text"]').should('not.exist')
|
||||
})
|
||||
|
||||
it('uploads icon and pdf files immediately through the UI', () => {
|
||||
|
|
|
|||
|
|
@ -21,10 +21,8 @@ describe('cypress database reset', () => {
|
|||
.clear()
|
||||
.type('Dirty Cypress description')
|
||||
cy.get('[data-cy="admin-element-rich-text"]')
|
||||
.clear()
|
||||
.type('<p>Dirty Cypress rich text</p>', {
|
||||
parseSpecialCharSequences: false,
|
||||
})
|
||||
.click()
|
||||
.type('{selectAll}{backspace}Dirty Cypress rich text')
|
||||
cy.get('[data-cy="admin-element-save"]').click()
|
||||
|
||||
cy.get('[data-cy="admin-element-status"]')
|
||||
|
|
|
|||
669
frontend/rabbi_gerzi/package-lock.json
generated
669
frontend/rabbi_gerzi/package-lock.json
generated
|
|
@ -8,6 +8,15 @@
|
|||
"name": "rabbi_gerzi",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@tiptap/extension-highlight": "^3.27.1",
|
||||
"@tiptap/extension-link": "^3.27.1",
|
||||
"@tiptap/extension-table": "^3.27.1",
|
||||
"@tiptap/extension-text-align": "^3.27.1",
|
||||
"@tiptap/extension-underline": "^3.27.1",
|
||||
"@tiptap/pm": "^3.27.1",
|
||||
"@tiptap/starter-kit": "^3.27.1",
|
||||
"@tiptap/vue-3": "^3.27.1",
|
||||
"lucide-vue-next": "^1.0.0",
|
||||
"pinia": "^3.0.4",
|
||||
"vue": "beta",
|
||||
"vue-router": "^5.0.4"
|
||||
|
|
@ -1130,6 +1139,31 @@
|
|||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
|
||||
"integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/utils": "^0.2.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "1.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
|
||||
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.7.5",
|
||||
"@floating-ui/utils": "^0.2.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/utils": {
|
||||
"version": "0.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz",
|
||||
"integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
|
||||
|
|
@ -2291,6 +2325,468 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tiptap/core": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.27.1.tgz",
|
||||
"integrity": "sha512-rV6Qn4wmC6BxfF+4mu6bqGWj9vA4oXXhsrpXaJL2uhjxeHAGofjwcHof2X84VYzeyXgdlsGmqKie4TAppVXZUQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-blockquote": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.27.1.tgz",
|
||||
"integrity": "sha512-VMF7xJx6qEGiX6DTKNiL31NLqypOcd/4sNjFSe8rb41PwejBJh/nOqVIbBvWkiT6NMGFLxMhj7zJ8/zPo1hXeg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bold": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.27.1.tgz",
|
||||
"integrity": "sha512-TlC5bsS+pqETTrlz4CZz9RO/cKBYtELGIxwtKeivUn3eNfnOxQbbu4WDsiwIfzRFyd0OMnKl6BPM2KnYEehoEQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bubble-menu": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.27.1.tgz",
|
||||
"integrity": "sha512-j/j8Qp9Z5nViade2m7zjrO/CYH/Ca80Qj7aqo0eUaei6FZQ5izlF9o4XQU5EFMAutV6mwynsPUp8FVo5sCuYfw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bullet-list": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.27.1.tgz",
|
||||
"integrity": "sha512-faCUHnRP47o9Zh9VZZX6EX/569udw9Vopm2PgEKPWuKLE2qaS5WBuUVU0iItdJmKUqaWiOZkpoW4jvnDmj0dfg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.27.1.tgz",
|
||||
"integrity": "sha512-epOUpFfEmBzjvnqvjv2qHX7NAuLo5dlOGV690lWu+sAYMjibuJBeVvAiKPyFCfRCCTUxdbDB3jbaOA1yEcEJ7w==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code-block": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.27.1.tgz",
|
||||
"integrity": "sha512-pHlzmZx2OlHfyQ0yRlT5UL4mGokz947DthZuYefN1OleVqOkHpWBG+2JQwqoNq6bmzMne92zbH32rhcJUEYSjA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-document": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.27.1.tgz",
|
||||
"integrity": "sha512-8FbBTkfnRP4iVaoj+2h3iWa+H0eGDD3yTyVCwrmue/sQTkqUNUoSuAZa3GDG4Sd41xdPwTJxl9nUWGgM1qDCnw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-dropcursor": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.27.1.tgz",
|
||||
"integrity": "sha512-blFf9x9RG0Qr7P3FoAH/033ffa+mMLZn34trVs8Vi0Ppk6FmJAg5HpYFOtmYoeREdNDJ5rHJKV7SoACbOHgskQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-floating-menu": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.27.1.tgz",
|
||||
"integrity": "sha512-BmJF1VqB7dSJkgAalrpVFj88WLhxKjcWPuWHOqf2ITrUU2832BhKLXKmxjWUy1gqV8PfNNVWtGfIERy7I0y0+Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-gapcursor": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.27.1.tgz",
|
||||
"integrity": "sha512-QoezN0wdvXIwLQ4ee2ccWDaX3RG0lzgQpIMpMz55oPDhpUVax1+19ApsS53LkcktpS4EbnPL4xO4DaJk0Vp7PQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-hard-break": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.27.1.tgz",
|
||||
"integrity": "sha512-iv/m9hzl6jfSj9Q8UEjAxONvCoUDaP7M9SRCPx3PaLNxA230TTD6RE0Ye4zFJ8ze7ZVoJJMAqg9Qpq1iYg2JOQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-heading": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.27.1.tgz",
|
||||
"integrity": "sha512-SrC4l1kEIyv9ZXFaI/8LQqU2MyMmjczw7XXsWUQOTN4YXv0JyVgMNR3cI/wz0d2xsTfBdZ1N85Tdng+Ga1t0Sg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-highlight": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-3.27.1.tgz",
|
||||
"integrity": "sha512-IeMIUKbW4oyRkgn92BPYQ0fifkbTwVigKwa107nGDHMokz+pHQPFHy8xG3U7gtUOra/8OUo57bFgNGuP0TaH4A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-horizontal-rule": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.27.1.tgz",
|
||||
"integrity": "sha512-QlKE7qn5qMnIGVGhXQlvYedvLtNJ9z0dmit5w8vPb8tKzW4Spk6M7N2kruprrDA8GBwHfeR5wmF+njfUm34qxg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-italic": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.27.1.tgz",
|
||||
"integrity": "sha512-jGGeyn9uRUnNjSTHpbqhiGsp6KaYTSbV09jDXPJI9cDwfV9hpugLvpaCZd0BMBbhU1B1W6kOfX0BE15qX/HQfA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-link": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.27.1.tgz",
|
||||
"integrity": "sha512-/2jBfsxBZUDGJmpZifqRQPz7f1E5qpS1BckTZ39TADzUJX+feKy7RJ3DtQ02+8y6SSMzvP9loGVjrk6zEMTk4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"linkifyjs": "^4.3.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.27.1.tgz",
|
||||
"integrity": "sha512-c2Upru7lj0/ZV/Ibww6cNz6sUS8m6Dp/9uygFhYcZOd3X8M0xBIEk42c6m6SQehkPziVA8QOgNJz7sMqsbz1OQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-item": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.27.1.tgz",
|
||||
"integrity": "sha512-zwRl01ETfCkWUvtvK5fw9bXtAajMPkvlkE3Cq6JvH3LF7XXJwDtNj5Tj7exacMpCaSZmlNc43vFb2rAYnrnwMA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-keymap": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.27.1.tgz",
|
||||
"integrity": "sha512-OIMZNlzPSO8WRd4ic73Fxckzl4N1tesjjLL2XApaNA/uMpO0LoF6WSRPAWv+Z24Wp92ARRJAnRP7iZoI5+Jxig==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-ordered-list": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.27.1.tgz",
|
||||
"integrity": "sha512-GYrKqD//9nHJ2r80uXqbDMzRnFpGzbaEQRTSGaO/SH7DvXWFMow8evkOdjQ7PCQO07jNjJo75+A85Jwu3Ov3AA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-paragraph": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.27.1.tgz",
|
||||
"integrity": "sha512-7K7eo1gruOgAsnbK+GCV23AUVUI0cL1bTig8HaPneoFMVbig7vddk8jNLKBWO8TXVbG7TuHdnDN4F98vdtwh5Q==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-strike": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.27.1.tgz",
|
||||
"integrity": "sha512-Y3DW1jlSlCNCyMGHP3+3qBNNPS83wuFz4RTYGjZtvRRTCRh7apZme9XRWMq1rN5mJ2Cr7fKocA2/5Bs13KgN6Q==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-table": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-table/-/extension-table-3.27.1.tgz",
|
||||
"integrity": "sha512-tNB8kjxo0+XPremnWkd6NUikpeJ+JQrss7HntL8GgIxX4t0gkdnLn9yUWb0JzcaYP7Y8iTZZHdkPs0P154DG8Q==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.27.1.tgz",
|
||||
"integrity": "sha512-6ZwaZwSrDh+KFFv6V1J79oO37yPs7y1bFxvk1/9Ih2rn3Xr5AWz+eMS+n8RpH3djBVVAQpdIAeYQgcn+VCSsTg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-align": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-3.27.1.tgz",
|
||||
"integrity": "sha512-EXawuJBO55wd8WcTbHTMoPhv0CGQxza4yCCPB5Hqz4ZPQwahIr3ej+8yp/kimIl0xokabwZ0/Fu8STQ4AkZv5g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-underline": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.27.1.tgz",
|
||||
"integrity": "sha512-N889J4nXN/TPfVt8uF9N1A0SY82E90zwc1y26lqOcw6KWNLmQrlhMh/9OD4ikLDbekmFpOBq/UicpHf/6S8hbQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extensions": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.27.1.tgz",
|
||||
"integrity": "sha512-1Tdx9faw8k0/83V6X+xCDVhV8yElGt95JxeW3YMkKQJI56QdlPz0xOdJPlMiSGJKinPyVier+x9LJD/YZUZIaw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/pm": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.27.1.tgz",
|
||||
"integrity": "sha512-Ffjx+vimmBU7zH/KrpXzJid3+pziCe/VL2aexSTP63cyQwKQ65LkFkCKaIsSpFdQQuakVZBGWjCA5RoBV852pw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-changeset": "^2.3.0",
|
||||
"prosemirror-commands": "^1.6.2",
|
||||
"prosemirror-dropcursor": "^1.8.1",
|
||||
"prosemirror-gapcursor": "^1.3.2",
|
||||
"prosemirror-history": "^1.4.1",
|
||||
"prosemirror-inputrules": "^1.4.0",
|
||||
"prosemirror-keymap": "^1.2.3",
|
||||
"prosemirror-model": "^1.25.7",
|
||||
"prosemirror-schema-list": "^1.5.0",
|
||||
"prosemirror-state": "^1.4.4",
|
||||
"prosemirror-tables": "^1.8.0",
|
||||
"prosemirror-transform": "^1.12.0",
|
||||
"prosemirror-view": "^1.41.8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/starter-kit": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.27.1.tgz",
|
||||
"integrity": "sha512-vfxRsqW8rCc0k4pzo0ilU3wobVi2wqVj88VZI2SlgZlNnUAkrDGDIAph7CTa9k9fshV+O1ivpEgPC5yC046jow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tiptap/core": "^3.27.1",
|
||||
"@tiptap/extension-blockquote": "^3.27.1",
|
||||
"@tiptap/extension-bold": "^3.27.1",
|
||||
"@tiptap/extension-bullet-list": "^3.27.1",
|
||||
"@tiptap/extension-code": "^3.27.1",
|
||||
"@tiptap/extension-code-block": "^3.27.1",
|
||||
"@tiptap/extension-document": "^3.27.1",
|
||||
"@tiptap/extension-dropcursor": "^3.27.1",
|
||||
"@tiptap/extension-gapcursor": "^3.27.1",
|
||||
"@tiptap/extension-hard-break": "^3.27.1",
|
||||
"@tiptap/extension-heading": "^3.27.1",
|
||||
"@tiptap/extension-horizontal-rule": "^3.27.1",
|
||||
"@tiptap/extension-italic": "^3.27.1",
|
||||
"@tiptap/extension-link": "^3.27.1",
|
||||
"@tiptap/extension-list": "^3.27.1",
|
||||
"@tiptap/extension-list-item": "^3.27.1",
|
||||
"@tiptap/extension-list-keymap": "^3.27.1",
|
||||
"@tiptap/extension-ordered-list": "^3.27.1",
|
||||
"@tiptap/extension-paragraph": "^3.27.1",
|
||||
"@tiptap/extension-strike": "^3.27.1",
|
||||
"@tiptap/extension-text": "^3.27.1",
|
||||
"@tiptap/extension-underline": "^3.27.1",
|
||||
"@tiptap/extensions": "^3.27.1",
|
||||
"@tiptap/pm": "^3.27.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/vue-3": {
|
||||
"version": "3.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.27.1.tgz",
|
||||
"integrity": "sha512-o5GB6hfUnyf9sCB306rHWmaIYRL+02ROX657EkuY8tEWKHMTuMjHWl2AqHMP47wz0W9DaMOJLvcPpYdAEKq3Mw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tiptap/extension-bubble-menu": "^3.27.1",
|
||||
"@tiptap/extension-floating-menu": "^3.27.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/pm": "3.27.1",
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node24": {
|
||||
"version": "24.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node24/-/node24-24.0.4.tgz",
|
||||
|
|
@ -5738,6 +6234,12 @@
|
|||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/linkifyjs": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.3.tgz",
|
||||
"integrity": "sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/listr2": {
|
||||
"version": "3.14.0",
|
||||
"resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
|
||||
|
|
@ -5908,6 +6410,16 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-vue-next": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-1.0.0.tgz",
|
||||
"integrity": "sha512-V6SPvx1IHTj/UY+FrIYWV5faISsPSb8BnWSFDxAtezWKvWc9ZZ40PDrdu1/Qb5vg4lHWr1hs1BAMGVGm6V1Xdg==",
|
||||
"deprecated": "Package deprecated. Please use @lucide/vue instead.",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"vue": ">=3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
|
|
@ -6316,6 +6828,12 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/orderedmap": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
|
||||
"integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ospath": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz",
|
||||
|
|
@ -6798,6 +7316,145 @@
|
|||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-changeset": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz",
|
||||
"integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-transform": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-commands": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz",
|
||||
"integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.10.2"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-dropcursor": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz",
|
||||
"integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.1.0",
|
||||
"prosemirror-view": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-gapcursor": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz",
|
||||
"integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-keymap": "^1.0.0",
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-view": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-history": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz",
|
||||
"integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.2.2",
|
||||
"prosemirror-transform": "^1.0.0",
|
||||
"prosemirror-view": "^1.31.0",
|
||||
"rope-sequence": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-inputrules": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz",
|
||||
"integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-keymap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz",
|
||||
"integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"w3c-keyname": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-model": {
|
||||
"version": "1.25.9",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.9.tgz",
|
||||
"integrity": "sha512-pRTklkDDMMRopyoAcrr9wV/8g/RYgrLHBuJAb5hlEuYZRdm5yqmPjWId83fpBwPpSFqEdja0H7Dfd7z1X/npcA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"orderedmap": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-schema-list": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz",
|
||||
"integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-state": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz",
|
||||
"integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-transform": "^1.0.0",
|
||||
"prosemirror-view": "^1.27.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-tables": {
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz",
|
||||
"integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-keymap": "^1.2.3",
|
||||
"prosemirror-model": "^1.25.4",
|
||||
"prosemirror-state": "^1.4.4",
|
||||
"prosemirror-transform": "^1.10.5",
|
||||
"prosemirror-view": "^1.41.4"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-transform": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz",
|
||||
"integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-view": {
|
||||
"version": "1.41.9",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.9.tgz",
|
||||
"integrity": "sha512-clTunTX+eaLbr87L1V1QPheRlEQJyTlL3gXe9x3jQIk3rL0RVWxviDGz8tFaydwIVm+hKhYCyr+R/zBtWr9s6A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.25.8",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
|
||||
|
|
@ -6981,6 +7638,12 @@
|
|||
"@rolldown/binding-win32-x64-msvc": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/rope-sequence": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
|
||||
"integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/run-applescript": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
|
||||
|
|
@ -8291,6 +8954,12 @@
|
|||
"typescript": ">=5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-keyname": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/webpack-virtual-modules": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,15 @@
|
|||
"test:e2e:open": "cypress open"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tiptap/extension-highlight": "^3.27.1",
|
||||
"@tiptap/extension-link": "^3.27.1",
|
||||
"@tiptap/extension-table": "^3.27.1",
|
||||
"@tiptap/extension-text-align": "^3.27.1",
|
||||
"@tiptap/extension-underline": "^3.27.1",
|
||||
"@tiptap/pm": "^3.27.1",
|
||||
"@tiptap/starter-kit": "^3.27.1",
|
||||
"@tiptap/vue-3": "^3.27.1",
|
||||
"lucide-vue-next": "^1.0.0",
|
||||
"pinia": "^3.0.4",
|
||||
"vue": "beta",
|
||||
"vue-router": "^5.0.4"
|
||||
|
|
|
|||
970
frontend/rabbi_gerzi/src/components/RichTextEditor.vue
Normal file
970
frontend/rabbi_gerzi/src/components/RichTextEditor.vue
Normal file
|
|
@ -0,0 +1,970 @@
|
|||
<script setup lang="ts">
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import {
|
||||
Table,
|
||||
TableCell,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@tiptap/extension-table'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import Underline from '@tiptap/extension-underline'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import type { Editor, JSONContent } from '@tiptap/core'
|
||||
import { EditorContent, useEditor } from '@tiptap/vue-3'
|
||||
import {
|
||||
AlignCenter,
|
||||
AlignJustify,
|
||||
AlignLeft,
|
||||
AlignRight,
|
||||
Bold,
|
||||
Columns3,
|
||||
Highlighter,
|
||||
Italic,
|
||||
Link2,
|
||||
List,
|
||||
ListOrdered,
|
||||
Minus,
|
||||
Plus,
|
||||
Quote,
|
||||
Redo2,
|
||||
Rows3,
|
||||
Strikethrough,
|
||||
Table2,
|
||||
TableCellsMerge,
|
||||
TableCellsSplit,
|
||||
Trash2,
|
||||
Underline as UnderlineIcon,
|
||||
Undo2,
|
||||
Unlink2,
|
||||
} from 'lucide-vue-next'
|
||||
import { computed, watch } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string
|
||||
disabled: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
|
||||
type HeadingLevel = 2 | 3 | 4
|
||||
type TextAlignment = 'left' | 'center' | 'right' | 'justify'
|
||||
|
||||
const allowedLinkProtocols = ['http:', 'https:', 'mailto:', 'tel:']
|
||||
|
||||
const editor = useEditor({
|
||||
content: props.modelValue,
|
||||
editable: !props.disabled,
|
||||
extensions: [
|
||||
StarterKit.configure({
|
||||
heading: {
|
||||
levels: [2, 3, 4],
|
||||
},
|
||||
link: false,
|
||||
underline: false,
|
||||
}),
|
||||
Underline,
|
||||
Highlight,
|
||||
Link.configure({
|
||||
autolink: true,
|
||||
defaultProtocol: 'https',
|
||||
HTMLAttributes: {
|
||||
rel: 'noreferrer',
|
||||
target: '_blank',
|
||||
},
|
||||
isAllowedUri: (linkUrl) => {
|
||||
return isAllowedLinkUrl(linkUrl)
|
||||
},
|
||||
linkOnPaste: true,
|
||||
openOnClick: false,
|
||||
protocols: ['http', 'https', 'mailto', 'tel'],
|
||||
shouldAutoLink: (linkUrl) => {
|
||||
return isAllowedLinkUrl(linkUrl)
|
||||
},
|
||||
}),
|
||||
TextAlign.configure({
|
||||
types: ['heading', 'paragraph'],
|
||||
}),
|
||||
Table.configure({
|
||||
resizable: true,
|
||||
}),
|
||||
TableRow,
|
||||
TableHeader,
|
||||
TableCell,
|
||||
],
|
||||
editorProps: {
|
||||
attributes: {
|
||||
'aria-label': 'Rich text editor',
|
||||
class: 'rich-text-editor__surface',
|
||||
'data-cy': 'admin-element-rich-text',
|
||||
},
|
||||
},
|
||||
onUpdate: ({ editor: updatedEditor }) => {
|
||||
emit('update:modelValue', getEditorHtml(updatedEditor))
|
||||
},
|
||||
})
|
||||
|
||||
const currentBlockType = computed(() => {
|
||||
const editorInstance = editor.value
|
||||
if (editorInstance === undefined) {
|
||||
return 'paragraph'
|
||||
}
|
||||
|
||||
if (editorInstance.isActive('heading', { level: 2 })) {
|
||||
return 'heading-2'
|
||||
}
|
||||
|
||||
if (editorInstance.isActive('heading', { level: 3 })) {
|
||||
return 'heading-3'
|
||||
}
|
||||
|
||||
if (editorInstance.isActive('heading', { level: 4 })) {
|
||||
return 'heading-4'
|
||||
}
|
||||
|
||||
return 'paragraph'
|
||||
})
|
||||
|
||||
const isInTable = computed(() => {
|
||||
const editorInstance = editor.value
|
||||
if (editorInstance === undefined) {
|
||||
return false
|
||||
}
|
||||
|
||||
return editorInstance.isActive('table')
|
||||
|| editorInstance.isActive('tableCell')
|
||||
|| editorInstance.isActive('tableHeader')
|
||||
|| editorInstance.isActive('tableRow')
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(currentValue) => {
|
||||
const editorInstance = editor.value
|
||||
if (editorInstance === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
if (getEditorHtml(editorInstance) === currentValue) {
|
||||
return
|
||||
}
|
||||
|
||||
editorInstance.commands.setContent(currentValue, {
|
||||
emitUpdate: false,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.disabled,
|
||||
(isDisabled) => {
|
||||
const editorInstance = editor.value
|
||||
if (editorInstance === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
editorInstance.setEditable(!isDisabled)
|
||||
},
|
||||
)
|
||||
|
||||
function getEditorHtml(editorInstance: Editor): string {
|
||||
if (editorInstance.isEmpty) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return editorInstance.getHTML()
|
||||
}
|
||||
|
||||
function isAllowedLinkUrl(linkUrl: string): boolean {
|
||||
const normalizedUrl = normalizeLinkUrl(linkUrl)
|
||||
|
||||
return normalizedUrl !== null
|
||||
}
|
||||
|
||||
function normalizeLinkUrl(linkUrl: string): string | null {
|
||||
const trimmedUrl = linkUrl.trim()
|
||||
if (trimmedUrl === '') {
|
||||
return null
|
||||
}
|
||||
|
||||
let parsedUrl: URL
|
||||
try {
|
||||
parsedUrl = new URL(trimmedUrl)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!allowedLinkProtocols.includes(parsedUrl.protocol)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return parsedUrl.toString()
|
||||
}
|
||||
|
||||
function isEditorDisabled(): boolean {
|
||||
return props.disabled || editor.value === undefined
|
||||
}
|
||||
|
||||
function isMarkActive(markName: string): boolean {
|
||||
const editorInstance = editor.value
|
||||
if (editorInstance === undefined) {
|
||||
return false
|
||||
}
|
||||
|
||||
return editorInstance.isActive(markName)
|
||||
}
|
||||
|
||||
function isAlignmentActive(alignment: TextAlignment): boolean {
|
||||
const editorInstance = editor.value
|
||||
if (editorInstance === undefined) {
|
||||
return false
|
||||
}
|
||||
|
||||
return editorInstance.isActive({ textAlign: alignment })
|
||||
}
|
||||
|
||||
function handleBlockTypeChange(changeEvent: Event): void {
|
||||
const target = changeEvent.target
|
||||
if (!(target instanceof HTMLSelectElement)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (target.value === 'paragraph') {
|
||||
setParagraph()
|
||||
return
|
||||
}
|
||||
|
||||
if (target.value === 'heading-2') {
|
||||
setHeading(2)
|
||||
return
|
||||
}
|
||||
|
||||
if (target.value === 'heading-3') {
|
||||
setHeading(3)
|
||||
return
|
||||
}
|
||||
|
||||
if (target.value === 'heading-4') {
|
||||
setHeading(4)
|
||||
}
|
||||
}
|
||||
|
||||
function setParagraph(): void {
|
||||
editor.value?.chain().focus().setParagraph().run()
|
||||
}
|
||||
|
||||
function setHeading(headingLevel: HeadingLevel): void {
|
||||
editor.value?.chain().focus().setHeading({ level: headingLevel }).run()
|
||||
}
|
||||
|
||||
function toggleBold(): void {
|
||||
editor.value?.chain().focus().toggleBold().run()
|
||||
}
|
||||
|
||||
function toggleItalic(): void {
|
||||
editor.value?.chain().focus().toggleItalic().run()
|
||||
}
|
||||
|
||||
function toggleUnderline(): void {
|
||||
editor.value?.chain().focus().toggleUnderline().run()
|
||||
}
|
||||
|
||||
function toggleStrike(): void {
|
||||
editor.value?.chain().focus().toggleStrike().run()
|
||||
}
|
||||
|
||||
function toggleHighlight(): void {
|
||||
editor.value?.chain().focus().toggleHighlight().run()
|
||||
}
|
||||
|
||||
function setTextAlign(alignment: TextAlignment): void {
|
||||
editor.value?.chain().focus().setTextAlign(alignment).run()
|
||||
}
|
||||
|
||||
function toggleBulletList(): void {
|
||||
editor.value?.chain().focus().toggleBulletList().run()
|
||||
}
|
||||
|
||||
function toggleOrderedList(): void {
|
||||
editor.value?.chain().focus().toggleOrderedList().run()
|
||||
}
|
||||
|
||||
function toggleBlockquote(): void {
|
||||
editor.value?.chain().focus().toggleBlockquote().run()
|
||||
}
|
||||
|
||||
function setHorizontalRule(): void {
|
||||
editor.value?.chain().focus().setHorizontalRule().run()
|
||||
}
|
||||
|
||||
function applyLink(): void {
|
||||
const editorInstance = editor.value
|
||||
if (editorInstance === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const linkUrl = window.prompt('Link URL', currentLinkHref(editorInstance))
|
||||
if (linkUrl === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const normalizedUrl = normalizeLinkUrl(linkUrl)
|
||||
if (normalizedUrl === null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (editorInstance.state.selection.empty) {
|
||||
insertLinkedText(editorInstance, normalizedUrl)
|
||||
return
|
||||
}
|
||||
|
||||
editorInstance
|
||||
.chain()
|
||||
.focus()
|
||||
.extendMarkRange('link')
|
||||
.setLink({ href: normalizedUrl })
|
||||
.run()
|
||||
}
|
||||
|
||||
function currentLinkHref(editorInstance: Editor): string {
|
||||
const linkAttributes = editorInstance.getAttributes('link') as Record<
|
||||
string,
|
||||
unknown
|
||||
>
|
||||
const href = linkAttributes.href
|
||||
|
||||
return typeof href === 'string' ? href : ''
|
||||
}
|
||||
|
||||
function insertLinkedText(editorInstance: Editor, linkUrl: string): void {
|
||||
const linkedText: JSONContent = {
|
||||
marks: [
|
||||
{
|
||||
attrs: {
|
||||
href: linkUrl,
|
||||
},
|
||||
type: 'link',
|
||||
},
|
||||
],
|
||||
text: linkUrl,
|
||||
type: 'text',
|
||||
}
|
||||
|
||||
editorInstance.chain().focus().insertContent(linkedText).run()
|
||||
}
|
||||
|
||||
function unsetLink(): void {
|
||||
editor.value?.chain().focus().unsetLink().run()
|
||||
}
|
||||
|
||||
function undo(): void {
|
||||
editor.value?.chain().focus().undo().run()
|
||||
}
|
||||
|
||||
function redo(): void {
|
||||
editor.value?.chain().focus().redo().run()
|
||||
}
|
||||
|
||||
function insertTable(): void {
|
||||
editor.value
|
||||
?.chain()
|
||||
.focus()
|
||||
.insertTable({
|
||||
cols: 3,
|
||||
rows: 3,
|
||||
withHeaderRow: true,
|
||||
})
|
||||
.run()
|
||||
}
|
||||
|
||||
function addColumnAfter(): void {
|
||||
editor.value?.chain().focus().addColumnAfter().run()
|
||||
}
|
||||
|
||||
function deleteColumn(): void {
|
||||
editor.value?.chain().focus().deleteColumn().run()
|
||||
}
|
||||
|
||||
function addRowAfter(): void {
|
||||
editor.value?.chain().focus().addRowAfter().run()
|
||||
}
|
||||
|
||||
function deleteRow(): void {
|
||||
editor.value?.chain().focus().deleteRow().run()
|
||||
}
|
||||
|
||||
function toggleHeaderRow(): void {
|
||||
editor.value?.chain().focus().toggleHeaderRow().run()
|
||||
}
|
||||
|
||||
function mergeOrSplitCells(): void {
|
||||
editor.value?.chain().focus().mergeOrSplit().run()
|
||||
}
|
||||
|
||||
function splitCell(): void {
|
||||
editor.value?.chain().focus().splitCell().run()
|
||||
}
|
||||
|
||||
function deleteTable(): void {
|
||||
editor.value?.chain().focus().deleteTable().run()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rich-text-editor">
|
||||
<div class="rich-text-editor__toolbar" aria-label="Rich text controls">
|
||||
<select
|
||||
class="rich-text-editor__select"
|
||||
data-cy="admin-rich-text-block-type"
|
||||
:disabled="isEditorDisabled()"
|
||||
:value="currentBlockType"
|
||||
aria-label="Block type"
|
||||
@change="handleBlockTypeChange"
|
||||
>
|
||||
<option value="paragraph">Paragraph</option>
|
||||
<option value="heading-2">Heading 2</option>
|
||||
<option value="heading-3">Heading 3</option>
|
||||
<option value="heading-4">Heading 4</option>
|
||||
</select>
|
||||
|
||||
<div class="rich-text-editor__button-group">
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
data-cy="admin-rich-text-bold"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('bold')"
|
||||
:class="{ 'rich-text-editor__button--active': isMarkActive('bold') }"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Bold"
|
||||
title="Bold"
|
||||
@click="toggleBold"
|
||||
>
|
||||
<Bold :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('italic')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isMarkActive('italic'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Italic"
|
||||
title="Italic"
|
||||
@click="toggleItalic"
|
||||
>
|
||||
<Italic :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('underline')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isMarkActive('underline'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Underline"
|
||||
title="Underline"
|
||||
@click="toggleUnderline"
|
||||
>
|
||||
<UnderlineIcon :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('strike')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isMarkActive('strike'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Strike"
|
||||
title="Strike"
|
||||
@click="toggleStrike"
|
||||
>
|
||||
<Strikethrough :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('highlight')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isMarkActive('highlight'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Highlight"
|
||||
title="Highlight"
|
||||
@click="toggleHighlight"
|
||||
>
|
||||
<Highlighter :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="rich-text-editor__button-group">
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isAlignmentActive('left')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isAlignmentActive('left'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Align left"
|
||||
title="Align left"
|
||||
@click="setTextAlign('left')"
|
||||
>
|
||||
<AlignLeft :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isAlignmentActive('center')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isAlignmentActive('center'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Align center"
|
||||
title="Align center"
|
||||
@click="setTextAlign('center')"
|
||||
>
|
||||
<AlignCenter :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isAlignmentActive('right')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isAlignmentActive('right'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Align right"
|
||||
title="Align right"
|
||||
@click="setTextAlign('right')"
|
||||
>
|
||||
<AlignRight :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isAlignmentActive('justify')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isAlignmentActive('justify'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Justify"
|
||||
title="Justify"
|
||||
@click="setTextAlign('justify')"
|
||||
>
|
||||
<AlignJustify :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="rich-text-editor__button-group">
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
data-cy="admin-rich-text-bullet-list"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('bulletList')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isMarkActive('bulletList'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Bullet list"
|
||||
title="Bullet list"
|
||||
@click="toggleBulletList"
|
||||
>
|
||||
<List :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('orderedList')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isMarkActive('orderedList'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Ordered list"
|
||||
title="Ordered list"
|
||||
@click="toggleOrderedList"
|
||||
>
|
||||
<ListOrdered :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('blockquote')"
|
||||
:class="{
|
||||
'rich-text-editor__button--active': isMarkActive('blockquote'),
|
||||
}"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Blockquote"
|
||||
title="Blockquote"
|
||||
@click="toggleBlockquote"
|
||||
>
|
||||
<Quote :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Horizontal rule"
|
||||
title="Horizontal rule"
|
||||
@click="setHorizontalRule"
|
||||
>
|
||||
<Minus :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="rich-text-editor__button-group">
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
data-cy="admin-rich-text-link"
|
||||
type="button"
|
||||
:aria-pressed="isMarkActive('link')"
|
||||
:class="{ 'rich-text-editor__button--active': isMarkActive('link') }"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Link"
|
||||
title="Link"
|
||||
@click="applyLink"
|
||||
>
|
||||
<Link2 :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Remove link"
|
||||
title="Remove link"
|
||||
@click="unsetLink"
|
||||
>
|
||||
<Unlink2 :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="rich-text-editor__button-group">
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
data-cy="admin-rich-text-insert-table"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Insert table"
|
||||
title="Insert table"
|
||||
@click="insertTable"
|
||||
>
|
||||
<Table2 :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled() || !isInTable"
|
||||
aria-label="Add column"
|
||||
title="Add column"
|
||||
@click="addColumnAfter"
|
||||
>
|
||||
<Columns3 :size="16" aria-hidden="true" />
|
||||
<Plus :size="11" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled() || !isInTable"
|
||||
aria-label="Delete column"
|
||||
title="Delete column"
|
||||
@click="deleteColumn"
|
||||
>
|
||||
<Columns3 :size="16" aria-hidden="true" />
|
||||
<Trash2 :size="11" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled() || !isInTable"
|
||||
aria-label="Add row"
|
||||
title="Add row"
|
||||
@click="addRowAfter"
|
||||
>
|
||||
<Rows3 :size="16" aria-hidden="true" />
|
||||
<Plus :size="11" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled() || !isInTable"
|
||||
aria-label="Delete row"
|
||||
title="Delete row"
|
||||
@click="deleteRow"
|
||||
>
|
||||
<Rows3 :size="16" aria-hidden="true" />
|
||||
<Trash2 :size="11" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled() || !isInTable"
|
||||
aria-label="Toggle header row"
|
||||
title="Toggle header row"
|
||||
@click="toggleHeaderRow"
|
||||
>
|
||||
<Rows3 :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled() || !isInTable"
|
||||
aria-label="Merge cells"
|
||||
title="Merge cells"
|
||||
@click="mergeOrSplitCells"
|
||||
>
|
||||
<TableCellsMerge :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled() || !isInTable"
|
||||
aria-label="Split cell"
|
||||
title="Split cell"
|
||||
@click="splitCell"
|
||||
>
|
||||
<TableCellsSplit :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled() || !isInTable"
|
||||
aria-label="Delete table"
|
||||
title="Delete table"
|
||||
@click="deleteTable"
|
||||
>
|
||||
<Trash2 :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="rich-text-editor__button-group">
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Undo"
|
||||
title="Undo"
|
||||
@click="undo"
|
||||
>
|
||||
<Undo2 :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
class="rich-text-editor__button"
|
||||
type="button"
|
||||
:disabled="isEditorDisabled()"
|
||||
aria-label="Redo"
|
||||
title="Redo"
|
||||
@click="redo"
|
||||
>
|
||||
<Redo2 :size="16" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EditorContent :editor="editor" class="rich-text-editor__content" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.rich-text-editor {
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
background: var(--color-white);
|
||||
}
|
||||
|
||||
.rich-text-editor:focus-within {
|
||||
border-color: var(--color-slate);
|
||||
}
|
||||
|
||||
.rich-text-editor__toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
padding: 0.55rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
background: #fbfaf6;
|
||||
}
|
||||
|
||||
.rich-text-editor__select {
|
||||
min-height: 2.2rem;
|
||||
padding: 0 0.55rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
color: var(--color-text);
|
||||
background: var(--color-white);
|
||||
font-family: var(--font-sans);
|
||||
font-size: 0.86rem;
|
||||
}
|
||||
|
||||
.rich-text-editor__button-group {
|
||||
display: inline-flex;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
background: var(--color-white);
|
||||
}
|
||||
|
||||
.rich-text-editor__button {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 2.15rem;
|
||||
height: 2.15rem;
|
||||
padding: 0 0.45rem;
|
||||
border: 0;
|
||||
border-right: 1px solid var(--color-border);
|
||||
color: var(--color-text-muted);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.rich-text-editor__button:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.rich-text-editor__button:hover:not(:disabled),
|
||||
.rich-text-editor__button:focus-visible,
|
||||
.rich-text-editor__button--active {
|
||||
color: var(--color-white);
|
||||
background: var(--color-slate);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.rich-text-editor__button:disabled,
|
||||
.rich-text-editor__select:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.rich-text-editor__content {
|
||||
background: var(--color-white);
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(.rich-text-editor__surface) {
|
||||
min-height: 15rem;
|
||||
padding: 0.85rem 0.95rem;
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-sans);
|
||||
font-size: 0.98rem;
|
||||
line-height: 1.65;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(.rich-text-editor__surface > *:first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(.rich-text-editor__surface > *:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(h2),
|
||||
.rich-text-editor__content :deep(h3),
|
||||
.rich-text-editor__content :deep(h4) {
|
||||
margin: 1.1rem 0 0.45rem;
|
||||
color: #2c2c2c;
|
||||
font-family: var(--font-serif);
|
||||
font-weight: 500;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(h2) {
|
||||
font-size: 1.55rem;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(h3) {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(h4) {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(p) {
|
||||
margin: 0 0 0.75rem;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(ul),
|
||||
.rich-text-editor__content :deep(ol) {
|
||||
margin: 0 0 0.85rem;
|
||||
padding-left: 1.45rem;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(blockquote) {
|
||||
margin: 1rem 0;
|
||||
padding: 0.1rem 0 0.1rem 1rem;
|
||||
border-left: 3px solid var(--color-olive);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(mark) {
|
||||
padding: 0 0.16em;
|
||||
background: #fff3a7;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(a) {
|
||||
color: var(--color-slate);
|
||||
font-weight: 600;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.16em;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(hr) {
|
||||
margin: 1.2rem 0;
|
||||
border: 0;
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(.tableWrapper) {
|
||||
max-width: 100%;
|
||||
margin: 1rem 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(table) {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(th),
|
||||
.rich-text-editor__content :deep(td) {
|
||||
min-width: 4rem;
|
||||
padding: 0.45rem 0.55rem;
|
||||
border: 1px solid var(--color-border);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(th) {
|
||||
background: #f6f3eb;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(.selectedCell) {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.rich-text-editor__content :deep(.selectedCell::after) {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
background: rgb(43 63 78 / 12%);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.rich-text-editor__toolbar {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.rich-text-editor__select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
import { storeToRefs } from 'pinia'
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import RichTextEditor from '@/components/RichTextEditor.vue'
|
||||
import SiteHeader from '@/components/SiteHeader.vue'
|
||||
import { useElementsStore } from '@/stores/elements'
|
||||
|
||||
|
|
@ -325,15 +326,10 @@ function resetInput(changeEvent: Event): void {
|
|||
</p>
|
||||
</section>
|
||||
|
||||
<label class="admin-element-page__field">
|
||||
<span class="admin-element-page__label">Rich Text HTML</span>
|
||||
<textarea
|
||||
v-model="form.richText"
|
||||
class="admin-element-page__textarea admin-element-page__code"
|
||||
data-cy="admin-element-rich-text"
|
||||
rows="9"
|
||||
/>
|
||||
</label>
|
||||
<div class="admin-element-page__field">
|
||||
<span class="admin-element-page__label">Rich Text</span>
|
||||
<RichTextEditor v-model="form.richText" :disabled="isSaving" />
|
||||
</div>
|
||||
|
||||
<section class="admin-element-page__media-field">
|
||||
<span class="admin-element-page__label">Short PDF</span>
|
||||
|
|
@ -559,10 +555,6 @@ function resetInput(changeEvent: Event): void {
|
|||
resize: vertical;
|
||||
}
|
||||
|
||||
.admin-element-page__code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
.admin-element-page__icon-preview {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
|
|
|
|||
|
|
@ -352,11 +352,93 @@ function isShortYoutubeHost(hostname: string): boolean {
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(h2),
|
||||
.element-page__rich-text :deep(h3),
|
||||
.element-page__rich-text :deep(h4) {
|
||||
margin: 1.6rem 0 0.65rem;
|
||||
color: #2c2c2c;
|
||||
font-family: var(--font-serif);
|
||||
font-weight: 500;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(h2) {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(h3) {
|
||||
font-size: 1.45rem;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(h4) {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(ul),
|
||||
.element-page__rich-text :deep(ol) {
|
||||
margin: 0 0 1rem;
|
||||
padding-left: 1.45rem;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(li) {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(blockquote) {
|
||||
margin: 1.35rem 0;
|
||||
padding: 0.2rem 0 0.2rem 1.1rem;
|
||||
border-left: 3px solid var(--color-olive);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(strong) {
|
||||
color: #2c2c2c;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(mark) {
|
||||
padding: 0 0.16em;
|
||||
background: #fff3a7;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(a) {
|
||||
color: var(--color-slate);
|
||||
font-weight: 600;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.16em;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(hr) {
|
||||
margin: 1.5rem 0;
|
||||
border: 0;
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(.tableWrapper) {
|
||||
max-width: 100%;
|
||||
margin: 1.4rem 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(table) {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(th),
|
||||
.element-page__rich-text :deep(td) {
|
||||
min-width: 4rem;
|
||||
padding: 0.55rem 0.65rem;
|
||||
border: 1px solid var(--color-border);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.element-page__rich-text :deep(th) {
|
||||
background: #f6f3eb;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.element-page__youtube {
|
||||
aspect-ratio: 16 / 9;
|
||||
margin-top: 1.75rem;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue