From 24b0070909df9e60c9210243e2c055dd4fd1c283 Mon Sep 17 00:00:00 2001 From: Tilman Vatteroth Date: Tue, 21 Feb 2023 19:46:56 +0100 Subject: [PATCH] fix(cheatsheet): refactor cheatsheet to use app extensions as source Signed-off-by: Tilman Vatteroth --- frontend/cypress/e2e/helpDialog.spec.ts | 16 -- frontend/locales/en.json | 255 +++++++++++++++++- .../editor-page/app-bar/app-bar.tsx | 2 + .../app-bar/cheatsheet/category-accordion.tsx | 73 +++++ .../app-bar/cheatsheet/cheatsheet-button.tsx | 44 +++ .../cheatsheet/cheatsheet-entry-pane.tsx | 85 ++++++ .../cheatsheet/cheatsheet-modal-body.tsx | 65 +++++ .../cheatsheet.module.scss | 6 + .../app-bar/cheatsheet/entry-list.tsx | 50 ++++ .../cheatsheet/read-more-link-item.tsx | 29 ++ .../app-bar/cheatsheet/topic-selection.tsx | 49 ++++ .../use-components-from-app-extensions.tsx | 32 +++ .../app-bar/help-button/cheatsheet-line.tsx | 67 ----- .../help-button/cheatsheet-tab-content.tsx | 64 ----- .../app-bar/help-button/help-button.tsx | 16 +- .../app-bar/help-button/help-modal.tsx | 14 +- .../cheatsheet/cheatsheet-extension.ts | 30 +++ .../basic-markdown-syntax-app-extension.ts | 63 +++++ ...sic-markdown-syntax-markdown-extension.ts} | 4 +- .../bootstrap-icon-app-extension.ts | 19 ++ .../extensions/emoji/emoji-app-extension.ts | 24 ++ .../iframe-capsule-app-extension.ts | 24 ++ .../image-placeholder-app-extension.ts | 23 ++ .../table-of-contents-app-extension.ts | 32 +++ .../table-of-contents-markdown-extension.ts | 6 +- .../hooks/use-markdown-extensions.ts | 14 +- .../render-page/document-toc-sidebar.tsx | 2 +- frontend/src/extensions/base/app-extension.ts | 5 + .../abcjs/abcjs-app-extension.ts | 5 + .../alert/alert-app-extension.ts | 5 + .../asciinema/asciinema-app-extension.ts | 5 + .../blockquote/blockquote-app-extension.ts | 5 + .../csv/csv-table-app-extension.ts | 5 + .../flowchart/flowchart-app-extension.ts | 5 + .../gist/gist-app-extension.ts | 5 + .../graphviz/graphviz-app-extension.ts | 5 + .../highlighted-code-fence-app-extension.ts | 10 + .../katex/katex-app-extension.ts | 5 + .../extra-integrations/katex/katex-frame.tsx | 9 +- .../mermaid/mermaid-app-extension.ts | 5 + .../optional-app-extensions.ts | 14 +- .../plantuml/plantuml-app-extension.ts | 5 + .../spoiler/spoiler-app-extension.ts | 5 + .../task-list/create-checkbox-content.ts | 14 + .../event-emitting-task-list-checkbox.tsx | 7 +- .../task-list/find-check-box.ts | 34 +++ .../task-list/set-checkbox-in-cheatsheet.tsx | 31 +++ .../task-list/set-checkbox-in-editor.tsx | 50 +++- .../task-list-checkbox-app-extension.ts | 6 + .../task-list/use-set-checkbox-in-editor.tsx | 74 ----- .../vega-lite/vega-lite-app-extension.ts | 7 + .../vimeo/vimeo-app-extension.ts | 5 + .../youtube/youtube-app-extension.ts | 5 + 53 files changed, 1164 insertions(+), 275 deletions(-) delete mode 100644 frontend/cypress/e2e/helpDialog.spec.ts create mode 100644 frontend/src/components/editor-page/app-bar/cheatsheet/category-accordion.tsx create mode 100644 frontend/src/components/editor-page/app-bar/cheatsheet/cheatsheet-button.tsx create mode 100644 frontend/src/components/editor-page/app-bar/cheatsheet/cheatsheet-entry-pane.tsx create mode 100644 frontend/src/components/editor-page/app-bar/cheatsheet/cheatsheet-modal-body.tsx rename frontend/src/components/editor-page/app-bar/{help-button => cheatsheet}/cheatsheet.module.scss (76%) create mode 100644 frontend/src/components/editor-page/app-bar/cheatsheet/entry-list.tsx create mode 100644 frontend/src/components/editor-page/app-bar/cheatsheet/read-more-link-item.tsx create mode 100644 frontend/src/components/editor-page/app-bar/cheatsheet/topic-selection.tsx create mode 100644 frontend/src/components/editor-page/app-bar/cheatsheet/use-components-from-app-extensions.tsx delete mode 100644 frontend/src/components/editor-page/app-bar/help-button/cheatsheet-line.tsx delete mode 100644 frontend/src/components/editor-page/app-bar/help-button/cheatsheet-tab-content.tsx create mode 100644 frontend/src/components/editor-page/cheatsheet/cheatsheet-extension.ts create mode 100644 frontend/src/components/markdown-renderer/extensions/basic-markdown-syntax/basic-markdown-syntax-app-extension.ts rename frontend/src/components/markdown-renderer/extensions/{generic-syntax-markdown-extension.ts => basic-markdown-syntax/basic-markdown-syntax-markdown-extension.ts} (84%) create mode 100644 frontend/src/components/markdown-renderer/extensions/bootstrap-icons/bootstrap-icon-app-extension.ts create mode 100644 frontend/src/components/markdown-renderer/extensions/emoji/emoji-app-extension.ts create mode 100644 frontend/src/components/markdown-renderer/extensions/iframe-capsule/iframe-capsule-app-extension.ts create mode 100644 frontend/src/components/markdown-renderer/extensions/image-placeholder/image-placeholder-app-extension.ts create mode 100644 frontend/src/components/markdown-renderer/extensions/table-of-contents/table-of-contents-app-extension.ts rename frontend/src/components/markdown-renderer/extensions/{ => table-of-contents}/table-of-contents-markdown-extension.ts (81%) create mode 100644 frontend/src/extensions/extra-integrations/task-list/create-checkbox-content.ts create mode 100644 frontend/src/extensions/extra-integrations/task-list/find-check-box.ts create mode 100644 frontend/src/extensions/extra-integrations/task-list/set-checkbox-in-cheatsheet.tsx delete mode 100644 frontend/src/extensions/extra-integrations/task-list/use-set-checkbox-in-editor.tsx diff --git a/frontend/cypress/e2e/helpDialog.spec.ts b/frontend/cypress/e2e/helpDialog.spec.ts deleted file mode 100644 index a709ad497..000000000 --- a/frontend/cypress/e2e/helpDialog.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -describe('Help Dialog', () => { - beforeEach(() => { - cy.visitTestNote() - }) - - it('ToDo-List', () => { - cy.getByCypressId('editor-help-button').click() - cy.get('input[type="checkbox"]').should('exist').should('not.be.checked') - }) -}) diff --git a/frontend/locales/en.json b/frontend/locales/en.json index f587d4ac3..a3fbd8a73 100644 --- a/frontend/locales/en.json +++ b/frontend/locales/en.json @@ -267,13 +267,6 @@ "features": "Features", "yamlMetadata": "YAML Metadata", "slideExample": "Slide Example" - }, - "cheatsheet": { - "title": "Cheatsheet", - "example": "Example", - "syntax": "Syntax", - "exampleAlert": "This is an alert area.", - "highlightedText": "Highlight" } }, "onlineStatus": { @@ -630,5 +623,253 @@ "help": "The primary user interface language" } } + }, + "cheatsheet": { + "button": "Open Cheatsheet", + "modal":{ + "title": "Cheatsheet", + "headlines": { + "description": "Description", + "exampleInput": "Example Input", + "exampleOutput": "Example Output", + "selectTopic": "Select Topic", + "readMoreLink": "Read More" + }, + "noSelection": "Select an entry on the left side to show the instructions." + }, + "categories": { + "basic": "Basics", + "other": "Other", + "embedding": "Embedding", + "charts": "Charts & Diagrams" + }, + "basics": { + "basicFormatting": { + "title": "Basic", + "description": "These are the basic markdown formatting rules.", + "example": "**Bold**\n__Bold__\n\n*Italic*\n_Italic_\n\n++Underline++\n~~Strikethrough~~\n\nSub~script~\n\nSuper^script^\n\n==Marked==" + }, + "abbreviation": { + "title": "Abbreviation", + "description": "Abbreviation definitions create tooltips for matching words. They can be placed defined in the document.", + "example": "*[HTML]: Hyper Text Markup Language\n*[W3C]: World Wide Web Consortium\nThe HTML specification\nis maintained by the W3C." + }, + "footnote": { + "title": "Footnotes", + "description": "Footnotes can be used to add extra information at the bottom of the page. They can be defined anywhere in the document.", + "example": "Here is a footnote reference,[^1] and another.[^longnote]\n\n[^1]: Here is the footnote.\n\n[^longnote]: Here's one with multiple blocks. Subsequent paragraphs are indented to show that they belong to the previous footnote." + }, + "headlines": { + "title": "Headlines", + "hashtag": { + "title": "Hashtag", + "description": "Headlines can be used to structure your document into sections. Every headline creates a linkable anchor.", + "example": "# Headline 1\n\n## Headline 2\n\n### Headline 3\n\n#### Headline 4\n\n##### Headline 5\n\n###### Headline 6" + }, + "equal": { + "title": "Equals sign", + "description": "An alternative form for the first and second level headline is to append a line of only equals signs or dashes after the headline text. ", + "example": "Headline 1\n==========\n\nHeadline 2\n----------" + } + }, + "code": { + "title": "Code", + "inline": { + "title": "Inline", + "description": "You can define an inline code block by wrapping it in backticks.", + "example": "This is `code`." + }, + "block": { + "title": "Block", + "description": "You can define a code block by putting a line of three backticks before and after the code part.\n\nIt is also possible to define a language for syntax highlighting. For more information check the entry \"Other > Code Highlighting\"", + "example": "```\nthis is a code block\n```" + } + }, + "lists": { + "title": "Lists", + "unordered": { + "title": "Unordered", + "description": "You can create unordered lists by prepending lines with dashes or asterisks.", + "example": "- A\n- B\n- C\n\n* A\n* B\n* C" + }, + "ordered": { + "title": "Ordered", + "description": "You can create ordered lists by prepending lines with numbers followed by a dot. Ordered lists will always start with one. Ordered lists that aren't separated by another element will continue the last list.", + "example": "1. A\n2. B\n3. C\n\n\n4. D\n5. E\n\nText\n\n100. A\n101. B\n102. C" + } + }, + "images": { + "title": "Images", + "basic": { + "title": "Basic", + "description": "Images can be defined using the link syntax with an exclamation mark in front of it. The text in the brackets will be used as alt-text.", + "example": "![This is an icon](/icons/apple-touch-icon.png)" + }, + "size": { + "title": "Size", + "description": "The size syntax allows you to set both dimensions of an image. If you omit one of the dimensions then image will be scaled to the relative size.", + "example": "![Image](/icons/apple-touch-icon.png =100x50)\n\n![Image](/icons/apple-touch-icon.png =60x)\n\n![Image](/icons/apple-touch-icon.png =x50)" + } + }, + "links": { + "title": "Links", + "description": "You can create text links by either using the link syntax, by writing the plain URL or by writing it in angle brackets.", + "example": "[Example link](https://example.org)\n\nhttps://example.org\n\n" + } + }, + "abcjs": { + "title": "abcjs", + "description": "You can render music sheets with abcjs by using music standard notation in a codeblock with `abc` as language.", + "example": "```abc\nX:1\nT:Speed the Plough\nM:4/4\nC:Trad.\nK:G\n|:GABc dedB|dedB dedB|c2ec B2dB|c2A2 A2BA|\nGABc dedB|dedB dedB|c2ec B2dB|A2F2 G4:|\n|:g2gf gdBd|g2f2 e2d2|c2ec B2dB|c2A2 A2df|\ng2gf g2Bd|g2f2 e2d2|c2ec B2dB|A2F2 G4:|\n```" + }, + "alert": { + "title": "Alert boxes", + "description": "Use alert boxes to bring extra attention to parts of your document.", + "example": ":::success\nThis is a success\n:::\n\n:::danger\nThis is a danger\n:::\n\n:::warning\nThis is a warning\n:::\n\n:::info\nThis is a info\n:::" + }, + "blockquoteTags": { + "name": { + "title": "Name", + "description": "Use name tags to indicate who wrote a specific quote e.g. if you're commenting on the text.", + "example": "> Imagination is more important than knowledge.\n> [name=Albert Einstein]" + }, + "color": { + "title": "Color", + "description": "Use color tags to tint the border of the quote.", + "example": "> This is the default color\n\n> This is red! [color=red]\n\n> This is blue! [color=#0000ff]" + }, + "time": { + "title": "Time", + "description": "Use time tags to specify when a time stamp", + "example": "The password is: changeme\n\n> Please change it ASAP [time=2020-03-05]" + }, + "title": "Blockquote Tags", + "description": "Use name, time or color tags to specify your blockquotes. Color tags modify the border color.", + "example": "> [name=Max] Named quote\n\n> [time=today] Time quote\n\n> [color=red] quote\n\n> [name=Max] [color=green] [time=today] Combined quote" + }, + "bootstrapIcon": { + "title": "Bootstrap Icons", + "description": "You can use bootstrap icons in your document by putting the name of an icon between colons but prefixed with `bi-`. A listing of all bootstrap icons can be found on their website.", + "example": ":bi-music-note-beamed::bi-music-note-beamed::bi-music-note-beamed:\nAround the :bi-globe-americas:\nAround the :bi-globe-asia-australia:\nAround the :bi-globe-central-south-asia:\nAround the :bi-globe-europe-africa:" + }, + "emoji": { + "title": "Emojis", + "description": "You can add colored emojis by either placing the unicode character or by using a shortcode. HedgeDoc supports every emoji that Twemoji supports. You can also use the emoji picker in the editor toolbar.", + "example": "I :heart: :hedgehog:" + }, + "csv": { + "title" : "CSV", + "table" : { + "title": "Table", + "description" : "You can render a CSV text as table by using a code block with `csv` as language. You must specify the delimiter.", + "example" : "```csv delimiter=;\nUsername; Identifier;First name;Last name\n\"booker12; rbooker\";9012;Rachel;Booker\ngrey07;2070;Laura;Grey\njohnson81;4081;Craig;Johnson\njenkins46;9346;Mary;Jenkins\nsmith79;5079;Jamie;Smith\n```" + }, + "header": { + "title": "Header", + "description": "By adding the header keyword you can define that the first line is used as table header", + "example": "```csv delimiter=; header\nUsername; Identifier;First name;Last name\n\"booker12; rbooker\";9012;Rachel;Booker\ngrey07;2070;Laura;Grey\njohnson81;4081;Craig;Johnson\njenkins46;9346;Mary;Jenkins\nsmith79;5079;Jamie;Smith\n```" + } + }, + "flowchart": { + "title": "flowchart.js", + "description": "Render flowcharts diagrams using flowchart.js by using a code block with `flow` as language.", + "example": "```flow\nst=>start: Start\ne=>end: End\nop=>operation: My Operation\nop2=>operation: lalala\ncond=>condition: Yes or No?\n\nst->op->op2->cond\ncond(yes)->e\ncond(no)->op2\n```" + }, + "gist": { + "title": "GitHub Gist", + "description": "Embed GitHub Gists by placing a gist URL on a single line.", + "example": "# This is my gist\nhttps://gist.github.com/schacon/1\nThis is just the link to a gist: https://gist.github.com/schacon/1\n[Using the link tag will also not trigger the embedding](https://gist.github.com/schacon/1)" + }, + "graphviz": { + "title": "GraphViz", + "description": "Render GraphViz diagrams by using the DOT language in a code block with `graphviz` as language.", + "example": "```graphviz\ngraph {\n a -- b\n a -- b\n b -- a [color=blue]\n}\n```" + }, + "katex": { + "title": "KaTeX", + "description": "You can render LaTeX mathematical expressions using KaTeX by encapsulating them in dollar signs.", + "example": "The *Gamma function* satisfying $\\Gamma(n) = (n-1)!\\quad\\forall n\\in\\mathbb N$ is via the Euler integral\n\n$$\nx = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.\n$$\n\n$$\n\\Gamma(z) = \\int_0^\\infty t^{z-1}e^{-t}dt\\,.\n$$" + }, + "asciinema": { + "title": "Asciinema", + "description": "Embed an Asciinema video by placing the URL in a single line.", + "example": "https://asciinema.org/a/117928\n" + }, + "mermaid": { + "title": "Mermaid", + "description": "Render diagrams and charts using mermaid.js by adding a code block with the language `mermaid`", + "example": "```mermaid\ngantt\n title A Gantt Diagram\n\n section Section\n A task: a1, 2014-01-01, 30d\n Another task: after a1, 20d\n\n section Another\n Task in sec: 2014-01-12, 12d\n Another task: 24d\n```" + }, + "imagePlaceholder": { + "title": "Image Placeholder", + "description": "You can use image placeholders to indicate spots where images should be placed. To do this use an image link with `https://` as URL. You can upload the actual image directly from the renderer. Placeholders also support size definition, alt text and title.", + "example": "![This is a placeholder image](https://)" + }, + "iframeCapsule": { + "title": "Iframe capsule", + "description": "To protect viewers every iframe has to be activated explicitly. Before this, no information is fetched. Adding additional privileges using the sandbox attribute is not allowed.", + "example": "" + }, + "plantuml": { + "title": "PlantUML", + "description": "Render diagrams and charts using PlantUML by adding a code block with the language `plantuml`. PlantUML diagrams are not rendered in your browser like the other charts, but by an external server.", + "example": "```plantuml\n@startuml\nparticipant Alice\nparticipant \"The **Famous** Bob\" as Bob\n\nAlice -> Bob : hello --there--\n... Some ~~long delay~~ ...\nBob -> Alice : ok\nnote left\n This is **bold**\n This is //italics//\n This is \"\"monospaced\"\"\n This is --stroked--\n This is __underlined__\n This is ~~waved~~\nend note\n\nAlice -> Bob : A //well formatted// message\nnote right of Alice\n This is displayed\n __left of__ Alice.\nend note\nnote left of Bob\n This is displayed\n **left of Alice Bob**.\nend note\nnote over Alice, Bob\n This is hosted by \nend note\n@enduml\n```" + }, + "spoiler": { + "title": "Spoiler", + "description": "Hide information by using a spoiler tag.", + "example": ":::spoiler This spoiler contains a surprise.\nSURPRISE!\n:::" + }, + "toc": { + "title": "Table Of Contents", + "basic": { + "title": "Basic", + "description": "Add a table of contents that is automatically generated using your headlines by adding `[toc]` into a single line.", + "example": "[toc]\n\n# This is a first headline\n\n## This is a second headline" + }, + "levelLimit": { + "title": "Level limits", + "description": "You can limit the levels of the headlines the TOC should show", + "example": "[toc:2:3]\n\n# This is a first headline\n\n## This is a second headline\n\n### This is a third headline\n\n#### This is a fourth headline" + } + }, + "vegaLite": { + "title": "Vega Lite", + "description": "Render diagrams and charts using vega lite by adding a code block with the language `vega-lite`", + "example": "```vega-lite\n{\n \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.json\",\n \"description\": \"Reproducing http://robslink.com/SAS/democd91/pyramid_pie.htm\",\n \"data\": {\n \"values\": [\n {\"category\": \"Sky\", \"value\": 75, \"order\": 3},\n {\"category\": \"Shady side of a pyramid\", \"value\": 10, \"order\": 1},\n {\"category\": \"Sunny side of a pyramid\", \"value\": 15, \"order\": 2}\n ]\n },\n \"mark\": {\"type\": \"arc\", \"outerRadius\": 80},\n \"encoding\": {\n \"theta\": {\n \"field\": \"value\", \"type\": \"quantitative\",\n \"scale\": {\"range\": [2.35619449, 8.639379797]},\n \"stack\": true\n },\n \"color\": {\n \"field\": \"category\", \"type\": \"nominal\",\n \"scale\": {\n \"domain\": [\"Sky\", \"Shady side of a pyramid\", \"Sunny side of a pyramid\"],\n \"range\": [\"#416D9D\", \"#674028\", \"#DEAC58\"]\n },\n \"legend\": {\n \"orient\": \"none\",\n \"title\": null,\n \"columns\": 1,\n \"legendX\": 200,\n \"legendY\": 80\n }\n },\n \"order\": {\n \"field\": \"order\"\n }\n },\n \"view\": {\"stroke\": null}\n}\n```" + }, + "vimeo": { + "title": "Vimeo", + "description": "Embed a Vimeo video by placing the URL in a single line.", + "example": "https://vimeo.com/23237102" + }, + "youtube": { + "title": "YouTube", + "description": "Embed a YouTube video by placing the URL in a single line.", + "example": "https://www.youtube.com/watch?v=YE7VzlLtp-4" + }, + "taskList": { + "title": "Task Lists", + "description": "You can turn any listing into a task list by adding brackets. The checkboxes in the rendering change the markdown content if clicked.", + "example": "- [ ] ToDos\n - [X] Buy some salad\n - [ ] Brush teeth\n - [x] Drink some water\n - [ ] **Click my box** and see the source code, if you're allowed to edit!\n" + }, + "codeHighlighting": { + "title": "Code Highlighting", + "language": { + "title": "Language", + "description": "Specify a language after the start tag of a code block to activate code highlighting.", + "example": "```js\nvar s = \"JavaScript syntax highlighting\";\nalert(s);\nfunction $initHighlight(block, cls) {\n try {\n if (cls.search(/\\bno\\-highlight\\b/) != -1)\n return process(block, true, 0x0F) +\n ' class=\"\"';\n } catch (e) {\n /* handle exception */\n }\n for (var i = 0 / 2; i < classes.length; i++) {\n if (checkCondition(classes[i]) === undefined)\n return /\\d+[\\s/]/g;\n }\n}\n```" + }, + "lineWrapping": { + "title": "Line wrapping", + "description": "Set an exclamation mark to activate line wrapping", + "example": "```text\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n```\n\n```text!\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n```" + }, + "lineNumbers": { + "title": "Line numbers", + "description": "Set a equals sign after the language to show line numbers. You can specify a start line number after the equal sign or a plus to continue the line numbers from the last code block.", + "example": "```markdown=12\nline1\n```\n```markdown=+\nline2\n```\n```markdown=\nline3\n```" + } + } } } diff --git a/frontend/src/components/editor-page/app-bar/app-bar.tsx b/frontend/src/components/editor-page/app-bar/app-bar.tsx index 8a82673c4..b692a8be5 100644 --- a/frontend/src/components/editor-page/app-bar/app-bar.tsx +++ b/frontend/src/components/editor-page/app-bar/app-bar.tsx @@ -10,6 +10,7 @@ import { ShowIf } from '../../common/show-if/show-if' import { SignInButton } from '../../landing-layout/navigation/sign-in-button' import { UserDropdown } from '../../landing-layout/navigation/user-dropdown' import { SettingsButton } from '../../layout/settings-dialog/settings-button' +import { CheatsheetButton } from './cheatsheet/cheatsheet-button' import { HelpButton } from './help-button/help-button' import { NavbarBranding } from './navbar-branding' import { ReadOnlyModeButton } from './read-only-mode-button' @@ -47,6 +48,7 @@ export const AppBar: React.FC = ({ mode }) => { +