Adjust editor config (#976)

* Adjust editor config

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
Co-authored-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Tilman Vatteroth 2021-02-03 22:13:04 +01:00 committed by GitHub
parent 0180c75e55
commit e12dc523f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
301 changed files with 4393 additions and 3741 deletions

View file

@ -57,6 +57,14 @@ ij_scss_space_before_opening_brace = true
ij_scss_use_double_quotes = true ij_scss_use_double_quotes = true
ij_scss_value_alignment = 0 ij_scss_value_alignment = 0
[.editorconfig]
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
ij_editorconfig_space_after_comma = true
ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.ats, *.ts, *.tsx}] [{*.ats, *.ts, *.tsx}]
indent_size = 2 indent_size = 2
tab_width = 2 tab_width = 2
@ -64,18 +72,18 @@ ij_continuation_indent_size = 2
ij_typescript_align_imports = false ij_typescript_align_imports = false
ij_typescript_align_multiline_array_initializer_expression = false ij_typescript_align_multiline_array_initializer_expression = false
ij_typescript_align_multiline_binary_operation = false ij_typescript_align_multiline_binary_operation = false
ij_typescript_align_multiline_chained_methods = false ij_typescript_align_multiline_chained_methods = true
ij_typescript_align_multiline_extends_list = false ij_typescript_align_multiline_extends_list = false
ij_typescript_align_multiline_for = true ij_typescript_align_multiline_for = true
ij_typescript_align_multiline_parameters = true ij_typescript_align_multiline_parameters = false
ij_typescript_align_multiline_parameters_in_calls = false ij_typescript_align_multiline_parameters_in_calls = false
ij_typescript_align_multiline_ternary_operation = false ij_typescript_align_multiline_ternary_operation = false
ij_typescript_align_object_properties = 0 ij_typescript_align_object_properties = 0
ij_typescript_align_union_types = false ij_typescript_align_union_types = true
ij_typescript_align_var_statements = 0 ij_typescript_align_var_statements = 0
ij_typescript_array_initializer_new_line_after_left_brace = false ij_typescript_array_initializer_new_line_after_left_brace = false
ij_typescript_array_initializer_right_brace_on_new_line = false ij_typescript_array_initializer_right_brace_on_new_line = false
ij_typescript_array_initializer_wrap = off ij_typescript_array_initializer_wrap = normal
ij_typescript_assignment_wrap = off ij_typescript_assignment_wrap = off
ij_typescript_binary_operation_sign_on_next_line = false ij_typescript_binary_operation_sign_on_next_line = false
ij_typescript_binary_operation_wrap = off ij_typescript_binary_operation_wrap = off
@ -95,26 +103,26 @@ ij_typescript_catch_on_new_line = false
ij_typescript_chained_call_dot_on_new_line = true ij_typescript_chained_call_dot_on_new_line = true
ij_typescript_class_brace_style = end_of_line ij_typescript_class_brace_style = end_of_line
ij_typescript_comma_on_new_line = false ij_typescript_comma_on_new_line = false
ij_typescript_do_while_brace_force = never ij_typescript_do_while_brace_force = always
ij_typescript_else_on_new_line = false ij_typescript_else_on_new_line = false
ij_typescript_enforce_trailing_comma = keep ij_typescript_enforce_trailing_comma = remove
ij_typescript_extends_keyword_wrap = off ij_typescript_extends_keyword_wrap = off
ij_typescript_extends_list_wrap = off ij_typescript_extends_list_wrap = off
ij_typescript_field_prefix = _ ij_typescript_field_prefix = _
ij_typescript_file_name_style = relaxed ij_typescript_file_name_style = relaxed
ij_typescript_finally_on_new_line = false ij_typescript_finally_on_new_line = false
ij_typescript_for_brace_force = never ij_typescript_for_brace_force = always
ij_typescript_for_statement_new_line_after_left_paren = false ij_typescript_for_statement_new_line_after_left_paren = false
ij_typescript_for_statement_right_paren_on_new_line = false ij_typescript_for_statement_right_paren_on_new_line = false
ij_typescript_for_statement_wrap = off ij_typescript_for_statement_wrap = off
ij_typescript_force_quote_style = false ij_typescript_force_quote_style = true
ij_typescript_force_semicolon_style = true ij_typescript_force_semicolon_style = true
ij_typescript_function_expression_brace_style = end_of_line ij_typescript_function_expression_brace_style = end_of_line
ij_typescript_if_brace_force = never ij_typescript_if_brace_force = always
ij_typescript_import_merge_members = global ij_typescript_import_merge_members = global
ij_typescript_import_prefer_absolute_path = global ij_typescript_import_prefer_absolute_path = global
ij_typescript_import_sort_members = true ij_typescript_import_sort_members = true
ij_typescript_import_sort_module_name = true ij_typescript_import_sort_module_name = false
ij_typescript_import_use_node_resolution = true ij_typescript_import_use_node_resolution = true
ij_typescript_imports_wrap = on_every_item ij_typescript_imports_wrap = on_every_item
ij_typescript_indent_case_from_switch = true ij_typescript_indent_case_from_switch = true
@ -122,7 +130,7 @@ ij_typescript_indent_chained_calls = true
ij_typescript_indent_package_children = 0 ij_typescript_indent_package_children = 0
ij_typescript_jsdoc_include_types = false ij_typescript_jsdoc_include_types = false
ij_typescript_jsx_attribute_value = braces ij_typescript_jsx_attribute_value = braces
ij_typescript_keep_blank_lines_in_code = 1 ij_typescript_keep_blank_lines_in_code = 2
ij_typescript_keep_first_column_comment = true ij_typescript_keep_first_column_comment = true
ij_typescript_keep_indents_on_empty_lines = false ij_typescript_keep_indents_on_empty_lines = false
ij_typescript_keep_line_breaks = true ij_typescript_keep_line_breaks = true
@ -131,11 +139,11 @@ ij_typescript_keep_simple_methods_in_one_line = false
ij_typescript_line_comment_add_space = true ij_typescript_line_comment_add_space = true
ij_typescript_line_comment_at_first_column = false ij_typescript_line_comment_at_first_column = false
ij_typescript_method_brace_style = end_of_line ij_typescript_method_brace_style = end_of_line
ij_typescript_method_call_chain_wrap = off ij_typescript_method_call_chain_wrap = split_into_lines
ij_typescript_method_parameters_new_line_after_left_paren = false ij_typescript_method_parameters_new_line_after_left_paren = false
ij_typescript_method_parameters_right_paren_on_new_line = false ij_typescript_method_parameters_right_paren_on_new_line = false
ij_typescript_method_parameters_wrap = off ij_typescript_method_parameters_wrap = off
ij_typescript_object_literal_wrap = on_every_item ij_typescript_object_literal_wrap = off
ij_typescript_parentheses_expression_new_line_after_left_paren = false ij_typescript_parentheses_expression_new_line_after_left_paren = false
ij_typescript_parentheses_expression_right_paren_on_new_line = false ij_typescript_parentheses_expression_right_paren_on_new_line = false
ij_typescript_place_assignment_sign_on_next_line = false ij_typescript_place_assignment_sign_on_next_line = false
@ -144,7 +152,7 @@ ij_typescript_prefer_explicit_types_function_expression_returns = false
ij_typescript_prefer_explicit_types_function_returns = false ij_typescript_prefer_explicit_types_function_returns = false
ij_typescript_prefer_explicit_types_vars_fields = false ij_typescript_prefer_explicit_types_vars_fields = false
ij_typescript_prefer_parameters_wrap = false ij_typescript_prefer_parameters_wrap = false
ij_typescript_reformat_c_style_comments = false ij_typescript_reformat_c_style_comments = true
ij_typescript_space_after_colon = true ij_typescript_space_after_colon = true
ij_typescript_space_after_comma = true ij_typescript_space_after_comma = true
ij_typescript_space_after_dots_in_rest_parameter = false ij_typescript_space_after_dots_in_rest_parameter = false
@ -175,7 +183,7 @@ ij_typescript_space_before_if_left_brace = true
ij_typescript_space_before_if_parentheses = true ij_typescript_space_before_if_parentheses = true
ij_typescript_space_before_method_call_parentheses = false ij_typescript_space_before_method_call_parentheses = false
ij_typescript_space_before_method_left_brace = true ij_typescript_space_before_method_left_brace = true
ij_typescript_space_before_method_parentheses = true ij_typescript_space_before_method_parentheses = false
ij_typescript_space_before_property_colon = false ij_typescript_space_before_property_colon = false
ij_typescript_space_before_quest = true ij_typescript_space_before_quest = true
ij_typescript_space_before_switch_left_brace = true ij_typescript_space_before_switch_left_brace = true
@ -202,7 +210,7 @@ ij_typescript_spaces_within_catch_parentheses = false
ij_typescript_spaces_within_for_parentheses = false ij_typescript_spaces_within_for_parentheses = false
ij_typescript_spaces_within_if_parentheses = false ij_typescript_spaces_within_if_parentheses = false
ij_typescript_spaces_within_imports = true ij_typescript_spaces_within_imports = true
ij_typescript_spaces_within_interpolation_expressions = false ij_typescript_spaces_within_interpolation_expressions = true
ij_typescript_spaces_within_method_call_parentheses = false ij_typescript_spaces_within_method_call_parentheses = false
ij_typescript_spaces_within_method_parentheses = false ij_typescript_spaces_within_method_parentheses = false
ij_typescript_spaces_within_object_literal_braces = true ij_typescript_spaces_within_object_literal_braces = true
@ -215,15 +223,15 @@ ij_typescript_spaces_within_while_parentheses = false
ij_typescript_special_else_if_treatment = true ij_typescript_special_else_if_treatment = true
ij_typescript_ternary_operation_signs_on_next_line = false ij_typescript_ternary_operation_signs_on_next_line = false
ij_typescript_ternary_operation_wrap = off ij_typescript_ternary_operation_wrap = off
ij_typescript_union_types_wrap = on_every_item ij_typescript_union_types_wrap = normal
ij_typescript_use_chained_calls_group_indents = false ij_typescript_use_chained_calls_group_indents = false
ij_typescript_use_double_quotes = false ij_typescript_use_double_quotes = false
ij_typescript_use_explicit_js_extension = global ij_typescript_use_explicit_js_extension = global
ij_typescript_use_path_mapping = always ij_typescript_use_path_mapping = always
ij_typescript_use_public_modifier = false ij_typescript_use_public_modifier = false
ij_typescript_use_semicolon_after_statement = false ij_typescript_use_semicolon_after_statement = false
ij_typescript_var_declaration_wrap = normal ij_typescript_var_declaration_wrap = on_every_item
ij_typescript_while_brace_force = never ij_typescript_while_brace_force = always
ij_typescript_while_on_new_line = false ij_typescript_while_on_new_line = false
ij_typescript_wrap_comments = false ij_typescript_wrap_comments = false
@ -275,8 +283,8 @@ ij_javascript_for_brace_force = never
ij_javascript_for_statement_new_line_after_left_paren = false ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off ij_javascript_for_statement_wrap = off
ij_javascript_force_quote_style = true ij_javascript_force_quote_style = false
ij_javascript_force_semicolon_style = true ij_javascript_force_semicolon_style = false
ij_javascript_function_expression_brace_style = end_of_line ij_javascript_function_expression_brace_style = end_of_line
ij_javascript_if_brace_force = never ij_javascript_if_brace_force = never
ij_javascript_import_merge_members = global ij_javascript_import_merge_members = global
@ -289,12 +297,12 @@ ij_javascript_indent_case_from_switch = true
ij_javascript_indent_chained_calls = true ij_javascript_indent_chained_calls = true
ij_javascript_indent_package_children = 0 ij_javascript_indent_package_children = 0
ij_javascript_jsx_attribute_value = braces ij_javascript_jsx_attribute_value = braces
ij_javascript_keep_blank_lines_in_code = 1 ij_javascript_keep_blank_lines_in_code = 2
ij_javascript_keep_first_column_comment = true ij_javascript_keep_first_column_comment = true
ij_javascript_keep_indents_on_empty_lines = false ij_javascript_keep_indents_on_empty_lines = false
ij_javascript_keep_line_breaks = true ij_javascript_keep_line_breaks = true
ij_javascript_keep_simple_blocks_in_one_line = true ij_javascript_keep_simple_blocks_in_one_line = false
ij_javascript_keep_simple_methods_in_one_line = true ij_javascript_keep_simple_methods_in_one_line = false
ij_javascript_line_comment_add_space = true ij_javascript_line_comment_add_space = true
ij_javascript_line_comment_at_first_column = false ij_javascript_line_comment_at_first_column = false
ij_javascript_method_brace_style = end_of_line ij_javascript_method_brace_style = end_of_line
@ -337,12 +345,12 @@ ij_javascript_space_before_for_left_brace = true
ij_javascript_space_before_for_parentheses = true ij_javascript_space_before_for_parentheses = true
ij_javascript_space_before_for_semicolon = false ij_javascript_space_before_for_semicolon = false
ij_javascript_space_before_function_left_parenth = true ij_javascript_space_before_function_left_parenth = true
ij_javascript_space_before_generator_mult = true ij_javascript_space_before_generator_mult = false
ij_javascript_space_before_if_left_brace = true ij_javascript_space_before_if_left_brace = true
ij_javascript_space_before_if_parentheses = true ij_javascript_space_before_if_parentheses = true
ij_javascript_space_before_method_call_parentheses = false ij_javascript_space_before_method_call_parentheses = false
ij_javascript_space_before_method_left_brace = true ij_javascript_space_before_method_left_brace = true
ij_javascript_space_before_method_parentheses = true ij_javascript_space_before_method_parentheses = false
ij_javascript_space_before_property_colon = false ij_javascript_space_before_property_colon = false
ij_javascript_space_before_quest = true ij_javascript_space_before_quest = true
ij_javascript_space_before_switch_left_brace = true ij_javascript_space_before_switch_left_brace = true
@ -368,11 +376,11 @@ ij_javascript_spaces_within_brackets = false
ij_javascript_spaces_within_catch_parentheses = false ij_javascript_spaces_within_catch_parentheses = false
ij_javascript_spaces_within_for_parentheses = false ij_javascript_spaces_within_for_parentheses = false
ij_javascript_spaces_within_if_parentheses = false ij_javascript_spaces_within_if_parentheses = false
ij_javascript_spaces_within_imports = true ij_javascript_spaces_within_imports = false
ij_javascript_spaces_within_interpolation_expressions = false ij_javascript_spaces_within_interpolation_expressions = false
ij_javascript_spaces_within_method_call_parentheses = false ij_javascript_spaces_within_method_call_parentheses = false
ij_javascript_spaces_within_method_parentheses = false ij_javascript_spaces_within_method_parentheses = false
ij_javascript_spaces_within_object_literal_braces = true ij_javascript_spaces_within_object_literal_braces = false
ij_javascript_spaces_within_object_type_braces = true ij_javascript_spaces_within_object_type_braces = true
ij_javascript_spaces_within_parentheses = false ij_javascript_spaces_within_parentheses = false
ij_javascript_spaces_within_switch_parentheses = false ij_javascript_spaces_within_switch_parentheses = false
@ -380,22 +388,22 @@ ij_javascript_spaces_within_type_assertion = false
ij_javascript_spaces_within_union_types = true ij_javascript_spaces_within_union_types = true
ij_javascript_spaces_within_while_parentheses = false ij_javascript_spaces_within_while_parentheses = false
ij_javascript_special_else_if_treatment = true ij_javascript_special_else_if_treatment = true
ij_javascript_ternary_operation_signs_on_next_line = true ij_javascript_ternary_operation_signs_on_next_line = false
ij_javascript_ternary_operation_wrap = off ij_javascript_ternary_operation_wrap = off
ij_javascript_union_types_wrap = on_every_item ij_javascript_union_types_wrap = on_every_item
ij_javascript_use_chained_calls_group_indents = false ij_javascript_use_chained_calls_group_indents = false
ij_javascript_use_double_quotes = false ij_javascript_use_double_quotes = true
ij_javascript_use_explicit_js_extension = global ij_javascript_use_explicit_js_extension = global
ij_javascript_use_path_mapping = always ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = false ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = never ij_javascript_while_brace_force = never
ij_javascript_while_on_new_line = false ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false ij_javascript_wrap_comments = false
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}] [{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}]
indent_size = 4 indent_size = 2
ij_json_keep_blank_lines_in_code = 0 ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true ij_json_keep_line_breaks = true
@ -433,9 +441,30 @@ ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal ij_html_text_wrap = normal
ij_html_uniform_ident = false
[{*.markdown, *.md}]
ij_markdown_force_one_space_after_blockquote_symbol = true
ij_markdown_force_one_space_after_header_symbol = true
ij_markdown_force_one_space_after_list_bullet = true
ij_markdown_force_one_space_between_words = true
ij_markdown_keep_indents_on_empty_lines = false
ij_markdown_max_lines_around_block_elements = 1
ij_markdown_max_lines_around_header = 1
ij_markdown_max_lines_between_paragraphs = 1
ij_markdown_min_lines_around_block_elements = 1
ij_markdown_min_lines_around_header = 1
ij_markdown_min_lines_between_paragraphs = 1
[{*.yaml, *.yml}] [{*.yaml, *.yml}]
indent_size = 2 indent_size = 2
ij_yaml_align_values_properties = do_not_align
ij_yaml_autoinsert_sequence_marker = true
ij_yaml_block_mapping_on_new_line = false
ij_yaml_indent_sequence_value = true
ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true ij_yaml_keep_line_breaks = true
ij_yaml_sequence_on_new_line = false
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true

View file

@ -24,7 +24,9 @@ describe('Banner', () => {
.find('.fa-times') .find('.fa-times')
.click() .click()
.then(() => { .then(() => {
expect(localStorage.getItem('bannerTimeStamp')).to.equal(banner.timestamp) expect(localStorage.getItem('bannerTimeStamp'))
.to
.equal(banner.timestamp)
}) })
cy.get('.alert-primary.show') cy.get('.alert-primary.show')
.should('not.exist') .should('not.exist')

View file

@ -49,28 +49,33 @@ describe('File upload', () => {
}) })
it('via paste', () => { it('via paste', () => {
cy.fixture('acme.png').then((image: string) => { cy.fixture('acme.png')
.then((image: string) => {
const pasteEvent = { const pasteEvent = {
clipboardData: { clipboardData: {
files: [Cypress.Blob.base64StringToBlob(image, 'image/png')] files: [Cypress.Blob.base64StringToBlob(image, 'image/png')]
} }
} }
cy.get('.CodeMirror-scroll').trigger('paste', pasteEvent) cy.get('.CodeMirror-scroll')
.trigger('paste', pasteEvent)
cy.get('.CodeMirror-activeline > .CodeMirror-line > span') cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
.should('have.text', `![](${ imageUrl })`) .should('have.text', `![](${ imageUrl })`)
}) })
}) })
it('via drag and drop', () => { it('via drag and drop', () => {
cy.fixture('acme.png').then((image: string) => { cy.fixture('acme.png')
.then((image: string) => {
const dropEvent = { const dropEvent = {
dataTransfer: { dataTransfer: {
files: [Cypress.Blob.base64StringToBlob(image, 'image/png')], files: [Cypress.Blob.base64StringToBlob(image, 'image/png')],
effectAllowed: 'uninitialized' effectAllowed: 'uninitialized'
} }
} }
cy.get('.CodeMirror-scroll').trigger('dragenter', dropEvent) cy.get('.CodeMirror-scroll')
cy.get('.CodeMirror-scroll').trigger('drop', dropEvent) .trigger('dragenter', dropEvent)
cy.get('.CodeMirror-scroll')
.trigger('drop', dropEvent)
cy.get('.CodeMirror-activeline > .CodeMirror-line > span') cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
.should('have.text', `![](${ imageUrl })`) .should('have.text', `![](${ imageUrl })`)
}) })
@ -86,7 +91,8 @@ describe('File upload', () => {
}) })
cy.get('.fa-upload') cy.get('.fa-upload')
.click() .click()
cy.fixture('acme.png').then(() => { cy.fixture('acme.png')
.then(() => {
cy.get('input[type=file]') cy.get('input[type=file]')
.attachFile({ filePath: 'acme.png', mimeType: 'image/png' }) .attachFile({ filePath: 'acme.png', mimeType: 'image/png' })
}) })
@ -101,7 +107,8 @@ describe('File upload', () => {
getData: (type = 'text') => testText getData: (type = 'text') => testText
} }
} }
cy.get('.CodeMirror-scroll').trigger('paste', pasteEvent) cy.get('.CodeMirror-scroll')
.trigger('paste', pasteEvent)
cy.get('.CodeMirror-activeline > .CodeMirror-line > span') cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
.should('have.text', `${ testText }`) .should('have.text', `${ testText }`)
}) })

View file

@ -160,14 +160,15 @@ describe('Code', () => {
return cy.wrap(null) return cy.wrap(null)
} }
cy.spy(frame.contentWindow.navigator.clipboard, 'writeText').as("copy") cy.spy(frame.contentWindow.navigator.clipboard, 'writeText')
.as('copy')
}) })
cy.getMarkdownRenderer() cy.getMarkdownRenderer()
.find('[data-cy="copy-code-button"]') .find('[data-cy="copy-code-button"]')
.click() .click()
cy.get("@copy") cy.get('@copy')
.should('be.calledWithExactly', 'let x = 0\n') .should('be.calledWithExactly', 'let x = 0\n')
}) })
}) })

View file

@ -17,7 +17,8 @@ describe('Languages', () => {
cy.get('@languages') cy.get('@languages')
.should('have.length', 28) .should('have.length', 28)
languages.forEach(language => { languages.forEach(language => {
cy.get('@languages').contains(language) cy.get('@languages')
.contains(language)
}) })
}) })

View file

@ -64,14 +64,16 @@ describe('Links Intro', () => {
describe('Menu Buttons logged in', () => { describe('Menu Buttons logged in', () => {
it('New note', () => { it('New note', () => {
cy.get('.d-inline-flex.btn-primary').click() cy.get('.d-inline-flex.btn-primary')
.click()
cy.url() cy.url()
.should('include', '/new') .should('include', '/new')
}) })
describe('User Menu', () => { describe('User Menu', () => {
beforeEach(() => { beforeEach(() => {
cy.get('#dropdown-user').click() cy.get('#dropdown-user')
.click()
}) })
it('Features', () => { it('Features', () => {

View file

@ -12,7 +12,7 @@ describe('profile page', () => {
}, { }, {
body: [ body: [
{ {
label: "cypress-App", label: 'cypress-App',
created: 1601991518 created: 1601991518
} }
] ]

View file

@ -21,7 +21,7 @@ describe('Toolbar Buttons', () => {
beforeEach(() => { beforeEach(() => {
cy.codemirrorFill(testText) cy.codemirrorFill(testText)
cy.get('.CodeMirror-line > span') cy.get('.CodeMirror-line > span')
.should("exist") .should('exist')
.should('have.text', testText) .should('have.text', testText)
}) })
@ -184,7 +184,7 @@ describe('Toolbar Buttons', () => {
beforeEach(() => { beforeEach(() => {
cy.codemirrorFill(testLink) cy.codemirrorFill(testLink)
cy.get('.CodeMirror-line > span') cy.get('.CodeMirror-line > span')
.should("exist") .should('exist')
.should('have.text', testLink) .should('have.text', testLink)
cy.get('@codeinput') cy.get('@codeinput')
.type('{ctrl}a') .type('{ctrl}a')

View file

@ -16,6 +16,7 @@ declare namespace Cypress {
} }
Cypress.Commands.add('checkExternalLink', { prevSubject: 'element' }, ($element: JQuery, url: string) => { Cypress.Commands.add('checkExternalLink', { prevSubject: 'element' }, ($element: JQuery, url: string) => {
cy.wrap($element).should('have.attr', 'href', url) cy.wrap($element)
.should('have.attr', 'href', url)
.should('have.attr', 'target', '_blank') .should('have.attr', 'target', '_blank')
}) })

View file

@ -50,9 +50,9 @@ beforeEach(() => {
sourceCodeUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', sourceCodeUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
issueTrackerUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' issueTrackerUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
}, },
"iframeCommunication": { 'iframeCommunication': {
"editorOrigin": "http://127.0.0.1:3001", 'editorOrigin': 'http://127.0.0.1:3001',
"rendererOrigin": "http://127.0.0.1:3001" 'rendererOrigin': 'http://127.0.0.1:3001'
} }
} }
}) })

View file

@ -12,6 +12,7 @@ declare namespace Cypress {
* @example cy.get(input).fill('content') * @example cy.get(input).fill('content')
*/ */
fill(value: string): Chainable<Element> fill(value: string): Chainable<Element>
codemirrorFill(value: string): Chainable<Element> codemirrorFill(value: string): Chainable<Element>
} }
} }
@ -25,7 +26,8 @@ Cypress.Commands.add('fill', {
}) })
Cypress.Commands.add('codemirrorFill', (content: string) => { Cypress.Commands.add('codemirrorFill', (content: string) => {
const line = content.split("\n").find(value => value !== ''); const line = content.split('\n')
.find(value => value !== '')
cy.get('.CodeMirror') cy.get('.CodeMirror')
.click() .click()
.get('textarea') .get('textarea')

View file

@ -16,6 +16,8 @@ declare namespace Cypress {
} }
Cypress.Commands.add('logout', () => { Cypress.Commands.add('logout', () => {
cy.get('#dropdown-user').click() cy.get('#dropdown-user')
cy.get('.fa-sign-out').click() .click()
cy.get('.fa-sign-out')
.click()
}) })

View file

@ -18,16 +18,16 @@ Cypress.Commands.add('visitTestEditor', (query?: string) => {
beforeEach(() => { beforeEach(() => {
cy.intercept(`/api/v2/notes/${ testNoteId }-get`, { cy.intercept(`/api/v2/notes/${ testNoteId }-get`, {
"id": "ABC123", 'id': 'ABC123',
"alias": "banner", 'alias': 'banner',
"lastChange": { 'lastChange': {
"userId": "test", 'userId': 'test',
"timestamp": 1600033920 'timestamp': 1600033920
}, },
"viewCount": 0, 'viewCount': 0,
"createTime": 1600033920, 'createTime': 1600033920,
"content": "", 'content': '',
"authorship": [], 'authorship': [],
"preVersionTwoNote": true 'preVersionTwoNote': true
}) })
}) })

View file

@ -3,8 +3,15 @@
"strict": true, "strict": true,
"baseUrl": "../node_modules", "baseUrl": "../node_modules",
"target": "es6", "target": "es6",
"lib": ["es6", "dom"], "lib": [
"types": ["cypress" ,"cypress-commands", "cypress-file-upload"] "es6",
"dom"
],
"types": [
"cypress",
"cypress-commands",
"cypress-file-upload"
]
}, },
"include": [ "include": [
"**/*.ts" "**/*.ts"

View file

@ -6,32 +6,72 @@
.loader { .loader {
@keyframes animation-roll { @keyframes animation-roll {
0% { transform: translateX(calc(-100vw / 2 - 100%)) rotateZ(0deg); } 0% {
100% { transform: translateX(calc(100vw / 2 + 100%)) rotateZ(720deg); } transform: translateX(calc(-100vw / 2 - 100%)) rotateZ(0deg);
}
100% {
transform: translateX(calc(100vw / 2 + 100%)) rotateZ(720deg);
}
} }
@keyframes animation-jump { @keyframes animation-jump {
0% { transform: scale(1,1) translateY(0); } 0% {
10% { transform: scale(1.1,.9) translateY(0); } transform: scale(1, 1) translateY(0);
30% { transform: scale(.9,1.1) translateY(-100px); } }
50% { transform: scale(1.05,.95) translateY(0); } 10% {
57% { transform: scale(1,1) translateY(-7px); } transform: scale(1.1, .9) translateY(0);
64% { transform: scale(1,1) translateY(0); } }
100% { transform: scale(1,1) translateY(0); } 30% {
transform: scale(.9, 1.1) translateY(-100px);
}
50% {
transform: scale(1.05, .95) translateY(0);
}
57% {
transform: scale(1, 1) translateY(-7px);
}
64% {
transform: scale(1, 1) translateY(0);
}
100% {
transform: scale(1, 1) translateY(0);
}
} }
@keyframes animation-shake { @keyframes animation-shake {
0% { transform: translate(1px, 1px) rotate(0deg); } 0% {
10% { transform: translate(-1px, -2px) rotate(-1deg); } transform: translate(1px, 1px) rotate(0deg);
20% { transform: translate(-3px, 0px) rotate(1deg); } }
30% { transform: translate(3px, 2px) rotate(0deg); } 10% {
40% { transform: translate(1px, -1px) rotate(1deg); } transform: translate(-1px, -2px) rotate(-1deg);
50% { transform: translate(-1px, 2px) rotate(-1deg); } }
60% { transform: translate(-3px, 1px) rotate(0deg); } 20% {
70% { transform: translate(3px, 1px) rotate(-1deg); } transform: translate(-3px, 0px) rotate(1deg);
80% { transform: translate(-1px, -1px) rotate(1deg); } }
90% { transform: translate(1px, 2px) rotate(0deg); } 30% {
100% { transform: translate(1px, -2px) rotate(-1deg); } transform: translate(3px, 2px) rotate(0deg);
}
40% {
transform: translate(1px, -1px) rotate(1deg);
}
50% {
transform: translate(-1px, 2px) rotate(-1deg);
}
60% {
transform: translate(-3px, 1px) rotate(0deg);
}
70% {
transform: translate(3px, 1px) rotate(-1deg);
}
80% {
transform: translate(-1px, -1px) rotate(1deg);
}
90% {
transform: translate(1px, 2px) rotate(0deg);
}
100% {
transform: translate(1px, -2px) rotate(-1deg);
}
} }
.animation-roll { .animation-roll {

View file

@ -30,7 +30,8 @@ export const ApplicationLoader: React.FC = ({ children }) => {
useEffect(() => { useEffect(() => {
for (const task of initTasks) { for (const task of initTasks) {
runTask(task.task).catch((reason: Error) => { runTask(task.task)
.catch((reason: Error) => {
console.error(reason) console.error(reason)
setFailedTitle(task.name) setFailedTitle(task.name)
}) })

View file

@ -16,68 +16,88 @@ describe('Test caching functionality', () => {
it('initialize with right lifetime, no entry limit', () => { it('initialize with right lifetime, no entry limit', () => {
const lifetime = 1000 const lifetime = 1000
const lifetimedCache = new Cache<string, string>(lifetime) const lifetimedCache = new Cache<string, string>(lifetime)
expect(lifetimedCache.entryLifetime).toEqual(lifetime) expect(lifetimedCache.entryLifetime)
expect(lifetimedCache.maxEntries).toEqual(0) .toEqual(lifetime)
expect(lifetimedCache.maxEntries)
.toEqual(0)
}) })
it('initialize with right lifetime, given entry limit', () => { it('initialize with right lifetime, given entry limit', () => {
const lifetime = 1000 const lifetime = 1000
const maxEntries = 10 const maxEntries = 10
const limitedCache = new Cache<string, string>(lifetime, maxEntries) const limitedCache = new Cache<string, string>(lifetime, maxEntries)
expect(limitedCache.entryLifetime).toEqual(lifetime) expect(limitedCache.entryLifetime)
expect(limitedCache.maxEntries).toEqual(maxEntries) .toEqual(lifetime)
expect(limitedCache.maxEntries)
.toEqual(maxEntries)
}) })
it('entry exists after inserting', () => { it('entry exists after inserting', () => {
testCache.put('test', 123) testCache.put('test', 123)
expect(testCache.has('test')).toBe(true) expect(testCache.has('test'))
.toBe(true)
}) })
it('entry does not exist prior inserting', () => { it('entry does not exist prior inserting', () => {
expect(testCache.has('test')).toBe(false) expect(testCache.has('test'))
.toBe(false)
}) })
it('entry does expire', () => { it('entry does expire', () => {
const shortLivingCache = new Cache<string, number>(2) const shortLivingCache = new Cache<string, number>(2)
shortLivingCache.put('test', 123) shortLivingCache.put('test', 123)
expect(shortLivingCache.has('test')).toBe(true) expect(shortLivingCache.has('test'))
.toBe(true)
setTimeout(() => { setTimeout(() => {
expect(shortLivingCache.has('test')).toBe(false) expect(shortLivingCache.has('test'))
.toBe(false)
}, 2000) }, 2000)
}) })
it('entry value does not change', () => { it('entry value does not change', () => {
const testValue = Date.now() const testValue = Date.now()
testCache.put('test', testValue) testCache.put('test', testValue)
expect(testCache.get('test')).toEqual(testValue) expect(testCache.get('test'))
.toEqual(testValue)
}) })
it('error is thrown on non-existent entry', () => { it('error is thrown on non-existent entry', () => {
const accessNonExistentEntry = () => { const accessNonExistentEntry = () => {
testCache.get('test') testCache.get('test')
} }
expect(accessNonExistentEntry).toThrow(Error) expect(accessNonExistentEntry)
.toThrow(Error)
}) })
it('newer item replaces older item', () => { it('newer item replaces older item', () => {
testCache.put('test', 123) testCache.put('test', 123)
testCache.put('test', 456) testCache.put('test', 456)
expect(testCache.get('test')).toEqual(456) expect(testCache.get('test'))
.toEqual(456)
}) })
it('entry limit is respected', () => { it('entry limit is respected', () => {
const limitedCache = new Cache<string, number>(1000, 2) const limitedCache = new Cache<string, number>(1000, 2)
limitedCache.put('first', 1) limitedCache.put('first', 1)
expect(limitedCache.has('first')).toBe(true) expect(limitedCache.has('first'))
expect(limitedCache.has('second')).toBe(false) .toBe(true)
expect(limitedCache.has('third')).toBe(false) expect(limitedCache.has('second'))
.toBe(false)
expect(limitedCache.has('third'))
.toBe(false)
limitedCache.put('second', 2) limitedCache.put('second', 2)
expect(limitedCache.has('first')).toBe(true) expect(limitedCache.has('first'))
expect(limitedCache.has('second')).toBe(true) .toBe(true)
expect(limitedCache.has('third')).toBe(false) expect(limitedCache.has('second'))
.toBe(true)
expect(limitedCache.has('third'))
.toBe(false)
limitedCache.put('third', 3) limitedCache.put('third', 3)
expect(limitedCache.has('first')).toBe(false) expect(limitedCache.has('first'))
expect(limitedCache.has('second')).toBe(true) .toBe(false)
expect(limitedCache.has('third')).toBe(true) expect(limitedCache.has('second'))
.toBe(true)
expect(limitedCache.has('third'))
.toBe(true)
}) })
}) })

View file

@ -10,10 +10,9 @@ export interface CacheEntry<T> {
} }
export class Cache<K, V> { export class Cache<K, V> {
private store = new Map<K, CacheEntry<V>>()
readonly entryLifetime: number readonly entryLifetime: number
readonly maxEntries: number readonly maxEntries: number
private store = new Map<K, CacheEntry<V>>()
constructor(lifetime: number, maxEntries = 0) { constructor(lifetime: number, maxEntries = 0) {
if (lifetime < 0) { if (lifetime < 0) {
@ -41,7 +40,8 @@ export class Cache<K, V> {
put(key: K, value: V): void { put(key: K, value: V): void {
if (this.maxEntries > 0 && this.store.size === this.maxEntries) { if (this.maxEntries > 0 && this.store.size === this.maxEntries) {
this.store.delete(this.store.keys().next().value) this.store.delete(this.store.keys()
.next().value)
} }
this.store.set(key, { this.store.set(key, {
entryCreated: Date.now(), entryCreated: Date.now(),

View file

@ -22,14 +22,19 @@ export const CopyOverlay: React.FC<CopyOverlayProps> = ({ content, clickComponen
const [tooltipId] = useState<string>(() => uuid()) const [tooltipId] = useState<string>(() => uuid())
const copyToClipboard = useCallback((content: string) => { const copyToClipboard = useCallback((content: string) => {
navigator.clipboard.writeText(content).then(() => { navigator.clipboard.writeText(content)
.then(() => {
setError(false) setError(false)
}).catch(() => { })
.catch(() => {
setError(true) setError(true)
console.error("couldn't copy") console.error('couldn\'t copy')
}).finally(() => { })
.finally(() => {
setShowCopiedTooltip(true) setShowCopiedTooltip(true)
setTimeout(() => { setShowCopiedTooltip(false) }, 2000) setTimeout(() => {
setShowCopiedTooltip(false)
}, 2000)
}) })
}, []) }, [])

View file

@ -15,7 +15,7 @@ export interface CopyToClipboardButtonProps {
content: string content: string
size?: 'sm' | 'lg' size?: 'sm' | 'lg'
variant?: Variant variant?: Variant
"data-cy"?: string 'data-cy'?: string
} }
export const CopyToClipboardButton: React.FC<CopyToClipboardButtonProps> = ({ export const CopyToClipboardButton: React.FC<CopyToClipboardButtonProps> = ({
@ -30,7 +30,7 @@ export const CopyToClipboardButton: React.FC<CopyToClipboardButtonProps> = ({
return ( return (
<Fragment> <Fragment>
<Button ref={ button } size={ size } variant={ variant } title={ t('renderer.highlightCode.copyCode') } <Button ref={ button } size={ size } variant={ variant } title={ t('renderer.highlightCode.copyCode') }
data-cy={props["data-cy"]}> data-cy={ props['data-cy'] }>
<ForkAwesomeIcon icon='files-o'/> <ForkAwesomeIcon icon='files-o'/>
</Button> </Button>
<CopyOverlay content={ content } clickComponent={ button }/> <CopyOverlay content={ content } clickComponent={ button }/>

View file

@ -25,7 +25,8 @@ export const CopyableField: React.FC<CopyableFieldProps> = ({ content, nativeSha
navigator.share({ navigator.share({
text: content, text: content,
url: url url: url
}).catch(err => { })
.catch(err => {
console.error('Native sharing failed: ', err) console.error('Native sharing failed: ', err)
}) })
}, [content, url]) }, [content, url])

File diff suppressed because one or more lines are too long

View file

@ -1 +1,29 @@
<svg clip-rule="evenodd" fill-rule="evenodd" height="1486" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 1486 1486" width="1486" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(200 -420 420 200 660 1340)" gradientUnits="userSpaceOnUse" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#fcca8c"/><stop offset="1" stop-color="#dca055"/></linearGradient><g fill-rule="nonzero" transform="translate(-142.756 -142.754)"><path d="m1553.66 961.083 75.25-75.258-75.25-75.246 56.61-90.096-90.1-56.616 35.15-100.446-100.44-35.142 11.91-105.746-105.74-11.912-11.92-105.75-105.74 11.912-35.15-100.445-100.43 35.145-56.63-90.1-90.107 56.617-75.242-75.246-75.242 75.25-90.104-56.612-56.612 90.096-100.442-35.15-35.142 100.441-105.75-11.916-11.912 105.741-105.742 11.913 11.917 105.741-100.454 35.15 35.145 100.438-90.1 56.612 56.621 90.117-75.258 75.25 75.25 75.258-56.613 90.107 90.1 56.61-35.145 100.44 100.45 35.15-11.913 105.73 105.742 11.92 11.912 105.74 105.75-11.91 35.142 100.43 100.437-35.13 56.617 90.1 90.096-56.62 75.25 74.55 75.25-74.53 90.099 56.61 56.61-90.11 100.45 35.15 35.14-100.44 105.75 11.91 11.91-105.75 105.75-11.91-11.92-105.74 100.45-35.15-35.15-100.45 90.1-56.61z" fill="#b51f08"/><path d="m1401.3 1004.78c0-145.437-117.9-263.341-263.34-263.341-72.24 0-137.68 29.112-185.252 76.225l-.033-.034-67.096 67.1-54.862-54.862c-48.267-55.067-119.071-89.879-198.042-89.879-145.442 0-263.342 117.904-263.342 263.341 0 76 32.23 144.43 83.721 192.49l432.779 432.55 423.217-423.49c52.88-49.77 92.25-120 92.25-200.1" fill="#fcca8c"/><path d="m885.579 884.73-54.862-54.862c-48.267-55.067-119.071-89.879-198.042-89.879-145.442 0-263.342 117.904-263.342 263.341 0 76 32.23 144.43 83.721 192.49l432.779 432.55" fill="url(#a)"/></g><path d="m743.077 1485.616-.254-743.64" fill="none"/><g fill-rule="nonzero" transform="translate(-142.756 -142.754)"><path d="m961.011 1553.59c-19.279-19.35-45.917-31.31-75.325-31.31-29.417 0-56.046 11.96-75.329 31.31.308 41.34 33.908 74.76 75.325 74.76 41.416 0 75.02-33.43 75.329-74.76" fill="#010007"/><path d="m797.707 1098.22c0 31.8-25.767 57.57-57.571 57.57-31.787 0-57.558-25.77-57.558-57.57s25.771-57.57 57.558-57.57c31.804 0 57.571 25.77 57.571 57.57" fill="#010007"/><path d="m777.962 1089.59c0 8.82-7.146 15.94-15.95 15.94-8.808 0-15.958-7.12-15.958-15.94 0-8.81 7.15-15.96 15.958-15.96 8.804 0 15.95 7.15 15.95 15.96" fill="#fffffa"/><path d="m1089.65 1098.22c0 31.8-25.77 57.57-57.57 57.57-31.79 0-57.567-25.77-57.567-57.57s25.777-57.57 57.567-57.57c31.8 0 57.57 25.77 57.57 57.57" fill="#010007"/><path d="m1069.9 1089.59c0 8.82-7.15 15.94-15.95 15.94-8.81 0-15.96-7.12-15.96-15.94 0-8.81 7.15-15.96 15.96-15.96 8.8 0 15.95 7.15 15.95 15.96" fill="#fffffa"/></g></svg> <svg clip-rule="evenodd" fill-rule="evenodd" height="1486" stroke-linejoin="round" stroke-miterlimit="2"
viewBox="0 0 1486 1486" width="1486" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="a" gradientTransform="matrix(200 -420 420 200 660 1340)" gradientUnits="userSpaceOnUse" x1="0"
x2="1" y1="0" y2="0">
<stop offset="0" stop-color="#fcca8c"/>
<stop offset="1" stop-color="#dca055"/>
</linearGradient>
<g fill-rule="nonzero" transform="translate(-142.756 -142.754)">
<path d="m1553.66 961.083 75.25-75.258-75.25-75.246 56.61-90.096-90.1-56.616 35.15-100.446-100.44-35.142 11.91-105.746-105.74-11.912-11.92-105.75-105.74 11.912-35.15-100.445-100.43 35.145-56.63-90.1-90.107 56.617-75.242-75.246-75.242 75.25-90.104-56.612-56.612 90.096-100.442-35.15-35.142 100.441-105.75-11.916-11.912 105.741-105.742 11.913 11.917 105.741-100.454 35.15 35.145 100.438-90.1 56.612 56.621 90.117-75.258 75.25 75.25 75.258-56.613 90.107 90.1 56.61-35.145 100.44 100.45 35.15-11.913 105.73 105.742 11.92 11.912 105.74 105.75-11.91 35.142 100.43 100.437-35.13 56.617 90.1 90.096-56.62 75.25 74.55 75.25-74.53 90.099 56.61 56.61-90.11 100.45 35.15 35.14-100.44 105.75 11.91 11.91-105.75 105.75-11.91-11.92-105.74 100.45-35.15-35.15-100.45 90.1-56.61z"
fill="#b51f08"/>
<path d="m1401.3 1004.78c0-145.437-117.9-263.341-263.34-263.341-72.24 0-137.68 29.112-185.252 76.225l-.033-.034-67.096 67.1-54.862-54.862c-48.267-55.067-119.071-89.879-198.042-89.879-145.442 0-263.342 117.904-263.342 263.341 0 76 32.23 144.43 83.721 192.49l432.779 432.55 423.217-423.49c52.88-49.77 92.25-120 92.25-200.1"
fill="#fcca8c"/>
<path d="m885.579 884.73-54.862-54.862c-48.267-55.067-119.071-89.879-198.042-89.879-145.442 0-263.342 117.904-263.342 263.341 0 76 32.23 144.43 83.721 192.49l432.779 432.55"
fill="url(#a)"/>
</g>
<path d="m743.077 1485.616-.254-743.64" fill="none"/>
<g fill-rule="nonzero" transform="translate(-142.756 -142.754)">
<path d="m961.011 1553.59c-19.279-19.35-45.917-31.31-75.325-31.31-29.417 0-56.046 11.96-75.329 31.31.308 41.34 33.908 74.76 75.325 74.76 41.416 0 75.02-33.43 75.329-74.76"
fill="#010007"/>
<path d="m797.707 1098.22c0 31.8-25.767 57.57-57.571 57.57-31.787 0-57.558-25.77-57.558-57.57s25.771-57.57 57.558-57.57c31.804 0 57.571 25.77 57.571 57.57"
fill="#010007"/>
<path d="m777.962 1089.59c0 8.82-7.146 15.94-15.95 15.94-8.808 0-15.958-7.12-15.958-15.94 0-8.81 7.15-15.96 15.958-15.96 8.804 0 15.95 7.15 15.95 15.96"
fill="#fffffa"/>
<path d="m1089.65 1098.22c0 31.8-25.77 57.57-57.57 57.57-31.79 0-57.567-25.77-57.567-57.57s25.777-57.57 57.567-57.57c31.8 0 57.57 25.77 57.57 57.57"
fill="#010007"/>
<path d="m1069.9 1089.59c0 8.82-7.15 15.94-15.95 15.94-8.81 0-15.96-7.12-15.96-15.94 0-8.81 7.15-15.96 15.96-15.96 8.8 0 15.95 7.15 15.95 15.96"
fill="#fffffa"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View file

@ -3,7 +3,7 @@ SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: AGPL-3.0-only SPDX-License-Identifier: AGPL-3.0-only
*/ */
import hljs from 'highlight.js/lib/core'; import hljs from 'highlight.js/lib/core'
import abnf from 'highlight.js/lib/languages/abnf' import abnf from 'highlight.js/lib/languages/abnf'
import accesslog from 'highlight.js/lib/languages/accesslog' import accesslog from 'highlight.js/lib/languages/accesslog'
import actionscript from 'highlight.js/lib/languages/actionscript' import actionscript from 'highlight.js/lib/languages/actionscript'
@ -194,196 +194,196 @@ import xl from 'highlight.js/lib/languages/xl'
import xquery from 'highlight.js/lib/languages/xquery' import xquery from 'highlight.js/lib/languages/xquery'
import zephir from 'highlight.js/lib/languages/zephir' import zephir from 'highlight.js/lib/languages/zephir'
hljs.registerLanguage('abnf', abnf); hljs.registerLanguage('abnf', abnf)
hljs.registerLanguage('accesslog', accesslog); hljs.registerLanguage('accesslog', accesslog)
hljs.registerLanguage('actionscript', actionscript); hljs.registerLanguage('actionscript', actionscript)
hljs.registerLanguage('ada', ada); hljs.registerLanguage('ada', ada)
hljs.registerLanguage('angelscript', angelscript); hljs.registerLanguage('angelscript', angelscript)
hljs.registerLanguage('apache', apache); hljs.registerLanguage('apache', apache)
hljs.registerLanguage('applescript', applescript); hljs.registerLanguage('applescript', applescript)
hljs.registerLanguage('arcade', arcade); hljs.registerLanguage('arcade', arcade)
hljs.registerLanguage('arduino', arduino); hljs.registerLanguage('arduino', arduino)
hljs.registerLanguage('armasm', armasm); hljs.registerLanguage('armasm', armasm)
hljs.registerLanguage('xml', xml); hljs.registerLanguage('xml', xml)
hljs.registerLanguage('asciidoc', asciidoc); hljs.registerLanguage('asciidoc', asciidoc)
hljs.registerLanguage('aspectj', aspectj); hljs.registerLanguage('aspectj', aspectj)
hljs.registerLanguage('autohotkey', autohotkey); hljs.registerLanguage('autohotkey', autohotkey)
hljs.registerLanguage('autoit', autoit); hljs.registerLanguage('autoit', autoit)
hljs.registerLanguage('avrasm', avrasm); hljs.registerLanguage('avrasm', avrasm)
hljs.registerLanguage('awk', awk); hljs.registerLanguage('awk', awk)
hljs.registerLanguage('axapta', axapta); hljs.registerLanguage('axapta', axapta)
hljs.registerLanguage('bash', bash); hljs.registerLanguage('bash', bash)
hljs.registerLanguage('basic', basic); hljs.registerLanguage('basic', basic)
hljs.registerLanguage('bnf', bnf); hljs.registerLanguage('bnf', bnf)
hljs.registerLanguage('brainfuck', brainfuck); hljs.registerLanguage('brainfuck', brainfuck)
hljs.registerLanguage('c-like', c_like); hljs.registerLanguage('c-like', c_like)
hljs.registerLanguage('c', c); hljs.registerLanguage('c', c)
hljs.registerLanguage('cal', cal); hljs.registerLanguage('cal', cal)
hljs.registerLanguage('capnproto', capnproto); hljs.registerLanguage('capnproto', capnproto)
hljs.registerLanguage('ceylon', ceylon); hljs.registerLanguage('ceylon', ceylon)
hljs.registerLanguage('clean', clean); hljs.registerLanguage('clean', clean)
hljs.registerLanguage('clojure', clojure); hljs.registerLanguage('clojure', clojure)
hljs.registerLanguage('clojure-repl', clojure_repl); hljs.registerLanguage('clojure-repl', clojure_repl)
hljs.registerLanguage('cmake', cmake); hljs.registerLanguage('cmake', cmake)
hljs.registerLanguage('coffeescript', coffeescript); hljs.registerLanguage('coffeescript', coffeescript)
hljs.registerLanguage('coq', coq); hljs.registerLanguage('coq', coq)
hljs.registerLanguage('cos', cos); hljs.registerLanguage('cos', cos)
hljs.registerLanguage('cpp', cpp); hljs.registerLanguage('cpp', cpp)
hljs.registerLanguage('crmsh', crmsh); hljs.registerLanguage('crmsh', crmsh)
hljs.registerLanguage('crystal', crystal); hljs.registerLanguage('crystal', crystal)
hljs.registerLanguage('csharp', csharp); hljs.registerLanguage('csharp', csharp)
hljs.registerLanguage('csp', csp); hljs.registerLanguage('csp', csp)
hljs.registerLanguage('css', css); hljs.registerLanguage('css', css)
hljs.registerLanguage('d', d); hljs.registerLanguage('d', d)
hljs.registerLanguage('markdown', markdown); hljs.registerLanguage('markdown', markdown)
hljs.registerLanguage('dart', dart); hljs.registerLanguage('dart', dart)
hljs.registerLanguage('delphi', delphi); hljs.registerLanguage('delphi', delphi)
hljs.registerLanguage('diff', diff); hljs.registerLanguage('diff', diff)
hljs.registerLanguage('django', django); hljs.registerLanguage('django', django)
hljs.registerLanguage('dns', dns); hljs.registerLanguage('dns', dns)
hljs.registerLanguage('dockerfile', dockerfile); hljs.registerLanguage('dockerfile', dockerfile)
hljs.registerLanguage('dos', dos); hljs.registerLanguage('dos', dos)
hljs.registerLanguage('dsconfig', dsconfig); hljs.registerLanguage('dsconfig', dsconfig)
hljs.registerLanguage('dts', dts); hljs.registerLanguage('dts', dts)
hljs.registerLanguage('dust', dust); hljs.registerLanguage('dust', dust)
hljs.registerLanguage('ebnf', ebnf); hljs.registerLanguage('ebnf', ebnf)
hljs.registerLanguage('elixir', elixir); hljs.registerLanguage('elixir', elixir)
hljs.registerLanguage('elm', elm); hljs.registerLanguage('elm', elm)
hljs.registerLanguage('ruby', ruby); hljs.registerLanguage('ruby', ruby)
hljs.registerLanguage('erb', erb); hljs.registerLanguage('erb', erb)
hljs.registerLanguage('erlang-repl', erlang_repl); hljs.registerLanguage('erlang-repl', erlang_repl)
hljs.registerLanguage('erlang', erlang); hljs.registerLanguage('erlang', erlang)
hljs.registerLanguage('excel', excel); hljs.registerLanguage('excel', excel)
hljs.registerLanguage('fix', fix); hljs.registerLanguage('fix', fix)
hljs.registerLanguage('flix', flix); hljs.registerLanguage('flix', flix)
hljs.registerLanguage('fortran', fortran); hljs.registerLanguage('fortran', fortran)
hljs.registerLanguage('fsharp', fsharp); hljs.registerLanguage('fsharp', fsharp)
hljs.registerLanguage('gams', gams); hljs.registerLanguage('gams', gams)
hljs.registerLanguage('gauss', gauss); hljs.registerLanguage('gauss', gauss)
hljs.registerLanguage('gcode', gcode); hljs.registerLanguage('gcode', gcode)
hljs.registerLanguage('gherkin', gherkin); hljs.registerLanguage('gherkin', gherkin)
hljs.registerLanguage('glsl', glsl); hljs.registerLanguage('glsl', glsl)
hljs.registerLanguage('gml', gml); hljs.registerLanguage('gml', gml)
hljs.registerLanguage('go', go); hljs.registerLanguage('go', go)
hljs.registerLanguage('golo', golo); hljs.registerLanguage('golo', golo)
hljs.registerLanguage('gradle', gradle); hljs.registerLanguage('gradle', gradle)
hljs.registerLanguage('groovy', groovy); hljs.registerLanguage('groovy', groovy)
hljs.registerLanguage('haml', haml); hljs.registerLanguage('haml', haml)
hljs.registerLanguage('handlebars', handlebars); hljs.registerLanguage('handlebars', handlebars)
hljs.registerLanguage('haskell', haskell); hljs.registerLanguage('haskell', haskell)
hljs.registerLanguage('haxe', haxe); hljs.registerLanguage('haxe', haxe)
hljs.registerLanguage('hsp', hsp); hljs.registerLanguage('hsp', hsp)
hljs.registerLanguage('html', xml); hljs.registerLanguage('html', xml)
hljs.registerLanguage('htmlbars', htmlbars); hljs.registerLanguage('htmlbars', htmlbars)
hljs.registerLanguage('http', http); hljs.registerLanguage('http', http)
hljs.registerLanguage('hy', hy); hljs.registerLanguage('hy', hy)
hljs.registerLanguage('inform7', inform7); hljs.registerLanguage('inform7', inform7)
hljs.registerLanguage('ini', ini); hljs.registerLanguage('ini', ini)
hljs.registerLanguage('irpf90', irpf90); hljs.registerLanguage('irpf90', irpf90)
hljs.registerLanguage('isbl', isbl); hljs.registerLanguage('isbl', isbl)
hljs.registerLanguage('java', java); hljs.registerLanguage('java', java)
hljs.registerLanguage('javascript', javascript); hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('jboss-cli', jboss_cli); hljs.registerLanguage('jboss-cli', jboss_cli)
hljs.registerLanguage('js', javascript); hljs.registerLanguage('js', javascript)
hljs.registerLanguage('json', json); hljs.registerLanguage('json', json)
hljs.registerLanguage('julia', julia); hljs.registerLanguage('julia', julia)
hljs.registerLanguage('julia-repl', julia_repl); hljs.registerLanguage('julia-repl', julia_repl)
hljs.registerLanguage('kotlin', kotlin); hljs.registerLanguage('kotlin', kotlin)
hljs.registerLanguage('lasso', lasso); hljs.registerLanguage('lasso', lasso)
hljs.registerLanguage('latex', latex); hljs.registerLanguage('latex', latex)
hljs.registerLanguage('ldif', ldif); hljs.registerLanguage('ldif', ldif)
hljs.registerLanguage('leaf', leaf); hljs.registerLanguage('leaf', leaf)
hljs.registerLanguage('less', less); hljs.registerLanguage('less', less)
hljs.registerLanguage('lisp', lisp); hljs.registerLanguage('lisp', lisp)
hljs.registerLanguage('livecodeserver', livecodeserver); hljs.registerLanguage('livecodeserver', livecodeserver)
hljs.registerLanguage('livescript', livescript); hljs.registerLanguage('livescript', livescript)
hljs.registerLanguage('llvm', llvm); hljs.registerLanguage('llvm', llvm)
hljs.registerLanguage('lsl', lsl); hljs.registerLanguage('lsl', lsl)
hljs.registerLanguage('lua', lua); hljs.registerLanguage('lua', lua)
hljs.registerLanguage('makefile', makefile); hljs.registerLanguage('makefile', makefile)
hljs.registerLanguage('mathematica', mathematica); hljs.registerLanguage('mathematica', mathematica)
hljs.registerLanguage('matlab', matlab); hljs.registerLanguage('matlab', matlab)
hljs.registerLanguage('maxima', maxima); hljs.registerLanguage('maxima', maxima)
hljs.registerLanguage('mel', mel); hljs.registerLanguage('mel', mel)
hljs.registerLanguage('mercury', mercury); hljs.registerLanguage('mercury', mercury)
hljs.registerLanguage('mipsasm', mipsasm); hljs.registerLanguage('mipsasm', mipsasm)
hljs.registerLanguage('mizar', mizar); hljs.registerLanguage('mizar', mizar)
hljs.registerLanguage('perl', perl); hljs.registerLanguage('perl', perl)
hljs.registerLanguage('mojolicious', mojolicious); hljs.registerLanguage('mojolicious', mojolicious)
hljs.registerLanguage('monkey', monkey); hljs.registerLanguage('monkey', monkey)
hljs.registerLanguage('moonscript', moonscript); hljs.registerLanguage('moonscript', moonscript)
hljs.registerLanguage('n1ql', n1ql); hljs.registerLanguage('n1ql', n1ql)
hljs.registerLanguage('nginx', nginx); hljs.registerLanguage('nginx', nginx)
hljs.registerLanguage('nim', nim); hljs.registerLanguage('nim', nim)
hljs.registerLanguage('nix', nix); hljs.registerLanguage('nix', nix)
hljs.registerLanguage('node-repl', node_repl); hljs.registerLanguage('node-repl', node_repl)
hljs.registerLanguage('nsis', nsis); hljs.registerLanguage('nsis', nsis)
hljs.registerLanguage('objectivec', objectivec); hljs.registerLanguage('objectivec', objectivec)
hljs.registerLanguage('ocaml', ocaml); hljs.registerLanguage('ocaml', ocaml)
hljs.registerLanguage('openscad', openscad); hljs.registerLanguage('openscad', openscad)
hljs.registerLanguage('oxygene', oxygene); hljs.registerLanguage('oxygene', oxygene)
hljs.registerLanguage('parser3', parser3); hljs.registerLanguage('parser3', parser3)
hljs.registerLanguage('pf', pf); hljs.registerLanguage('pf', pf)
hljs.registerLanguage('pgsql', pgsql); hljs.registerLanguage('pgsql', pgsql)
hljs.registerLanguage('php', php); hljs.registerLanguage('php', php)
hljs.registerLanguage('php-template', php_template); hljs.registerLanguage('php-template', php_template)
hljs.registerLanguage('plaintext', plaintext); hljs.registerLanguage('plaintext', plaintext)
hljs.registerLanguage('pony', pony); hljs.registerLanguage('pony', pony)
hljs.registerLanguage('powershell', powershell); hljs.registerLanguage('powershell', powershell)
hljs.registerLanguage('processing', processing); hljs.registerLanguage('processing', processing)
hljs.registerLanguage('profile', profile); hljs.registerLanguage('profile', profile)
hljs.registerLanguage('prolog', prolog); hljs.registerLanguage('prolog', prolog)
hljs.registerLanguage('properties', properties); hljs.registerLanguage('properties', properties)
hljs.registerLanguage('protobuf', protobuf); hljs.registerLanguage('protobuf', protobuf)
hljs.registerLanguage('puppet', puppet); hljs.registerLanguage('puppet', puppet)
hljs.registerLanguage('purebasic', purebasic); hljs.registerLanguage('purebasic', purebasic)
hljs.registerLanguage('python', python); hljs.registerLanguage('python', python)
hljs.registerLanguage('python-repl', python_repl); hljs.registerLanguage('python-repl', python_repl)
hljs.registerLanguage('q', q); hljs.registerLanguage('q', q)
hljs.registerLanguage('qml', qml); hljs.registerLanguage('qml', qml)
hljs.registerLanguage('r', r); hljs.registerLanguage('r', r)
hljs.registerLanguage('reasonml', reasonml); hljs.registerLanguage('reasonml', reasonml)
hljs.registerLanguage('rib', rib); hljs.registerLanguage('rib', rib)
hljs.registerLanguage('roboconf', roboconf); hljs.registerLanguage('roboconf', roboconf)
hljs.registerLanguage('routeros', routeros); hljs.registerLanguage('routeros', routeros)
hljs.registerLanguage('rsl', rsl); hljs.registerLanguage('rsl', rsl)
hljs.registerLanguage('ruleslanguage', ruleslanguage); hljs.registerLanguage('ruleslanguage', ruleslanguage)
hljs.registerLanguage('rust', rust); hljs.registerLanguage('rust', rust)
hljs.registerLanguage('sas', sas); hljs.registerLanguage('sas', sas)
hljs.registerLanguage('scala', scala); hljs.registerLanguage('scala', scala)
hljs.registerLanguage('scheme', scheme); hljs.registerLanguage('scheme', scheme)
hljs.registerLanguage('scilab', scilab); hljs.registerLanguage('scilab', scilab)
hljs.registerLanguage('scss', scss); hljs.registerLanguage('scss', scss)
hljs.registerLanguage('shell', shell); hljs.registerLanguage('shell', shell)
hljs.registerLanguage('smali', smali); hljs.registerLanguage('smali', smali)
hljs.registerLanguage('smalltalk', smalltalk); hljs.registerLanguage('smalltalk', smalltalk)
hljs.registerLanguage('sml', sml); hljs.registerLanguage('sml', sml)
hljs.registerLanguage('sqf', sqf); hljs.registerLanguage('sqf', sqf)
hljs.registerLanguage('sql', sql); hljs.registerLanguage('sql', sql)
hljs.registerLanguage('stan', stan); hljs.registerLanguage('stan', stan)
hljs.registerLanguage('stata', stata); hljs.registerLanguage('stata', stata)
hljs.registerLanguage('step21', step21); hljs.registerLanguage('step21', step21)
hljs.registerLanguage('stylus', stylus); hljs.registerLanguage('stylus', stylus)
hljs.registerLanguage('subunit', subunit); hljs.registerLanguage('subunit', subunit)
hljs.registerLanguage('swift', swift); hljs.registerLanguage('swift', swift)
hljs.registerLanguage('taggerscript', taggerscript); hljs.registerLanguage('taggerscript', taggerscript)
hljs.registerLanguage('yaml', yaml); hljs.registerLanguage('yaml', yaml)
hljs.registerLanguage('tap', tap); hljs.registerLanguage('tap', tap)
hljs.registerLanguage('tcl', tcl); hljs.registerLanguage('tcl', tcl)
hljs.registerLanguage('thrift', thrift); hljs.registerLanguage('thrift', thrift)
hljs.registerLanguage('tp', tp); hljs.registerLanguage('tp', tp)
hljs.registerLanguage('twig', twig); hljs.registerLanguage('twig', twig)
hljs.registerLanguage('typescript', typescript); hljs.registerLanguage('typescript', typescript)
hljs.registerLanguage('vala', vala); hljs.registerLanguage('vala', vala)
hljs.registerLanguage('vbnet', vbnet); hljs.registerLanguage('vbnet', vbnet)
hljs.registerLanguage('vbscript', vbscript); hljs.registerLanguage('vbscript', vbscript)
hljs.registerLanguage('vbscript-html', vbscript_html); hljs.registerLanguage('vbscript-html', vbscript_html)
hljs.registerLanguage('verilog', verilog); hljs.registerLanguage('verilog', verilog)
hljs.registerLanguage('vhdl', vhdl); hljs.registerLanguage('vhdl', vhdl)
hljs.registerLanguage('vim', vim); hljs.registerLanguage('vim', vim)
hljs.registerLanguage('x86asm', x86asm); hljs.registerLanguage('x86asm', x86asm)
hljs.registerLanguage('xl', xl); hljs.registerLanguage('xl', xl)
hljs.registerLanguage('xquery', xquery); hljs.registerLanguage('xquery', xquery)
hljs.registerLanguage('zephir', zephir); hljs.registerLanguage('zephir', zephir)
export default hljs; export default hljs

View file

@ -19,7 +19,8 @@ export interface IconButtonProps extends ButtonProps {
export const IconButton: React.FC<IconButtonProps> = ({ icon, children, border = false, ...props }) => { export const IconButton: React.FC<IconButtonProps> = ({ icon, children, border = false, ...props }) => {
return ( return (
<Button {...props} className={`btn-icon p-0 d-inline-flex align-items-stretch ${border ? 'with-border' : ''}`}> <Button { ...props }
className={ `btn-icon p-0 d-inline-flex align-items-stretch ${ border ? 'with-border' : '' }` }>
<span className="icon-part d-flex align-items-center"> <span className="icon-part d-flex align-items-center">
<ForkAwesomeIcon icon={ icon } className={ 'icon' }/> <ForkAwesomeIcon icon={ icon } className={ 'icon' }/>
</span> </span>

View file

@ -26,7 +26,8 @@ export const CommonModal: React.FC<CommonModalProps> = ({ show, onHide, titleI18
useTranslation() useTranslation()
return ( return (
<Modal data-cy={'limitReachedModal'} show={show} onHide={onHide} animation={true} dialogClassName={`text-dark ${additionalClasses ?? ''}`} size={size}> <Modal data-cy={ 'limitReachedModal' } show={ show } onHide={ onHide } animation={ true }
dialogClassName={ `text-dark ${ additionalClasses ?? '' }` } size={ size }>
<Modal.Header closeButton={ !!closeButton }> <Modal.Header closeButton={ !!closeButton }>
<Modal.Title> <Modal.Title>
<ShowIf condition={ !!icon }> <ShowIf condition={ !!icon }>

View file

@ -5,5 +5,6 @@
*/ */
export const createNumberRangeArray = (length: number): number[] => { export const createNumberRangeArray = (length: number): number[] => {
return Array.from(Array(length).keys()) return Array.from(Array(length)
.keys())
} }

View file

@ -53,12 +53,15 @@ export const PagerPagination: React.FC<PaginationProps> = ({ numberOfPageButtons
0 0
) )
const paginationItemsBefore = Array.from(new Array(correctedPageIndex - correctedLowerPageIndex)).map((k, index) => { const paginationItemsBefore = Array.from(new Array(correctedPageIndex - correctedLowerPageIndex))
.map((k, index) => {
const itemIndex = correctedLowerPageIndex + index const itemIndex = correctedLowerPageIndex + index
return <PagerItem key={itemIndex} index={itemIndex} onClick={setPageIndex}/> return <PagerItem key={ itemIndex } index={ itemIndex }
onClick={ setPageIndex }/>
}) })
const paginationItemsAfter = Array.from(new Array(correctedUpperPageIndex - correctedPageIndex)).map((k, index) => { const paginationItemsAfter = Array.from(new Array(correctedUpperPageIndex - correctedPageIndex))
.map((k, index) => {
const itemIndex = correctedPageIndex + index + 1 const itemIndex = correctedPageIndex + index + 1
return <PagerItem key={ itemIndex } index={ itemIndex } onClick={ setPageIndex }/> return <PagerItem key={ itemIndex } index={ itemIndex } onClick={ setPageIndex }/>
}) })

View file

@ -22,7 +22,8 @@ export const Pager: React.FC<PagerPageProps> = ({ children, numberOfElementsPerP
return <Fragment> return <Fragment>
{ {
React.Children.toArray(children).filter((value, index) => { React.Children.toArray(children)
.filter((value, index) => {
const pageOfElement = Math.floor((index) / numberOfElementsPerPage) const pageOfElement = Math.floor((index) / numberOfElementsPerPage)
return (pageOfElement === correctedPageIndex) return (pageOfElement === correctedPageIndex)
}) })

View file

@ -56,7 +56,9 @@ export const DocumentInfobar: React.FC<DocumentInfobarProps> = ({
<span className={ 'ml-auto' }> <span className={ 'ml-auto' }>
{ viewCount } <Trans i18nKey={ 'views.readOnly.viewCount' }/> { viewCount } <Trans i18nKey={ 'views.readOnly.viewCount' }/>
<ShowIf condition={ editable }> <ShowIf condition={ editable }>
<InternalLink text={''} href={`/n/${noteId}`} icon={'pencil'} className={'text-primary text-decoration-none mx-1'} title={t('views.readOnly.editNote')}/> <InternalLink text={ '' } href={ `/n/${ noteId }` } icon={ 'pencil' }
className={ 'text-primary text-decoration-none mx-1' }
title={ t('views.readOnly.editNote') }/>
</ShowIf> </ShowIf>
</span> </span>
</div> </div>

View file

@ -55,7 +55,7 @@ export const DocumentReadOnlyPage: React.FC = () => {
noteId={ id } noteId={ id }
viewCount={ noteDetails.viewCount } viewCount={ noteDetails.viewCount }
/> />
<RenderIframe extraClasses={"flex-fill"} <RenderIframe extraClasses={ 'flex-fill' }
markdownContent={ markdownContent } markdownContent={ markdownContent }
onFirstHeadingChange={ onFirstHeadingChange } onFirstHeadingChange={ onFirstHeadingChange }
onFrontmatterChange={ onFrontmatterChange }/> onFrontmatterChange={ onFrontmatterChange }/>

View file

@ -46,7 +46,8 @@ export const AppBar: React.FC<AppBarProps> = ({ mode }) => {
</ShowIf> </ShowIf>
<DarkModeButton/> <DarkModeButton/>
<Link to={ `/p/${ id }` } target='_blank'> <Link to={ `/p/${ id }` } target='_blank'>
<Button title={t('editor.documentBar.slideMode')} className="ml-2 text-secondary" size="sm" variant="outline-light"> <Button title={ t('editor.documentBar.slideMode') } className="ml-2 text-secondary" size="sm"
variant="outline-light">
<ForkAwesomeIcon icon="television"/> <ForkAwesomeIcon icon="television"/>
</Button> </Button>
</Link> </Link>

View file

@ -43,22 +43,26 @@ export const HelpButton: React.FC = () => {
<Modal show={ show } onHide={ () => setShow(false) } animation={ true } className='text-dark' size='lg'> <Modal show={ show } onHide={ () => setShow(false) } animation={ true } className='text-dark' size='lg'>
<Modal.Header closeButton> <Modal.Header closeButton>
<Modal.Title> <Modal.Title>
<ForkAwesomeIcon icon='question-circle'/> <Trans i18nKey={'editor.documentBar.help'}/> <Trans i18nKey={`editor.help.${tab}`}/> <ForkAwesomeIcon icon='question-circle'/> <Trans i18nKey={ 'editor.documentBar.help' }/> <Trans
i18nKey={ `editor.help.${ tab }` }/>
</Modal.Title> </Modal.Title>
</Modal.Header> </Modal.Header>
<Modal.Body> <Modal.Body>
<nav className='nav nav-tabs'> <nav className='nav nav-tabs'>
<Button variant={'light'} className={`nav-link nav-item ${tab === HelpTabStatus.Cheatsheet ? 'active' : ''}`} <Button variant={ 'light' }
className={ `nav-link nav-item ${ tab === HelpTabStatus.Cheatsheet ? 'active' : '' }` }
onClick={ () => setTab(HelpTabStatus.Cheatsheet) } onClick={ () => setTab(HelpTabStatus.Cheatsheet) }
> >
<Trans i18nKey={ 'editor.help.cheatsheet.title' }/> <Trans i18nKey={ 'editor.help.cheatsheet.title' }/>
</Button> </Button>
<Button variant={'light'} className={`nav-link nav-item ${tab === HelpTabStatus.Shortcuts ? 'active' : ''}`} <Button variant={ 'light' }
className={ `nav-link nav-item ${ tab === HelpTabStatus.Shortcuts ? 'active' : '' }` }
onClick={ () => setTab(HelpTabStatus.Shortcuts) } onClick={ () => setTab(HelpTabStatus.Shortcuts) }
> >
<Trans i18nKey={ 'editor.help.shortcuts.title' }/> <Trans i18nKey={ 'editor.help.shortcuts.title' }/>
</Button> </Button>
<Button variant={'light'} className={`nav-link nav-item ${tab === HelpTabStatus.Links ? 'active' : ''}`} <Button variant={ 'light' }
className={ `nav-link nav-item ${ tab === HelpTabStatus.Links ? 'active' : '' }` }
onClick={ () => setTab(HelpTabStatus.Links) } onClick={ () => setTab(HelpTabStatus.Links) }
> >
<Trans i18nKey={ 'editor.help.links.title' }/> <Trans i18nKey={ 'editor.help.links.title' }/>

View file

@ -30,12 +30,14 @@ export const Shortcut: React.FC = () => {
} }
return ( return (
<Row className={ 'justify-content-center pt-4' }> <Row className={ 'justify-content-center pt-4' }>
{Object.keys(shortcutMap).map(category => { { Object.keys(shortcutMap)
.map(category => {
return ( return (
<Card key={ category } className={ 'm-2 w-50' }> <Card key={ category } className={ 'm-2 w-50' }>
<Card.Header>{ category }</Card.Header> <Card.Header>{ category }</Card.Header>
<ListGroup variant="flush"> <ListGroup variant="flush">
{Object.entries(shortcutMap[category]).map(([functionName, shortcuts]) => { { Object.entries(shortcutMap[category])
.map(([functionName, shortcuts]) => {
return ( return (
<ListGroup.Item key={ functionName } className={ 'd-flex justify-content-between' }> <ListGroup.Item key={ functionName } className={ 'd-flex justify-content-between' }>
<span><Trans i18nKey={ functionName }/></span> <span><Trans i18nKey={ functionName }/></span>

View file

@ -3,9 +3,9 @@
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns="http://www.w3.org/2000/svg"
width="512" width="512"
height="512" height="512"
viewBox="0 0 135.46666 135.46666" viewBox="0 0 135.46666 135.46666"

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -9,6 +9,7 @@
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
.btn { .btn {
svg g { svg g {
@import "../../../../style/variables.light"; @import "../../../../style/variables.light";

View file

@ -31,7 +31,8 @@ export const DocumentInfoModal: React.FC<DocumentInfoModalProps> = ({show, onHid
<DocumentInfoTimeLine <DocumentInfoTimeLine
size={ '2x' } size={ '2x' }
mode={ DocumentInfoLineWithTimeMode.CREATED } mode={ DocumentInfoLineWithTimeMode.CREATED }
time={DateTime.local().minus({ days: 11 })} time={ DateTime.local()
.minus({ days: 11 }) }
userName={ 'Tilman' } userName={ 'Tilman' }
profileImageSrc={ '/img/avatar.png' }/> profileImageSrc={ '/img/avatar.png' }/>
</ListGroup.Item> </ListGroup.Item>
@ -39,7 +40,8 @@ export const DocumentInfoModal: React.FC<DocumentInfoModalProps> = ({show, onHid
<DocumentInfoTimeLine <DocumentInfoTimeLine
size={ '2x' } size={ '2x' }
mode={ DocumentInfoLineWithTimeMode.EDITED } mode={ DocumentInfoLineWithTimeMode.EDITED }
time={DateTime.local().minus({ minutes: 3 })} time={ DateTime.local()
.minus({ minutes: 3 }) }
userName={ 'Philip' } userName={ 'Philip' }
profileImageSrc={ '/img/avatar.png' }/> profileImageSrc={ '/img/avatar.png' }/>
</ListGroup.Item> </ListGroup.Item>
@ -60,5 +62,5 @@ export const DocumentInfoModal: React.FC<DocumentInfoModalProps> = ({show, onHid
</ListGroup> </ListGroup>
</Modal.Body> </Modal.Body>
</CommonModal> </CommonModal>
); )
} }

View file

@ -34,7 +34,8 @@ export const DocumentInfoTimeLine: React.FC<DocumentInfoLineWithTimeProps> = ({
return ( return (
<DocumentInfoLine icon={ icon } size={ size }> <DocumentInfoLine icon={ icon } size={ size }>
<Trans i18nKey={ i18nKey }> <Trans i18nKey={ i18nKey }>
<UserAvatar photo={profileImageSrc} additionalClasses={'font-style-normal bold font-weight-bold'} name={userName} size={size ? 'lg' : undefined}/> <UserAvatar photo={ profileImageSrc } additionalClasses={ 'font-style-normal bold font-weight-bold' }
name={ userName } size={ size ? 'lg' : undefined }/>
<TimeFromNow time={ time }/> <TimeFromNow time={ time }/>
</Trans> </Trans>
</DocumentInfoLine> </DocumentInfoLine>

View file

@ -14,6 +14,7 @@ export interface TimeFromNowProps {
export const TimeFromNow: React.FC<TimeFromNowProps> = ({ time }) => { export const TimeFromNow: React.FC<TimeFromNowProps> = ({ time }) => {
return ( return (
<time className={'mx-1'} title={time.toFormat('DDDD T')} dateTime={time.toString()}>{time.toRelative()}</time> <time className={ 'mx-1' } title={ time.toFormat('DDDD T') }
dateTime={ time.toString() }>{ time.toRelative() }</time>
) )
} }

View file

@ -69,22 +69,26 @@ export const PermissionModal: React.FC<PermissionsModalProps> = ({ show, onHide
useEffect(() => { useEffect(() => {
// set owner // set owner
getUserById(permissionsApiResponse.owner).then(response => { getUserById(permissionsApiResponse.owner)
.then(response => {
setOwner({ setOwner({
name: response.name, name: response.name,
photo: response.photo photo: response.photo
}) })
}).catch(() => setError(true)) })
.catch(() => setError(true))
// set user List // set user List
permissionsApiResponse.sharedTo.forEach(shareUser => { permissionsApiResponse.sharedTo.forEach(shareUser => {
getUserById(shareUser.username).then(response => { getUserById(shareUser.username)
.then(response => {
setUserList(list => list.concat([{ setUserList(list => list.concat([{
id: response.id, id: response.id,
name: response.name, name: response.name,
photo: response.photo, photo: response.photo,
canEdit: shareUser.canEdit canEdit: shareUser.canEdit
}])) }]))
}).catch(() => setError(true)) })
.catch(() => setError(true))
}) })
// set group List // set group List
permissionsApiResponse.sharedToGroup.forEach(sharedGroup => { permissionsApiResponse.sharedToGroup.forEach(sharedGroup => {

View file

@ -29,7 +29,8 @@ export const RevisionModalListEntry: React.FC<RevisionModalListEntryProps> = ({
> >
<span> <span>
<ForkAwesomeIcon icon={ 'clock-o' } className='mx-2'/> <ForkAwesomeIcon icon={ 'clock-o' } className='mx-2'/>
{DateTime.fromMillis(revision.timestamp * 1000).toFormat('DDDD T')} { DateTime.fromMillis(revision.timestamp * 1000)
.toFormat('DDDD T') }
</span> </span>
<span> <span>
<ForkAwesomeIcon icon={ 'file-text-o' } className='mx-2'/> <ForkAwesomeIcon icon={ 'file-text-o' } className='mx-2'/>
@ -38,9 +39,11 @@ export const RevisionModalListEntry: React.FC<RevisionModalListEntryProps> = ({
<span className={ 'd-flex flex-row my-1 align-items-center' }> <span className={ 'd-flex flex-row my-1 align-items-center' }>
<ForkAwesomeIcon icon={ 'user-o' } className={ 'mx-2' }/> <ForkAwesomeIcon icon={ 'user-o' } className={ 'mx-2' }/>
{ {
revisionAuthorListMap.get(revision.timestamp)?.map((user, index) => { revisionAuthorListMap.get(revision.timestamp)
?.map((user, index) => {
return ( return (
<UserAvatar name={user.name} photo={user.photo} showName={false} additionalClasses={'mx-1'} key={index}/> <UserAvatar name={ user.name } photo={ user.photo } showName={ false }
additionalClasses={ 'mx-1' } key={ index }/>
) )
}) })
} }

View file

@ -36,7 +36,8 @@ export const RevisionModal: React.FC<PermissionsModalProps> = ({ show, onHide })
const { id } = useParams<{ id: string }>() const { id } = useParams<{ id: string }>()
useEffect(() => { useEffect(() => {
getAllRevisions(id).then(fetchedRevisions => { getAllRevisions(id)
.then(fetchedRevisions => {
fetchedRevisions.forEach(revision => { fetchedRevisions.forEach(revision => {
const authorData = getUserDataForRevision(revision.authors) const authorData = getUserDataForRevision(revision.authors)
revisionAuthorListMap.current.set(revision.timestamp, authorData) revisionAuthorListMap.current.set(revision.timestamp, authorData)
@ -45,22 +46,26 @@ export const RevisionModal: React.FC<PermissionsModalProps> = ({ show, onHide })
if (fetchedRevisions.length >= 1) { if (fetchedRevisions.length >= 1) {
setSelectedRevisionTimestamp(fetchedRevisions[0].timestamp) setSelectedRevisionTimestamp(fetchedRevisions[0].timestamp)
} }
}).catch(() => setError(true)) })
.catch(() => setError(true))
}, [setRevisions, setError, id]) }, [setRevisions, setError, id])
useEffect(() => { useEffect(() => {
if (selectedRevisionTimestamp === null) { if (selectedRevisionTimestamp === null) {
return return
} }
getRevision(id, selectedRevisionTimestamp).then(fetchedRevision => { getRevision(id, selectedRevisionTimestamp)
.then(fetchedRevision => {
setSelectedRevision(fetchedRevision) setSelectedRevision(fetchedRevision)
}).catch(() => setError(true)) })
.catch(() => setError(true))
}, [selectedRevisionTimestamp, id]) }, [selectedRevisionTimestamp, id])
const markdownContent = useNoteMarkdownContent() const markdownContent = useNoteMarkdownContent()
return ( return (
<CommonModal show={show} onHide={onHide} titleI18nKey={'editor.modal.revision.title'} icon={'history'} closeButton={true} size={'xl'} additionalClasses='revision-modal'> <CommonModal show={ show } onHide={ onHide } titleI18nKey={ 'editor.modal.revision.title' } icon={ 'history' }
closeButton={ true } size={ 'xl' } additionalClasses='revision-modal'>
<Modal.Body> <Modal.Body>
<Row> <Row>
<Col lg={ 4 } className={ 'scroll-col' }> <Col lg={ 4 } className={ 'scroll-col' }>

View file

@ -41,11 +41,13 @@ export const ShareModal: React.FC<ShareModalProps> = ({ show, onHide }) => {
url={ `${ baseUrl }/n/${ id }?${ editorMode }` }/> url={ `${ baseUrl }/n/${ id }?${ editorMode }` }/>
<ShowIf condition={ noteFrontmatter.type === 'slide' }> <ShowIf condition={ noteFrontmatter.type === 'slide' }>
<Trans i18nKey={ 'editor.modal.shareLink.slidesDescription' }/> <Trans i18nKey={ 'editor.modal.shareLink.slidesDescription' }/>
<CopyableField content={`${baseUrl}/p/${id}`} nativeShareButton={true} url={`${baseUrl}/p/${id}`}/> <CopyableField content={ `${ baseUrl }/p/${ id }` } nativeShareButton={ true }
url={ `${ baseUrl }/p/${ id }` }/>
</ShowIf> </ShowIf>
<ShowIf condition={ noteFrontmatter.type === '' }> <ShowIf condition={ noteFrontmatter.type === '' }>
<Trans i18nKey={ 'editor.modal.shareLink.viewOnlyDescription' }/> <Trans i18nKey={ 'editor.modal.shareLink.viewOnlyDescription' }/>
<CopyableField content={`${baseUrl}/s/${id}`} nativeShareButton={true} url={`${baseUrl}/s/${id}`}/> <CopyableField content={ `${ baseUrl }/s/${ id }` } nativeShareButton={ true }
url={ `${ baseUrl }/s/${ id }` }/>
</ShowIf> </ShowIf>
</Modal.Body> </Modal.Body>
</CommonModal> </CommonModal>

View file

@ -24,7 +24,7 @@ export const useOnIframeLoad = (frameReference: RefObject<HTMLIFrameElement>, if
return return
} else { } else {
onNavigateAway() onNavigateAway()
console.error("Navigated away from unknown URL") console.error('Navigated away from unknown URL')
frame.src = renderPageUrl frame.src = renderPageUrl
sendToRenderPage.current = true sendToRenderPage.current = true
} }

View file

@ -19,7 +19,8 @@ export const MaxLengthWarningModal: React.FC<MaxLengthWarningModalProps> = ({ sh
useTranslation() useTranslation()
return ( return (
<CommonModal data-cy={'limitReachedModal'} show={show} onHide={onHide} titleI18nKey={'editor.error.limitReached.title'} closeButton={true}> <CommonModal data-cy={ 'limitReachedModal' } show={ show } onHide={ onHide }
titleI18nKey={ 'editor.error.limitReached.title' } closeButton={ true }>
<Modal.Body> <Modal.Body>
<Trans i18nKey={ 'editor.error.limitReached.description' } values={ { maxLength } }/> <Trans i18nKey={ 'editor.error.limitReached.description' } values={ { maxLength } }/>
<strong className='mt-2 d-block'><Trans i18nKey={ 'editor.error.limitReached.advice' }/></strong> <strong className='mt-2 d-block'><Trans i18nKey={ 'editor.error.limitReached.advice' }/></strong>

View file

@ -58,7 +58,8 @@ export const EditorPage: React.FC = () => {
useEffect(() => { useEffect(() => {
const requestedMode = search.substr(1) const requestedMode = search.substr(1)
const mode = Object.values(EditorMode).find(mode => mode === requestedMode) const mode = Object.values(EditorMode)
.find(mode => mode === requestedMode)
if (mode) { if (mode) {
setEditorMode(mode) setEditorMode(mode)
} }
@ -100,7 +101,7 @@ export const EditorPage: React.FC = () => {
<LoadingNoteAlert show={ loading }/> <LoadingNoteAlert show={ loading }/>
</div> </div>
<ShowIf condition={ !error && !loading }> <ShowIf condition={ !error && !loading }>
<div className={"flex-fill d-flex h-100 w-100 overflow-hidden flex-row"}> <div className={ 'flex-fill d-flex h-100 w-100 overflow-hidden flex-row' }>
<Splitter <Splitter
showLeft={ editorMode === EditorMode.EDITOR || editorMode === EditorMode.BOTH } showLeft={ editorMode === EditorMode.EDITOR || editorMode === EditorMode.BOTH }
left={ left={

View file

@ -21,7 +21,8 @@ const codeBlockHint = (editor: Editor): Promise< Hints| null > => {
} }
const term = searchResult[1] const term = searchResult[1]
if (allSupportedLanguages.length === 0) { if (allSupportedLanguages.length === 0) {
allSupportedLanguages = hljs.default.listLanguages().concat('csv', 'flow', 'html', 'js', 'markmap', 'abc', 'graphviz', 'mermaid', 'vega-lite') allSupportedLanguages = hljs.default.listLanguages()
.concat('csv', 'flow', 'html', 'js', 'markmap', 'abc', 'graphviz', 'mermaid', 'vega-lite')
} }
const suggestions = search(term, allSupportedLanguages) const suggestions = search(term, allSupportedLanguages)
const cursor = editor.getCursor() const cursor = editor.getCursor()

View file

@ -16,7 +16,8 @@ const spoilerSuggestion: Hint = {
const suggestions = validAlertLevels.map((suggestion: string): Hint => ({ const suggestions = validAlertLevels.map((suggestion: string): Hint => ({
text: ':::' + suggestion + '\n\n::: \n', text: ':::' + suggestion + '\n\n::: \n',
displayText: suggestion displayText: suggestion
})).concat(spoilerSuggestion) }))
.concat(spoilerSuggestion)
const containerHint = (editor: Editor): Promise<Hints | null> => { const containerHint = (editor: Editor): Promise<Hints | null> => {
return new Promise((resolve) => { return new Promise((resolve) => {

View file

@ -40,7 +40,8 @@ export const findWordAtCursor = (editor: Editor): findWordAtCursorResponse => {
} }
return { return {
text: line.slice(start, end).toLowerCase(), text: line.slice(start, end)
.toLowerCase(),
start: start, start: start,
end: end end: end
} }
@ -49,7 +50,8 @@ export const findWordAtCursor = (editor: Editor): findWordAtCursorResponse => {
export const search = (term: string, list: string[]): string[] => { export const search = (term: string, list: string[]): string[] => {
const suggestions: string[] = [] const suggestions: string[] = []
list.forEach(item => { list.forEach(item => {
if (item.toLowerCase().startsWith(term.toLowerCase())) { if (item.toLowerCase()
.startsWith(term.toLowerCase())) {
suggestions.push(item) suggestions.push(item)
} }
}) })
@ -64,5 +66,5 @@ export const allHinters: Hinter[] = [
ImageHinter, ImageHinter,
LinkAndExtraTagHinter, LinkAndExtraTagHinter,
PDFHinter, PDFHinter,
CollapsableBlockHinter, CollapsableBlockHinter
] ]

View file

@ -51,7 +51,8 @@ const linkAndExtraTagHint = (editor: Editor): Promise< Hints| null > => {
case 'time': case 'time':
// show the current time when the autocompletion is opened and not when the function is loaded // show the current time when the autocompletion is opened and not when the function is loaded
return { return {
text: `[time=${DateTime.local().toFormat('DDDD T')}]` text: `[time=${ DateTime.local()
.toFormat('DDDD T') }]`
} }
default: default:
return { return {

View file

@ -30,6 +30,7 @@
.CodeMirror-line, .CodeMirror-line-like { .CodeMirror-line, .CodeMirror-line-like {
font-feature-settings: inherit; font-feature-settings: inherit;
} }
.CodeMirror-line, .CodeMirror-line-like { .CodeMirror-line, .CodeMirror-line-like {
font-variant-ligatures: none; font-variant-ligatures: none;
} }

View file

@ -30,7 +30,8 @@ const tab = (editor: Editor) => {
const tab = '\t' const tab = '\t'
// contruct x length spaces // contruct x length spaces
const spaces = Array((editor.getOption('indentUnit') ?? 0) + 1).join(' ') const spaces = Array((editor.getOption('indentUnit') ?? 0) + 1)
.join(' ')
// auto indent whole line when in list or blockquote // auto indent whole line when in list or blockquote
const cursor = editor.getCursor() const cursor = editor.getCursor()
@ -43,7 +44,8 @@ const tab = (editor: Editor) => {
const regex = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))/ const regex = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))/
let match let match
const multiple = editor.getSelection().split('\n').length > 1 || const multiple = editor.getSelection()
.split('\n').length > 1 ||
editor.getSelections().length > 1 editor.getSelections().length > 1
if (multiple) { if (multiple) {

View file

@ -17,32 +17,39 @@ borrow some color from tomorrow-night-eighties
.dark #main-toolbar { .dark #main-toolbar {
background: #1d222a; background: #1d222a;
} }
.dark #working-set-list-container, .dark #working-set-list-container,
.dark #editor-holder .pane-header { .dark #editor-holder .pane-header {
background: #15181e; background: #15181e;
} }
.dark .working-set-header, .dark .working-set-header,
.dark #project-files-header .btn-alt-quiet { .dark #project-files-header .btn-alt-quiet {
background: rgba(204, 217, 255, 0.05); background: rgba(204, 217, 255, 0.05);
} }
.dark .working-set-header > span { .dark .working-set-header > span {
background: transparent; background: transparent;
} }
.dark .sidebar-selection, .dark .sidebar-selection,
.dark .filetree-selection, .dark .filetree-selection,
.dark .sidebar-selection-extension, .dark .sidebar-selection-extension,
.dark .filetree-selection-extension { .dark .filetree-selection-extension {
background: #282c34; background: #282c34;
} }
.dark #status-bar, .dark #status-bar,
.dark #status-indicators { .dark #status-indicators {
background: #15181e; background: #15181e;
border-top-color: #1d222a; border-top-color: #1d222a;
} }
.dark a, .dark a,
.dark .open-files-container li.selected a { .dark .open-files-container li.selected a {
color: #528bff; color: #528bff;
} }
/* Code Styling */ /* Code Styling */
.cm-s-one-dark.CodeMirror, .cm-s-one-dark.CodeMirror,
.cm-s-one-dark .CodeMirror-scroll { .cm-s-one-dark .CodeMirror-scroll {
@ -50,26 +57,33 @@ borrow some color from tomorrow-night-eighties
background-color: #1e2126; background-color: #1e2126;
color: #abb2bf; color: #abb2bf;
} }
.cm-s-one-dark .CodeMirror-activeline-background { .cm-s-one-dark .CodeMirror-activeline-background {
background: transparent; background: transparent;
} }
.cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline-background { .cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline-background {
background: rgba(204, 217, 255, 0.05); background: rgba(204, 217, 255, 0.05);
} }
.show-line-padding .cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline-background { .show-line-padding .cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline-background {
box-shadow: inset 15px 0 0 0 #000; box-shadow: inset 15px 0 0 0 #000;
} }
.cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline .CodeMirror-gutter-elt { .cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline .CodeMirror-gutter-elt {
background: transparent; background: transparent;
color: #5c6370; color: #5c6370;
} }
.cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline .inline-widget .CodeMirror-gutter-elt { .cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline .inline-widget .CodeMirror-gutter-elt {
color: red; color: red;
} }
.cm-s-one-dark .cm-string-2, .cm-s-one-dark .cm-string-2,
.cm-s-one-dark .cm-hr { .cm-s-one-dark .cm-hr {
color: #56b6c2; color: #56b6c2;
} }
.cm-s-one-dark .cm-number, .cm-s-one-dark .cm-number,
.cm-s-one-dark .cm-attribute, .cm-s-one-dark .cm-attribute,
.cm-s-one-dark .cm-qualifier, .cm-s-one-dark .cm-qualifier,
@ -77,9 +91,11 @@ borrow some color from tomorrow-night-eighties
.cm-s-one-dark .cm-atom { .cm-s-one-dark .cm-atom {
color: #eda35e; color: #eda35e;
} }
.cm-s-one-dark .cm-def { .cm-s-one-dark .cm-def {
color: #c678dd; color: #c678dd;
} }
.cm-s-one-dark .cm-property, .cm-s-one-dark .cm-property,
.cm-s-one-dark .cm-variable, .cm-s-one-dark .cm-variable,
.cm-s-one-dark .cm-variable-2, .cm-s-one-dark .cm-variable-2,
@ -89,10 +105,12 @@ borrow some color from tomorrow-night-eighties
.cm-s-one-dark .cm-bracket { .cm-s-one-dark .cm-bracket {
color: #f76e79; color: #f76e79;
} }
/*borrow from tomorrow-night-eighties*/ /*borrow from tomorrow-night-eighties*/
.cm-s-one-dark .cm-variable { .cm-s-one-dark .cm-variable {
color: #99cc99; color: #99cc99;
} }
.cm-s-one-dark .cm-variable-2 { .cm-s-one-dark .cm-variable-2 {
color: #6699cc; color: #6699cc;
} }
@ -101,34 +119,42 @@ borrow some color from tomorrow-night-eighties
color: #5c6370; color: #5c6370;
font-style: italic; font-style: italic;
} }
.cm-s-one-dark .cm-error, .cm-s-one-dark .cm-error,
.cm-s-one-dark .cm-minus { .cm-s-one-dark .cm-minus {
color: #be5046; color: #be5046;
} }
.cm-s-one-dark .cm-header { .cm-s-one-dark .cm-header {
color: #eda35e; color: #eda35e;
} }
.cm-s-one-dark .cm-link { .cm-s-one-dark .cm-link {
color: #98c379; color: #98c379;
text-decoration: none; text-decoration: none;
} }
.cm-s-one-dark .cm-rangeinfo { .cm-s-one-dark .cm-rangeinfo {
color: #c678dd; color: #c678dd;
} }
.cm-s-one-dark .cm-keyword, .cm-s-one-dark .cm-keyword,
.cm-s-one-dark .cm-builtin, .cm-s-one-dark .cm-builtin,
.cm-s-one-dark .cm-tag { .cm-s-one-dark .cm-tag {
color: #e06c75; color: #e06c75;
} }
.cm-s-one-dark .cm-m-markdown.cm-keyword, .cm-s-one-dark .cm-m-markdown.cm-keyword,
.cm-s-one-dark .cm-m-markdown.cm-builtin, .cm-s-one-dark .cm-m-markdown.cm-builtin,
.cm-s-one-dark .cm-m-markdown.cm-tag { .cm-s-one-dark .cm-m-markdown.cm-tag {
color: #98c379; color: #98c379;
} }
.cm-s-one-dark .cm-string { .cm-s-one-dark .cm-string {
/* color: #98c379;*/ /* color: #98c379;*/
color: #6699cc; color: #6699cc;
} }
/* Extra CSS */ /* Extra CSS */
.cm-s-one-dark .CodeMirror-searching { .cm-s-one-dark .CodeMirror-searching {
color: #fff !important; color: #fff !important;
@ -137,32 +163,40 @@ borrow some color from tomorrow-night-eighties
background-color: rgba(204, 217, 255, 0.09); background-color: rgba(204, 217, 255, 0.09);
box-shadow: 0px 0px 6px rgba(66, 133, 244, 0.4); box-shadow: 0px 0px 6px rgba(66, 133, 244, 0.4);
} }
.cm-s-one-dark .CodeMirror-searching.searching-current-match { .cm-s-one-dark .CodeMirror-searching.searching-current-match {
color: #fff; color: #fff;
background-color: #528bff; background-color: #528bff;
box-shadow: 0px 0px 6px rgba(66, 133, 244, 0.8); box-shadow: 0px 0px 6px rgba(66, 133, 244, 0.8);
} }
.cm-s-one-dark .CodeMirror-cursor { .cm-s-one-dark .CodeMirror-cursor {
border-left: 2px solid #528bff !important; border-left: 2px solid #528bff !important;
} }
.cm-fat-cursor .CodeMirror-cursor { .cm-fat-cursor .CodeMirror-cursor {
border-left: 2px solid #3C5B9E !important; border-left: 2px solid #3C5B9E !important;
background: #3C5B9E; background: #3C5B9E;
} }
.cm-s-one-dark .CodeMirror-gutters { .cm-s-one-dark .CodeMirror-gutters {
/* background-color: #282c34;*/ /* background-color: #282c34;*/
background-color: #1e2126; background-color: #1e2126;
border-right: 1px solid rgba(204, 217, 255, 0.05); border-right: 1px solid rgba(204, 217, 255, 0.05);
} }
.cm-s-one-dark .CodeMirror-linenumber { .cm-s-one-dark .CodeMirror-linenumber {
color: #393e46; color: #393e46;
} }
.cm-s-one-dark.CodeMirror .CodeMirror-selected { .cm-s-one-dark.CodeMirror .CodeMirror-selected {
background: rgba(204, 217, 255, 0.05); background: rgba(204, 217, 255, 0.05);
} }
.cm-s-one-dark.CodeMirror-focused .CodeMirror-selected { .cm-s-one-dark.CodeMirror-focused .CodeMirror-selected {
background: rgba(204, 217, 255, 0.09); background: rgba(204, 217, 255, 0.09);
} }
.cm-s-one-dark .CodeMirror-matchingbracket, .cm-s-one-dark .CodeMirror-matchingbracket,
.cm-s-one-dark .CodeMirror-matchingtag { .cm-s-one-dark .CodeMirror-matchingtag {
/* Ensure visibility against gray inline editor background */ /* Ensure visibility against gray inline editor background */
@ -170,52 +204,65 @@ borrow some color from tomorrow-night-eighties
color: #abb2bf !important; color: #abb2bf !important;
border-bottom: 1px solid #528bff; border-bottom: 1px solid #528bff;
} }
.cm-s-one-dark .CodeMirror-overwrite .CodeMirror-cursor { .cm-s-one-dark .CodeMirror-overwrite .CodeMirror-cursor {
border-left: none !important; border-left: none !important;
border-bottom: 1px solid #fff; border-bottom: 1px solid #fff;
width: 0.5em; width: 0.5em;
} }
.cm-s-one-dark.CodeMirror .CodeMirror { .cm-s-one-dark.CodeMirror .CodeMirror {
background: transparent; background: transparent;
} }
.cm-s-one-dark.CodeMirror .CodeMirror .CodeMirror-gutters { .cm-s-one-dark.CodeMirror .CodeMirror .CodeMirror-gutters {
background: transparent; background: transparent;
border-right: none; border-right: none;
} }
.cm-s-one-dark.CodeMirror .CodeMirror .CodeMirror-activeline-background { .cm-s-one-dark.CodeMirror .CodeMirror .CodeMirror-activeline-background {
background: transparent; background: transparent;
} }
.cm-s-one-dark.CodeMirror .CodeMirror .CodeMirror-activeline .CodeMirror-gutter-elt { .cm-s-one-dark.CodeMirror .CodeMirror .CodeMirror-activeline .CodeMirror-gutter-elt {
background: transparent; background: transparent;
color: #5c6370; color: #5c6370;
} }
.cm-s-one-dark.CodeMirror .CodeMirror-focused .CodeMirror-activeline-background { .cm-s-one-dark.CodeMirror .CodeMirror-focused .CodeMirror-activeline-background {
background: #000; background: #000;
} }
.cm-s-one-dark.CodeMirror .CodeMirror-focused .CodeMirror-activeline .CodeMirror-gutter-elt { .cm-s-one-dark.CodeMirror .CodeMirror-focused .CodeMirror-activeline .CodeMirror-gutter-elt {
background: rgba(204, 217, 255, 0.05); background: rgba(204, 217, 255, 0.05);
color: #fff; color: #fff;
} }
.cm-s-one-dark .CodeMirror-foldgutter-open:after { .cm-s-one-dark .CodeMirror-foldgutter-open:after {
color: #393e46; color: #393e46;
} }
.cm-s-one-dark .CodeMirror-foldgutter-folded:after { .cm-s-one-dark .CodeMirror-foldgutter-folded:after {
color: #5c6370; color: #5c6370;
} }
.cm-s-one-dark .CodeMirror.over-gutter .CodeMirror-foldgutter-open:after, .cm-s-one-dark .CodeMirror.over-gutter .CodeMirror-foldgutter-open:after,
.cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline .CodeMirror-foldgutter-open:after { .cm-s-one-dark.CodeMirror-focused .CodeMirror-activeline .CodeMirror-foldgutter-open:after {
color: #5c6370; color: #5c6370;
} }
.cm-s-one-dark .CodeMirror-foldmarker { .cm-s-one-dark .CodeMirror-foldmarker {
border-color: #393e46; border-color: #393e46;
color: #abb2bf; color: #abb2bf;
background: rgba(204, 217, 255, 0.05); background: rgba(204, 217, 255, 0.05);
} }
/* Non-editor styling */ /* Non-editor styling */
.image-view, .image-view,
.not-editor { .not-editor {
background-color: #282c34; background-color: #282c34;
} }
.view-pane .image-view { .view-pane .image-view {
color: #abb2bf; color: #abb2bf;
} }

View file

@ -34,7 +34,8 @@ export const createStatusInfo = (editor: Editor, maxDocumentLength: number): Sta
remainingCharacters: maxDocumentLength - editor.getValue().length, remainingCharacters: maxDocumentLength - editor.getValue().length,
linesInDocument: editor.lineCount(), linesInDocument: editor.lineCount(),
selectedColumns: editor.getSelection().length, selectedColumns: editor.getSelection().length,
selectedLines: editor.getSelection().split('\n').length selectedLines: editor.getSelection()
.split('\n').length
}) })
export const StatusBar: React.FC<StatusBarInfo> = ({ position, selectedColumns, selectedLines, charactersInDocument, linesInDocument, remainingCharacters }) => { export const StatusBar: React.FC<StatusBarInfo> = ({ position, selectedColumns, selectedLines, charactersInDocument, linesInDocument, remainingCharacters }) => {

View file

@ -5,7 +5,7 @@
*/ */
import { EditorConfiguration } from 'codemirror' import { EditorConfiguration } from 'codemirror'
import equal from "fast-deep-equal" import equal from 'fast-deep-equal'
import React, { ChangeEvent, useCallback } from 'react' import React, { ChangeEvent, useCallback } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
@ -33,7 +33,8 @@ export const EditorPreferenceBooleanProperty: React.FC<EditorPreferenceBooleanPr
const i18nPrefix = `editor.modal.preferences.${ property }` const i18nPrefix = `editor.modal.preferences.${ property }`
return ( return (
<EditorPreferenceInput onChange={selectItem} property={property} type={EditorPreferenceInputType.SELECT} value={preference}> <EditorPreferenceInput onChange={ selectItem } property={ property } type={ EditorPreferenceInputType.SELECT }
value={ preference }>
<option value={ 'true' }> <option value={ 'true' }>
{ t(`${ i18nPrefix }.on`) } { t(`${ i18nPrefix }.on`) }
</option> </option>

View file

@ -25,7 +25,8 @@ export const EditorPreferenceInput: React.FC<EditorPreferenceInputProps> = ({ pr
return ( return (
<Form.Group controlId={ `editor-pref-${ property }` }> <Form.Group controlId={ `editor-pref-${ property }` }>
<Form.Label> <Form.Label>
<Trans i18nKey={`editor.modal.preferences.${property}${type===EditorPreferenceInputType.NUMBER ? '' : '.label'}`}/> <Trans
i18nKey={ `editor.modal.preferences.${ property }${ type === EditorPreferenceInputType.NUMBER ? '' : '.label' }` }/>
</Form.Label> </Form.Label>
<Form.Control <Form.Control
as={ type === EditorPreferenceInputType.NUMBER ? 'input' : 'select' } as={ type === EditorPreferenceInputType.NUMBER ? 'input' : 'select' }

View file

@ -11,7 +11,8 @@ import { setEditorLigatures } from '../../../../../redux/editor/methods'
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input' import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
export const EditorPreferenceLigaturesSelect: React.FC = () => { export const EditorPreferenceLigaturesSelect: React.FC = () => {
const ligaturesEnabled = useSelector((state: ApplicationState) => Boolean(state.editorConfig.ligatures).toString()) const ligaturesEnabled = useSelector((state: ApplicationState) => Boolean(state.editorConfig.ligatures)
.toString())
const saveLigatures = useCallback((event: ChangeEvent<HTMLSelectElement>) => { const saveLigatures = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
const ligaturesActivated: boolean = event.target.value === 'true' const ligaturesActivated: boolean = event.target.value === 'true'
setEditorLigatures(ligaturesActivated) setEditorLigatures(ligaturesActivated)
@ -19,7 +20,7 @@ export const EditorPreferenceLigaturesSelect: React.FC = () => {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<EditorPreferenceInput onChange={saveLigatures} value={ligaturesEnabled} property={"ligatures"} <EditorPreferenceInput onChange={ saveLigatures } value={ ligaturesEnabled } property={ 'ligatures' }
type={ EditorPreferenceInputType.BOOLEAN }> type={ EditorPreferenceInputType.BOOLEAN }>
<option value='true'>{ t(`common.yes`) }</option> <option value='true'>{ t(`common.yes`) }</option>
<option value='false'>{ t(`common.no`) }</option> <option value='false'>{ t(`common.no`) }</option>

View file

@ -5,7 +5,7 @@
*/ */
import { EditorConfiguration } from 'codemirror' import { EditorConfiguration } from 'codemirror'
import equal from "fast-deep-equal" import equal from 'fast-deep-equal'
import React, { ChangeEvent, useCallback } from 'react' import React, { ChangeEvent, useCallback } from 'react'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import { ApplicationState } from '../../../../../redux' import { ApplicationState } from '../../../../../redux'
@ -29,6 +29,7 @@ export const EditorPreferenceNumberProperty: React.FC<EditorPreferenceNumberProp
}, [property]) }, [property])
return ( return (
<EditorPreferenceInput onChange={selectItem} property={property} type={EditorPreferenceInputType.NUMBER} value={preference}/> <EditorPreferenceInput onChange={ selectItem } property={ property } type={ EditorPreferenceInputType.NUMBER }
value={ preference }/>
) )
} }

View file

@ -5,7 +5,7 @@
*/ */
import { EditorConfiguration } from 'codemirror' import { EditorConfiguration } from 'codemirror'
import equal from "fast-deep-equal" import equal from 'fast-deep-equal'
import React, { ChangeEvent, useCallback } from 'react' import React, { ChangeEvent, useCallback } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
@ -35,7 +35,8 @@ export const EditorPreferenceSelectProperty: React.FC<EditorPreferenceSelectProp
const i18nPrefix = `editor.modal.preferences.${ property }` const i18nPrefix = `editor.modal.preferences.${ property }`
return ( return (
<EditorPreferenceInput onChange={selectItem} property={property} type={EditorPreferenceInputType.SELECT} value={preference}> <EditorPreferenceInput onChange={ selectItem } property={ property } type={ EditorPreferenceInputType.SELECT }
value={ preference }>
{ selections.map(selection => { selections.map(selection =>
<option key={ selection } value={ selection }> <option key={ selection } value={ selection }>
{ t(`${ i18nPrefix }.${ selection }`) } { t(`${ i18nPrefix }.${ selection }`) }

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import equal from "fast-deep-equal" import equal from 'fast-deep-equal'
import React, { Fragment, useState } from 'react' import React, { Fragment, useState } from 'react'
import { Button, Form, ListGroup } from 'react-bootstrap' import { Button, Form, ListGroup } from 'react-bootstrap'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -17,8 +17,8 @@ import { EditorPreferenceBooleanProperty } from './editor-preference-boolean-pro
import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input' import { EditorPreferenceInput, EditorPreferenceInputType } from './editor-preference-input'
import { EditorPreferenceLigaturesSelect } from './editor-preference-ligatures-select' import { EditorPreferenceLigaturesSelect } from './editor-preference-ligatures-select'
import { EditorPreferenceNumberProperty } from './editor-preference-number-property' import { EditorPreferenceNumberProperty } from './editor-preference-number-property'
import { EditorPreferenceProperty } from "./editor-preference-property" import { EditorPreferenceProperty } from './editor-preference-property'
import { EditorPreferenceSelectProperty } from "./editor-preference-select-property" import { EditorPreferenceSelectProperty } from './editor-preference-select-property'
export const EditorPreferences: React.FC = () => { export const EditorPreferences: React.FC = () => {
const { t } = useTranslation() const { t } = useTranslation()
@ -39,10 +39,12 @@ export const EditorPreferences: React.FC = () => {
<Form> <Form>
<ListGroup> <ListGroup>
<ListGroup.Item> <ListGroup.Item>
<EditorPreferenceSelectProperty property={EditorPreferenceProperty.THEME} selections={['one-dark', 'neat']}/> <EditorPreferenceSelectProperty property={ EditorPreferenceProperty.THEME }
selections={ ['one-dark', 'neat'] }/>
</ListGroup.Item> </ListGroup.Item>
<ListGroup.Item> <ListGroup.Item>
<EditorPreferenceSelectProperty property={EditorPreferenceProperty.KEYMAP} selections={['sublime', 'emacs', 'vim']}/> <EditorPreferenceSelectProperty property={ EditorPreferenceProperty.KEYMAP }
selections={ ['sublime', 'emacs', 'vim'] }/>
</ListGroup.Item> </ListGroup.Item>
<ListGroup.Item> <ListGroup.Item>
<EditorPreferenceBooleanProperty property={ EditorPreferenceProperty.INDENT_WITH_TABS }/> <EditorPreferenceBooleanProperty property={ EditorPreferenceProperty.INDENT_WITH_TABS }/>
@ -56,7 +58,9 @@ export const EditorPreferences: React.FC = () => {
<EditorPreferenceLigaturesSelect/> <EditorPreferenceLigaturesSelect/>
</ListGroup.Item> </ListGroup.Item>
<ListGroup.Item> <ListGroup.Item>
<EditorPreferenceInput onChange={() => alert('This feature is not yet implemented.')} property={EditorPreferenceProperty.SPELL_CHECK} type={EditorPreferenceInputType.SELECT}> <EditorPreferenceInput onChange={ () => alert('This feature is not yet implemented.') }
property={ EditorPreferenceProperty.SPELL_CHECK }
type={ EditorPreferenceInputType.SELECT }>
<option value='off'>Off</option> <option value='off'>Off</option>
<option value='en'>English</option> <option value='en'>English</option>
</EditorPreferenceInput> </EditorPreferenceInput>

View file

@ -29,7 +29,8 @@ export const EmojiPickerButton: React.FC<EmojiPickerButtonProps> = ({ editor })
addEmoji(emoji, editor) addEmoji(emoji, editor)
} } } }
onDismiss={ () => setShowEmojiPicker(false) }/> onDismiss={ () => setShowEmojiPicker(false) }/>
<Button data-cy={'show-emoji-picker'} variant='light' onClick={() => setShowEmojiPicker(old => !old)} title={t('editor.editorToolbar.emoji')}> <Button data-cy={ 'show-emoji-picker' } variant='light' onClick={ () => setShowEmojiPicker(old => !old) }
title={ t('editor.editorToolbar.emoji') }>
<ForkAwesomeIcon icon="smile-o"/> <ForkAwesomeIcon icon="smile-o"/>
</Button> </Button>
</Fragment> </Fragment>

View file

@ -19,7 +19,8 @@ export interface EmojiPickerProps {
onDismiss: () => void onDismiss: () => void
} }
export const customEmojis: CustomEmoji[] = Object.keys(ForkAwesomeIcons).map((name) => ({ export const customEmojis: CustomEmoji[] = Object.keys(ForkAwesomeIcons)
.map((name) => ({
name: `fa-${ name }`, name: `fa-${ name }`,
shortcodes: [`fa-${ name.toLowerCase() }`], shortcodes: [`fa-${ name.toLowerCase() }`],
url: forkawesomeIcon, url: forkawesomeIcon,
@ -92,6 +93,7 @@ export const EmojiPicker: React.FC<EmojiPickerProps> = ({ show, onEmojiSelected,
}, [darkModeEnabled]) }, [darkModeEnabled])
return ( return (
<div className={`position-absolute emoji-picker-container ${!show ? 'd-none' : ''}`} ref={pickerContainerRef}/> <div className={ `position-absolute emoji-picker-container ${ !show ? 'd-none' : '' }` }
ref={ pickerContainerRef }/>
) )
} }

View file

@ -30,7 +30,8 @@ export const TablePickerButton: React.FC<TablePickerButtonProps> = ({ editor })
addTable(editor, rows, cols) addTable(editor, rows, cols)
} } } }
/> />
<Button data-cy={'show-table-overlay'} variant='light' onClick={() => setShowTablePicker(old => !old)} title={t('editor.editorToolbar.table.title')}> <Button data-cy={ 'show-table-overlay' } variant='light' onClick={ () => setShowTablePicker(old => !old) }
title={ t('editor.editorToolbar.table.title') }>
<ForkAwesomeIcon icon="table"/> <ForkAwesomeIcon icon="table"/>
</Button> </Button>
</Fragment> </Fragment>

View file

@ -5,7 +5,6 @@
*/ */
.table-picker-container { .table-picker-container {
z-index: 1111; z-index: 1111;

View file

@ -45,7 +45,8 @@ export const TablePicker: React.FC<TablePickerProps> = ({ show, onDismiss, onTab
}, [onTablePicked, tableSize]) }, [onTablePicked, tableSize])
return ( return (
<div className={`position-absolute table-picker-container p-2 ${!show || showDialog ? 'd-none' : ''} bg-light`} ref={containerRef} role="grid"> <div className={ `position-absolute table-picker-container p-2 ${ !show || showDialog ? 'd-none' : '' } bg-light` }
ref={ containerRef } role="grid">
<p className={ 'lead' }> <p className={ 'lead' }>
{ tableSize { tableSize
? t('editor.editorToolbar.table.size', { cols: tableSize?.columns, rows: tableSize.rows }) ? t('editor.editorToolbar.table.size', { cols: tableSize?.columns, rows: tableSize.rows })
@ -53,8 +54,10 @@ export const TablePicker: React.FC<TablePickerProps> = ({ show, onDismiss, onTab
} }
</p> </p>
<div className={ 'table-container' }> <div className={ 'table-container' }>
{createNumberRangeArray(8).map((row: number) => ( { createNumberRangeArray(8)
createNumberRangeArray(10).map((col: number) => ( .map((row: number) => (
createNumberRangeArray(10)
.map((col: number) => (
<div <div
key={ `${ row }_${ col }` } key={ `${ row }_${ col }` }
className={ `table-cell ${ tableSize && row < tableSize.rows && col < tableSize.columns ? 'bg-primary' : '' }` } className={ `table-cell ${ tableSize && row < tableSize.rows && col < tableSize.columns ? 'bg-primary' : '' }` }

View file

@ -48,63 +48,80 @@ export const ToolBar: React.FC<ToolBarProps> = ({ editor }) => {
return ( return (
<ButtonToolbar className='bg-light'> <ButtonToolbar className='bg-light'>
<ButtonGroup className={ 'mx-1 flex-wrap' }> <ButtonGroup className={ 'mx-1 flex-wrap' }>
<Button data-cy={'format-bold'} variant='light' onClick={() => makeSelectionBold(editor)} title={t('editor.editorToolbar.bold')}> <Button data-cy={ 'format-bold' } variant='light' onClick={ () => makeSelectionBold(editor) }
title={ t('editor.editorToolbar.bold') }>
<ForkAwesomeIcon icon="bold"/> <ForkAwesomeIcon icon="bold"/>
</Button> </Button>
<Button data-cy={'format-italic'} variant='light' onClick={() => makeSelectionItalic(editor)} title={t('editor.editorToolbar.italic')}> <Button data-cy={ 'format-italic' } variant='light' onClick={ () => makeSelectionItalic(editor) }
title={ t('editor.editorToolbar.italic') }>
<ForkAwesomeIcon icon="italic"/> <ForkAwesomeIcon icon="italic"/>
</Button> </Button>
<Button data-cy={'format-underline'} variant='light' onClick={() => underlineSelection(editor)} title={t('editor.editorToolbar.underline')}> <Button data-cy={ 'format-underline' } variant='light' onClick={ () => underlineSelection(editor) }
title={ t('editor.editorToolbar.underline') }>
<ForkAwesomeIcon icon="underline"/> <ForkAwesomeIcon icon="underline"/>
</Button> </Button>
<Button data-cy={'format-strikethrough'} variant='light' onClick={() => strikeThroughSelection(editor)} title={t('editor.editorToolbar.strikethrough')}> <Button data-cy={ 'format-strikethrough' } variant='light' onClick={ () => strikeThroughSelection(editor) }
title={ t('editor.editorToolbar.strikethrough') }>
<ForkAwesomeIcon icon="strikethrough"/> <ForkAwesomeIcon icon="strikethrough"/>
</Button> </Button>
<Button data-cy={'format-subscript'} variant='light' onClick={() => subscriptSelection(editor)} title={t('editor.editorToolbar.subscript')}> <Button data-cy={ 'format-subscript' } variant='light' onClick={ () => subscriptSelection(editor) }
title={ t('editor.editorToolbar.subscript') }>
<ForkAwesomeIcon icon="subscript"/> <ForkAwesomeIcon icon="subscript"/>
</Button> </Button>
<Button data-cy={'format-superscript'} variant='light' onClick={() => superscriptSelection(editor)} title={t('editor.editorToolbar.superscript')}> <Button data-cy={ 'format-superscript' } variant='light' onClick={ () => superscriptSelection(editor) }
title={ t('editor.editorToolbar.superscript') }>
<ForkAwesomeIcon icon="superscript"/> <ForkAwesomeIcon icon="superscript"/>
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<ButtonGroup className={ 'mx-1 flex-wrap' }> <ButtonGroup className={ 'mx-1 flex-wrap' }>
<Button data-cy={'format-heading'} variant='light' onClick={() => addHeaderLevel(editor)} title={t('editor.editorToolbar.header')}> <Button data-cy={ 'format-heading' } variant='light' onClick={ () => addHeaderLevel(editor) }
title={ t('editor.editorToolbar.header') }>
<ForkAwesomeIcon icon="header"/> <ForkAwesomeIcon icon="header"/>
</Button> </Button>
<Button data-cy={'format-code-block'} variant='light' onClick={() => addCodeFences(editor)} title={t('editor.editorToolbar.code')}> <Button data-cy={ 'format-code-block' } variant='light' onClick={ () => addCodeFences(editor) }
title={ t('editor.editorToolbar.code') }>
<ForkAwesomeIcon icon="code"/> <ForkAwesomeIcon icon="code"/>
</Button> </Button>
<Button data-cy={'format-block-quote'} variant='light' onClick={() => addQuotes(editor)} title={t('editor.editorToolbar.blockquote')}> <Button data-cy={ 'format-block-quote' } variant='light' onClick={ () => addQuotes(editor) }
title={ t('editor.editorToolbar.blockquote') }>
<ForkAwesomeIcon icon="quote-right"/> <ForkAwesomeIcon icon="quote-right"/>
</Button> </Button>
<Button data-cy={'format-unordered-list'} variant='light' onClick={() => addList(editor)} title={t('editor.editorToolbar.unorderedList')}> <Button data-cy={ 'format-unordered-list' } variant='light' onClick={ () => addList(editor) }
title={ t('editor.editorToolbar.unorderedList') }>
<ForkAwesomeIcon icon="list"/> <ForkAwesomeIcon icon="list"/>
</Button> </Button>
<Button data-cy={'format-ordered-list'} variant='light' onClick={() => addOrderedList(editor)} title={t('editor.editorToolbar.orderedList')}> <Button data-cy={ 'format-ordered-list' } variant='light' onClick={ () => addOrderedList(editor) }
title={ t('editor.editorToolbar.orderedList') }>
<ForkAwesomeIcon icon="list-ol"/> <ForkAwesomeIcon icon="list-ol"/>
</Button> </Button>
<Button data-cy={'format-check-list'} variant='light' onClick={() => addTaskList(editor)} title={t('editor.editorToolbar.checkList')}> <Button data-cy={ 'format-check-list' } variant='light' onClick={ () => addTaskList(editor) }
title={ t('editor.editorToolbar.checkList') }>
<ForkAwesomeIcon icon="check-square"/> <ForkAwesomeIcon icon="check-square"/>
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<ButtonGroup className={ 'mx-1 flex-wrap' }> <ButtonGroup className={ 'mx-1 flex-wrap' }>
<Button data-cy={'format-link'} variant='light' onClick={() => addLink(editor)} title={t('editor.editorToolbar.link')}> <Button data-cy={ 'format-link' } variant='light' onClick={ () => addLink(editor) }
title={ t('editor.editorToolbar.link') }>
<ForkAwesomeIcon icon="link"/> <ForkAwesomeIcon icon="link"/>
</Button> </Button>
<Button data-cy={'format-image'} variant='light' onClick={() => addImage(editor)} title={t('editor.editorToolbar.image')}> <Button data-cy={ 'format-image' } variant='light' onClick={ () => addImage(editor) }
title={ t('editor.editorToolbar.image') }>
<ForkAwesomeIcon icon="picture-o"/> <ForkAwesomeIcon icon="picture-o"/>
</Button> </Button>
<UploadImageButton editor={ editor }/> <UploadImageButton editor={ editor }/>
</ButtonGroup> </ButtonGroup>
<ButtonGroup className={ 'mx-1 flex-wrap' }> <ButtonGroup className={ 'mx-1 flex-wrap' }>
<TablePickerButton editor={ editor }/> <TablePickerButton editor={ editor }/>
<Button data-cy={'format-add-line'} variant='light' onClick={() => addLine(editor)} title={t('editor.editorToolbar.line')}> <Button data-cy={ 'format-add-line' } variant='light' onClick={ () => addLine(editor) }
title={ t('editor.editorToolbar.line') }>
<ForkAwesomeIcon icon="minus"/> <ForkAwesomeIcon icon="minus"/>
</Button> </Button>
<Button data-cy={'format-collapsable-block'} variant='light' onClick={() => addCollapsableBlock(editor)} title={t('editor.editorToolbar.collapsableBlock')}> <Button data-cy={ 'format-collapsable-block' } variant='light' onClick={ () => addCollapsableBlock(editor) }
title={ t('editor.editorToolbar.collapsableBlock') }>
<ForkAwesomeIcon icon="caret-square-o-down"/> <ForkAwesomeIcon icon="caret-square-o-down"/>
</Button> </Button>
<Button data-cy={'format-add-comment'} variant='light' onClick={() => addComment(editor)} title={t('editor.editorToolbar.comment')}> <Button data-cy={ 'format-add-comment' } variant='light' onClick={ () => addComment(editor) }
title={ t('editor.editorToolbar.comment') }>
<ForkAwesomeIcon icon="comment"/> <ForkAwesomeIcon icon="comment"/>
</Button> </Button>
<EmojiPickerButton editor={ editor }/> <EmojiPickerButton editor={ editor }/>

View file

@ -119,9 +119,12 @@ const mockListSelections = (positions: FromTo, empty: boolean): (() => CodeMirro
const expectFromToReplacement = (position: FromTo, expectedReplacement: string, done: () => void): ((replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => void) => { const expectFromToReplacement = (position: FromTo, expectedReplacement: string, done: () => void): ((replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => void) => {
return (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => { return (replacement: string | string[], from: CodeMirror.Position, to?: CodeMirror.Position) => {
expect(from).toEqual(position.from) expect(from)
expect(to).toEqual(position.to) .toEqual(position.from)
expect(replacement).toEqual(expectedReplacement) expect(to)
.toEqual(position.to)
expect(replacement)
.toEqual(expectedReplacement)
done() done()
} }
} }
@ -421,7 +424,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from, getCursor: () => cursor.from,
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(firstHeading) expect(replacement)
.toEqual(firstHeading)
done() done()
}, },
getLine: (): string => (noHeading) getLine: (): string => (noHeading)
@ -434,7 +438,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from, getCursor: () => cursor.from,
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(secondHeading) expect(replacement)
.toEqual(secondHeading)
done() done()
}, },
getLine: (): string => (firstHeading) getLine: (): string => (firstHeading)
@ -447,7 +452,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from, getCursor: () => cursor.from,
listSelections: mockListSelections(firstLine, false), listSelections: mockListSelections(firstLine, false),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(firstLineFirstHeading) expect(replacement)
.toEqual(firstLineFirstHeading)
done() done()
}, },
getLine: (): string => (firstLineNoHeading) getLine: (): string => (firstLineNoHeading)
@ -460,7 +466,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from, getCursor: () => cursor.from,
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(firstLineFirstHeading) expect(replacement)
.toEqual(firstLineFirstHeading)
done() done()
}, },
getLine: (): string => (firstLineNoHeading) getLine: (): string => (firstLineNoHeading)
@ -473,7 +480,8 @@ describe('test addHeaderLevel', () => {
getCursor: () => cursor.from, getCursor: () => cursor.from,
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(firstLineFirstHeading) expect(replacement)
.toEqual(firstLineFirstHeading)
done() done()
}, },
getLine: (): string => (firstLineNoHeading) getLine: (): string => (firstLineNoHeading)
@ -492,7 +500,8 @@ describe('test addCodeFences', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => '', getLine: (): string => '',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('```\n\n```') expect(replacement)
.toEqual('```\n\n```')
done() done()
} }
}) })
@ -506,7 +515,8 @@ describe('test addCodeFences', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => '1st line', getLine: (): string => '1st line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('```\n1st line\n```') expect(replacement)
.toEqual('```\n1st line\n```')
done() done()
} }
}) })
@ -555,7 +565,8 @@ describe('test addQuotes', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`> ${textFirstLine}`) expect(replacement)
.toEqual(`> ${ textFirstLine }`)
done() done()
} }
}) })
@ -602,7 +613,8 @@ describe('test unordered list', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`- ${textFirstLine}`) expect(replacement)
.toEqual(`- ${ textFirstLine }`)
done() done()
} }
}) })
@ -625,7 +637,8 @@ describe('test unordered list', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('- 2nd line3rd line') expect(replacement)
.toEqual('- 2nd line3rd line')
done() done()
} }
}) })
@ -638,7 +651,8 @@ describe('test unordered list', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('- line3rd ') expect(replacement)
.toEqual('- line3rd ')
done() done()
} }
}) })
@ -655,7 +669,8 @@ describe('test ordered list', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`1. ${textFirstLine}`) expect(replacement)
.toEqual(`1. ${ textFirstLine }`)
done() done()
} }
}) })
@ -678,7 +693,8 @@ describe('test ordered list', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('1. 2nd line3rd line') expect(replacement)
.toEqual('1. 2nd line3rd line')
done() done()
} }
}) })
@ -691,7 +707,8 @@ describe('test ordered list', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('1. line3rd ') expect(replacement)
.toEqual('1. line3rd ')
done() done()
} }
}) })
@ -709,7 +726,8 @@ describe('test todo list', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`- [ ] ${textFirstLine}`) expect(replacement)
.toEqual(`- [ ] ${ textFirstLine }`)
done() done()
} }
}) })
@ -732,7 +750,8 @@ describe('test todo list', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('- [ ] 2nd line3rd line') expect(replacement)
.toEqual('- [ ] 2nd line3rd line')
done() done()
} }
}) })
@ -745,7 +764,8 @@ describe('test todo list', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('- [ ] line3rd ') expect(replacement)
.toEqual('- [ ] line3rd ')
done() done()
} }
}) })
@ -764,7 +784,8 @@ describe('test addLink', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('[](https://)') expect(replacement)
.toEqual('[](https://)')
done() done()
} }
}) })
@ -787,7 +808,8 @@ describe('test addLink', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('[2nd line3rd line](https://)') expect(replacement)
.toEqual('[2nd line3rd line](https://)')
done() done()
} }
}) })
@ -800,7 +822,8 @@ describe('test addLink', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('[line3rd ](https://)') expect(replacement)
.toEqual('[line3rd ](https://)')
done() done()
} }
}) })
@ -819,7 +842,8 @@ describe('test addImage', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('![](https://)') expect(replacement)
.toEqual('![](https://)')
done() done()
} }
}) })
@ -842,7 +866,8 @@ describe('test addImage', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('![2nd line3rd line](https://)') expect(replacement)
.toEqual('![2nd line3rd line](https://)')
done() done()
} }
}) })
@ -855,7 +880,8 @@ describe('test addImage', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('![line3rd ](https://)') expect(replacement)
.toEqual('![line3rd ](https://)')
done() done()
} }
}) })
@ -874,7 +900,8 @@ describe('test addLine', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n----`) expect(replacement)
.toEqual(`${ textFirstLine }\n----`)
done() done()
} }
}) })
@ -897,7 +924,8 @@ describe('test addLine', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line', getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n----') expect(replacement)
.toEqual('2nd line\n----')
done() done()
} }
}) })
@ -910,7 +938,8 @@ describe('test addLine', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line', getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n----') expect(replacement)
.toEqual('2nd line\n----')
done() done()
} }
}) })
@ -929,7 +958,8 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n:::spoiler Toggle label\n Toggled content\n:::`) expect(replacement)
.toEqual(`${ textFirstLine }\n:::spoiler Toggle label\n Toggled content\n:::`)
done() done()
} }
}) })
@ -952,7 +982,8 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line', getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::') expect(replacement)
.toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::')
done() done()
} }
}) })
@ -965,7 +996,8 @@ describe('test collapsable block', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line', getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::') expect(replacement)
.toEqual('2nd line\n:::spoiler Toggle label\n Toggled content\n:::')
done() done()
} }
}) })
@ -984,7 +1016,8 @@ describe('test addComment', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n> []`) expect(replacement)
.toEqual(`${ textFirstLine }\n> []`)
done() done()
} }
}) })
@ -1007,7 +1040,8 @@ describe('test addComment', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line', getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n> []') expect(replacement)
.toEqual('2nd line\n> []')
done() done()
} }
}) })
@ -1020,7 +1054,8 @@ describe('test addComment', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line', getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual('2nd line\n> []') expect(replacement)
.toEqual('2nd line\n> []')
done() done()
} }
}) })
@ -1039,7 +1074,8 @@ describe('test addTable', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`${textFirstLine}\n${table}`) expect(replacement)
.toEqual(`${ textFirstLine }\n${ table }`)
done() done()
} }
}) })
@ -1062,7 +1098,8 @@ describe('test addTable', () => {
listSelections: mockListSelections(multiline, false), listSelections: mockListSelections(multiline, false),
getLine: (): string => '2nd line', getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`2nd line\n${table}`) expect(replacement)
.toEqual(`2nd line\n${ table }`)
done() done()
} }
}) })
@ -1075,7 +1112,8 @@ describe('test addTable', () => {
listSelections: mockListSelections(multilineOffset, false), listSelections: mockListSelections(multilineOffset, false),
getLine: (): string => '2nd line', getLine: (): string => '2nd line',
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(`2nd line\n${table}`) expect(replacement)
.toEqual(`2nd line\n${ table }`)
done() done()
} }
}) })
@ -1112,7 +1150,8 @@ describe('test addEmoji with native emoji', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(':1234:') expect(replacement)
.toEqual(':1234:')
done() done()
} }
}) })
@ -1173,7 +1212,8 @@ describe('test addEmoji with native emoji', () => {
listSelections: mockListSelections(cursor, true), listSelections: mockListSelections(cursor, true),
getLine: (): string => (textFirstLine), getLine: (): string => (textFirstLine),
replaceRange: (replacement: string | string[]) => { replaceRange: (replacement: string | string[]) => {
expect(replacement).toEqual(forkAwesomeIcon) expect(replacement)
.toEqual(forkAwesomeIcon)
done() done()
} }
}) })

View file

@ -32,10 +32,14 @@ export const addCollapsableBlock = (editor: Editor): void => changeLines(editor,
export const addComment = (editor: Editor): void => changeLines(editor, line => `${ line }\n> []`) export const addComment = (editor: Editor): void => changeLines(editor, line => `${ line }\n> []`)
export const addTable = (editor: Editor, rows: number, columns: number): void => { export const addTable = (editor: Editor, rows: number, columns: number): void => {
const rowArray = createNumberRangeArray(rows) const rowArray = createNumberRangeArray(rows)
const colArray = createNumberRangeArray(columns).map(col => col + 1) const colArray = createNumberRangeArray(columns)
.map(col => col + 1)
const head = '| # ' + colArray.join(' | # ') + ' |' const head = '| # ' + colArray.join(' | # ') + ' |'
const divider = '| ' + colArray.map(() => '----').join(' | ') + ' |' const divider = '| ' + colArray.map(() => '----')
const body = rowArray.map(() => '| ' + colArray.map(() => 'Text').join(' | ') + ' |').join('\n') .join(' | ') + ' |'
const body = rowArray.map(() => '| ' + colArray.map(() => 'Text')
.join(' | ') + ' |')
.join('\n')
const table = `${ head }\n${ divider }\n${ body }` const table = `${ head }\n${ divider }\n${ body }`
changeLines(editor, line => `${ line }\n${ table }`) changeLines(editor, line => `${ line }\n${ table }`)
} }
@ -89,7 +93,8 @@ export const insertOnStartOfLines = (editor: Editor, symbol: string): void => {
const to = range.empty() ? { line: cursor.line, ch: editor.getLine(cursor.line).length } : range.to() const to = range.empty() ? { line: cursor.line, ch: editor.getLine(cursor.line).length } : range.to()
const selection = editor.getRange(from, to) const selection = editor.getRange(from, to)
const lines = selection.split('\n') const lines = selection.split('\n')
editor.replaceRange(lines.map(line => `${symbol}${line}`).join('\n'), from, to, '+input') editor.replaceRange(lines.map(line => `${ symbol }${ line }`)
.join('\n'), from, to, '+input')
} }
editor.setSelections(ranges) editor.setSelections(ranges)
} }
@ -117,7 +122,8 @@ export const createList = (editor: Editor, listMark: (i: number) => string): voi
const selection = editor.getRange(from, to) const selection = editor.getRange(from, to)
const lines = selection.split('\n') const lines = selection.split('\n')
editor.replaceRange(lines.map((line, i) => `${listMark(i + 1)}${line}`).join('\n'), from, to, '+input') editor.replaceRange(lines.map((line, i) => `${ listMark(i + 1) }${ line }`)
.join('\n'), from, to, '+input')
} }
editor.setSelections(ranges) editor.setSelections(ranges)
} }

View file

@ -29,10 +29,16 @@ describe('yaml frontmatter tests', () => {
const testFrontmatter = (input: string, expectedRaw: Partial<RawNoteFrontmatter>, expectedFinished: Partial<NoteFrontmatter>) => { const testFrontmatter = (input: string, expectedRaw: Partial<RawNoteFrontmatter>, expectedFinished: Partial<NoteFrontmatter>) => {
md.render(input) md.render(input)
expect(raw).not.toBe(undefined) expect(raw)
expect(raw).toEqual(expectedRaw) .not
expect(finished).not.toBe(undefined) .toBe(undefined)
expect(finished).toEqual({ expect(raw)
.toEqual(expectedRaw)
expect(finished)
.not
.toBe(undefined)
expect(finished)
.toEqual({
...defaultYAML, ...defaultYAML,
...expectedFinished ...expectedFinished
}) })

View file

@ -257,7 +257,8 @@ export class NoteFrontmatter {
theme: 'white' theme: 'white'
} */ } */
if (typeof rawData?.tags === 'string') { if (typeof rawData?.tags === 'string') {
this.tags = rawData?.tags?.split(',').map(entry => entry.trim()) ?? [] this.tags = rawData?.tags?.split(',')
.map(entry => entry.trim()) ?? []
this.deprecatedTagsSyntax = true this.deprecatedTagsSyntax = true
} else if (typeof rawData?.tags === 'object') { } else if (typeof rawData?.tags === 'object') {
this.tags = rawData?.tags?.filter(tag => tag !== null) ?? [] this.tags = rawData?.tags?.filter(tag => tag !== null) ?? []

View file

@ -24,7 +24,7 @@ export const useOnIframeLoad = (frameReference: RefObject<HTMLIFrameElement>, if
return return
} else { } else {
onNavigateAway() onNavigateAway()
console.error("Navigated away from unknown URL") console.error('Navigated away from unknown URL')
frame.src = renderPageUrl frame.src = renderPageUrl
sendToRenderPage.current = true sendToRenderPage.current = true
} }

View file

@ -39,13 +39,18 @@ export const RenderIframe: React.FC<MarkdownDocumentProps> = (
const onIframeLoad = useOnIframeLoad(frameReference, iframeCommunicator, rendererOrigin, renderPageUrl, resetRendererReady) const onIframeLoad = useOnIframeLoad(frameReference, iframeCommunicator, rendererOrigin, renderPageUrl, resetRendererReady)
useEffect(() => () => iframeCommunicator.unregisterEventListener(), [iframeCommunicator]) useEffect(() => () => iframeCommunicator.unregisterEventListener(), [iframeCommunicator])
useEffect(() => iframeCommunicator.onFirstHeadingChange(onFirstHeadingChange), [iframeCommunicator, onFirstHeadingChange]) useEffect(() => iframeCommunicator.onFirstHeadingChange(onFirstHeadingChange), [iframeCommunicator,
useEffect(() => iframeCommunicator.onFrontmatterChange(onFrontmatterChange), [iframeCommunicator, onFrontmatterChange]) onFirstHeadingChange])
useEffect(() => iframeCommunicator.onFrontmatterChange(onFrontmatterChange), [iframeCommunicator,
onFrontmatterChange])
useEffect(() => iframeCommunicator.onSetScrollState(onScroll), [iframeCommunicator, onScroll]) useEffect(() => iframeCommunicator.onSetScrollState(onScroll), [iframeCommunicator, onScroll])
useEffect(() => iframeCommunicator.onSetScrollSourceToRenderer(onMakeScrollSource), [iframeCommunicator, onMakeScrollSource]) useEffect(() => iframeCommunicator.onSetScrollSourceToRenderer(onMakeScrollSource), [iframeCommunicator,
useEffect(() => iframeCommunicator.onTaskCheckboxChange(onTaskCheckedChange), [iframeCommunicator, onTaskCheckedChange]) onMakeScrollSource])
useEffect(() => iframeCommunicator.onTaskCheckboxChange(onTaskCheckedChange), [iframeCommunicator,
onTaskCheckedChange])
useEffect(() => iframeCommunicator.onImageClicked(setLightboxDetails), [iframeCommunicator]) useEffect(() => iframeCommunicator.onImageClicked(setLightboxDetails), [iframeCommunicator])
useEffect(() => iframeCommunicator.onRendererReady(() => setRendererReady(true)), [darkMode, iframeCommunicator, scrollState]) useEffect(() => iframeCommunicator.onRendererReady(() => setRendererReady(true)), [darkMode, iframeCommunicator,
scrollState])
useEffect(() => { useEffect(() => {
if (rendererReady) { if (rendererReady) {
iframeCommunicator.sendSetDarkmode(darkMode) iframeCommunicator.sendSetDarkmode(darkMode)

View file

@ -16,7 +16,7 @@ export const DeleteNoteSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({ hi
return ( return (
<Fragment> <Fragment>
<SidebarButton icon={"trash"} className={className} hide={hide} onClick={() => setShowDialog(true)}> <SidebarButton icon={ 'trash' } className={ className } hide={ hide } onClick={ () => setShowDialog(true) }>
<Trans i18nKey={ 'landing.history.menu.deleteNote' }/> <Trans i18nKey={ 'landing.history.menu.deleteNote' }/>
</SidebarButton> </SidebarButton>
<DeletionModal <DeletionModal

View file

@ -16,7 +16,7 @@ export const DocumentInfoSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({c
return ( return (
<Fragment> <Fragment>
<SidebarButton hide={hide} className={className} icon={"line-chart"} onClick={() => setShowModal(true)}> <SidebarButton hide={ hide } className={ className } icon={ 'line-chart' } onClick={ () => setShowModal(true) }>
<Trans i18nKey={ 'editor.modal.documentInfo.title' }/> <Trans i18nKey={ 'editor.modal.documentInfo.title' }/>
</SidebarButton> </SidebarButton>
<DocumentInfoModal show={ showModal } onHide={ () => setShowModal(false) }/> <DocumentInfoModal show={ showModal } onHide={ () => setShowModal(false) }/>

View file

@ -19,7 +19,7 @@ export const ExportMarkdownSidebarEntry: React.FC = () => {
}, [markdownContent]) }, [markdownContent])
return ( return (
<SidebarButton data-cy={"menu-export-markdown"} onClick={onClick} icon={'file-text'}> <SidebarButton data-cy={ 'menu-export-markdown' } onClick={ onClick } icon={ 'file-text' }>
<Trans i18nKey={ 'editor.export.markdown-file' }/> <Trans i18nKey={ 'editor.export.markdown-file' }/>
</SidebarButton> </SidebarButton>
) )

View file

@ -29,28 +29,29 @@ export const ExportMenuSidebarMenu: React.FC<SpecificSidebarMenuProps> = (
return ( return (
<Fragment> <Fragment>
<SidebarButton data-cy={"menu-export"} hide={hide} icon={expand ? "arrow-left" : "cloud-download"} <SidebarButton data-cy={ 'menu-export' } hide={ hide } icon={ expand ? 'arrow-left' : 'cloud-download' }
className={ className } onClick={ onClickHandler }> className={ className } onClick={ onClickHandler }>
<Trans i18nKey={ 'editor.documentBar.export' }/> <Trans i18nKey={ 'editor.documentBar.export' }/>
</SidebarButton> </SidebarButton>
<SidebarMenu expand={ expand }> <SidebarMenu expand={ expand }>
<SidebarButton icon={"github"}> <SidebarButton icon={ 'github' }>
Gist Gist
</SidebarButton> </SidebarButton>
<SidebarButton icon={"gitlab"}> <SidebarButton icon={ 'gitlab' }>
Gitlab Snippet Gitlab Snippet
</SidebarButton> </SidebarButton>
<ExportMarkdownSidebarEntry/> <ExportMarkdownSidebarEntry/>
<SidebarButton icon={"file-code-o"}> <SidebarButton icon={ 'file-code-o' }>
HTML HTML
</SidebarButton> </SidebarButton>
<SidebarButton icon={"file-code-o"}> <SidebarButton icon={ 'file-code-o' }>
<Trans i18nKey='editor.export.rawHtml'/> <Trans i18nKey='editor.export.rawHtml'/>
</SidebarButton> </SidebarButton>
<SidebarButton icon={"file-pdf-o"}> <SidebarButton icon={ 'file-pdf-o' }>
<a className='small text-muted' dir={'auto'} href={links.faq} target={'_blank'} rel='noopener noreferrer'> <a className='small text-muted' dir={ 'auto' } href={ links.faq } target={ '_blank' }
rel='noopener noreferrer'>
<Trans i18nKey={ 'editor.export.pdf' }/> <Trans i18nKey={ 'editor.export.pdf' }/>
&nbsp; &nbsp;
<span className={ 'text-primary' }> <span className={ 'text-primary' }>

View file

@ -39,10 +39,10 @@ export const ImportMarkdownSidebarEntry: React.FC = () => {
return ( return (
<Fragment> <Fragment>
<SidebarButton data-cy={"menu-import-markdown"} icon={"file-text-o"} onClick={buttonClick}> <SidebarButton data-cy={ 'menu-import-markdown' } icon={ 'file-text-o' } onClick={ buttonClick }>
<Trans i18nKey={ 'editor.import.file' }/> <Trans i18nKey={ 'editor.import.file' }/>
</SidebarButton> </SidebarButton>
<UploadInput onLoad={onImportMarkdown} data-cy={"menu-import-markdown-input"} <UploadInput onLoad={ onImportMarkdown } data-cy={ 'menu-import-markdown-input' }
acceptedFiles={ '.md, text/markdown, text/plain' } onClickRef={ clickRef }/> acceptedFiles={ '.md, text/markdown, text/plain' } onClickRef={ clickRef }/>
</Fragment> </Fragment>
) )

View file

@ -29,18 +29,18 @@ export const ImportMenuSidebarMenu: React.FC<SpecificSidebarMenuProps> = (
return ( return (
<Fragment> <Fragment>
<SidebarButton data-cy={"menu-import"} hide={hide} icon={expand ? "arrow-left" : "cloud-upload"} <SidebarButton data-cy={ 'menu-import' } hide={ hide } icon={ expand ? 'arrow-left' : 'cloud-upload' }
className={ className } onClick={ onClickHandler }> className={ className } onClick={ onClickHandler }>
<Trans i18nKey={ 'editor.documentBar.import' }/> <Trans i18nKey={ 'editor.documentBar.import' }/>
</SidebarButton> </SidebarButton>
<SidebarMenu expand={ expand }> <SidebarMenu expand={ expand }>
<SidebarButton icon={"github"}> <SidebarButton icon={ 'github' }>
Gist Gist
</SidebarButton> </SidebarButton>
<SidebarButton icon={"gitlab"}> <SidebarButton icon={ 'gitlab' }>
Gitlab Snippet Gitlab Snippet
</SidebarButton> </SidebarButton>
<SidebarButton icon={"clipboard"}> <SidebarButton icon={ 'clipboard' }>
<Trans i18nKey={ 'editor.import.clipboard' }/> <Trans i18nKey={ 'editor.import.clipboard' }/>
</SidebarButton> </SidebarButton>
<ImportMarkdownSidebarEntry/> <ImportMarkdownSidebarEntry/>

View file

@ -16,7 +16,7 @@ export const PermissionsSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({cl
return ( return (
<Fragment> <Fragment>
<SidebarButton hide={hide} className={className} icon={"lock"} onClick={() => setShowModal(true)}> <SidebarButton hide={ hide } className={ className } icon={ 'lock' } onClick={ () => setShowModal(true) }>
<Trans i18nKey={ 'editor.modal.permissions.title' }/> <Trans i18nKey={ 'editor.modal.permissions.title' }/>
</SidebarButton> </SidebarButton>
<PermissionModal show={ showModal } onHide={ () => setShowModal(false) }/> <PermissionModal show={ showModal } onHide={ () => setShowModal(false) }/>

View file

@ -15,7 +15,7 @@ export const RevisionSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({class
return ( return (
<Fragment> <Fragment>
<SidebarButton hide={hide} className={className} icon={"history"} onClick={() => setShowModal(true)}> <SidebarButton hide={ hide } className={ className } icon={ 'history' } onClick={ () => setShowModal(true) }>
<Trans i18nKey={ 'editor.modal.revision.title' }/> <Trans i18nKey={ 'editor.modal.revision.title' }/>
</SidebarButton> </SidebarButton>
<RevisionModal show={ showModal } onHide={ () => setShowModal(false) }/> <RevisionModal show={ showModal } onHide={ () => setShowModal(false) }/>

View file

@ -16,7 +16,7 @@ export const ShareSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({classNam
return ( return (
<Fragment> <Fragment>
<SidebarButton hide={hide} className={className} icon={"share"} onClick={() => setShowModal(true)}> <SidebarButton hide={ hide } className={ className } icon={ 'share' } onClick={ () => setShowModal(true) }>
<Trans i18nKey={ 'editor.modal.shareLink.title' }/> <Trans i18nKey={ 'editor.modal.shareLink.title' }/>
</SidebarButton> </SidebarButton>
<ShareModal show={ showModal } onHide={ () => setShowModal(false) }/> <ShareModal show={ showModal } onHide={ () => setShowModal(false) }/>

View file

@ -10,7 +10,7 @@ import { IconName } from '../../common/fork-awesome/types'
import { ShowIf } from '../../common/show-if/show-if' import { ShowIf } from '../../common/show-if/show-if'
import { SidebarEntryProps } from './types' import { SidebarEntryProps } from './types'
export type SidebarEntryVariant = "primary" export type SidebarEntryVariant = 'primary'
export const SidebarButton: React.FC<SidebarEntryProps> = ({ children, icon, className, variant, buttonRef, hide, ...props }) => { export const SidebarButton: React.FC<SidebarEntryProps> = ({ children, icon, className, variant, buttonRef, hide, ...props }) => {
return ( return (

View file

@ -14,5 +14,5 @@ export const SidebarMenu: React.FC<SidebarMenuProps> = ({children, expand}) => {
{ children } { children }
</div> </div>
</div> </div>
); )
} }

View file

@ -14,7 +14,7 @@ import { PermissionsSidebarEntry } from './permissions-sidebar-entry'
import { PinNoteSidebarEntry } from './pin-note-sidebar-entry' import { PinNoteSidebarEntry } from './pin-note-sidebar-entry'
import { RevisionSidebarEntry } from './revision-sidebar-entry' import { RevisionSidebarEntry } from './revision-sidebar-entry'
import { ShareSidebarEntry } from './share-sidebar-entry' import { ShareSidebarEntry } from './share-sidebar-entry'
import "./style/theme.scss" import './style/theme.scss'
import { DocumentSidebarMenuSelection } from './types' import { DocumentSidebarMenuSelection } from './types'
import { UsersOnlineSidebarMenu } from './users-online-sidebar-menu/users-online-sidebar-menu' import { UsersOnlineSidebarMenu } from './users-online-sidebar-menu/users-online-sidebar-menu'

View file

@ -21,7 +21,7 @@ export interface SidebarEntryProps {
hide?: boolean hide?: boolean
className?: string className?: string
onClick?: () => void onClick?: () => void
"data-cy"?: string 'data-cy'?: string
} }
export interface SidebarMenuProps { export interface SidebarMenuProps {

View file

@ -10,7 +10,7 @@ export interface UploadInputProps {
onLoad: (file: File) => Promise<void> onLoad: (file: File) => Promise<void>
acceptedFiles: string acceptedFiles: string
onClickRef: MutableRefObject<(() => void) | undefined> onClickRef: MutableRefObject<(() => void) | undefined>
"data-cy"?: string 'data-cy'?: string
} }
export const UploadInput: React.FC<UploadInputProps> = ({ onLoad, acceptedFiles, onClickRef, ...props }) => { export const UploadInput: React.FC<UploadInputProps> = ({ onLoad, acceptedFiles, onClickRef, ...props }) => {
@ -25,9 +25,11 @@ export const UploadInput: React.FC<UploadInputProps> = ({ onLoad, acceptedFiles,
return return
} }
const file = fileInput.files[0] const file = fileInput.files[0]
onLoad(file).then(() => { onLoad(file)
.then(() => {
fileInput.value = '' fileInput.value = ''
}).catch((error) => { })
.catch((error) => {
console.error(error) console.error(error)
}) })
}) })
@ -39,6 +41,7 @@ export const UploadInput: React.FC<UploadInputProps> = ({ onLoad, acceptedFiles,
}) })
return ( return (
<input data-cy={props["data-cy"]} type='file' ref={fileInputReference} className='d-none' accept={acceptedFiles}/> <input data-cy={ props['data-cy'] } type='file' ref={ fileInputReference } className='d-none'
accept={ acceptedFiles }/>
) )
} }

View file

@ -20,8 +20,9 @@ export const UserLine: React.FC<UserLineProps> = ({ name, photo, color, status }
return ( return (
<div className={ 'd-flex align-items-center h-100 w-100' }> <div className={ 'd-flex align-items-center h-100 w-100' }>
<div className='d-inline-flex align-items-bottom user-line-color-indicator' style={ { borderLeftColor: color } }/> <div className='d-inline-flex align-items-bottom user-line-color-indicator' style={ { borderLeftColor: color } }/>
<UserAvatar photo={photo} name={name} additionalClasses={'flex-fill overflow-hidden px-2 text-nowrap w-100'}/> <UserAvatar photo={ photo } name={ name }
<div className={"active-indicator-container"}> additionalClasses={ 'flex-fill overflow-hidden px-2 text-nowrap w-100' }/>
<div className={ 'active-indicator-container' }>
<ActiveIndicator status={ status }/> <ActiveIndicator status={ status }/>
</div> </div>
</div> </div>

View file

@ -36,16 +36,19 @@ export const UsersOnlineSidebarMenu: React.FC<SpecificSidebarMenuProps> = ({
return ( return (
<Fragment> <Fragment>
<SidebarButton hide={hide} buttonRef={buttonRef} onClick={onClickHandler} icon={expand ? "arrow-left" : "users"} <SidebarButton hide={ hide } buttonRef={ buttonRef } onClick={ onClickHandler }
icon={ expand ? 'arrow-left' : 'users' }
variant={ 'primary' } className={ `online-entry ${ className ?? '' }` }> variant={ 'primary' } className={ `online-entry ${ className ?? '' }` }>
<Trans i18nKey={ 'editor.onlineStatus.online' }/> <Trans i18nKey={ 'editor.onlineStatus.online' }/>
</SidebarButton> </SidebarButton>
<SidebarMenu expand={ expand }> <SidebarMenu expand={ expand }>
<SidebarButton> <SidebarButton>
<UserLine name="Philip Molares" photo="/img/avatar.png" color="red" status={ActiveIndicatorStatus.INACTIVE}/> <UserLine name="Philip Molares" photo="/img/avatar.png" color="red"
status={ ActiveIndicatorStatus.INACTIVE }/>
</SidebarButton> </SidebarButton>
<SidebarButton> <SidebarButton>
<UserLine name="Tilman Vatteroth" photo="/img/avatar.png" color="blue" status={ActiveIndicatorStatus.ACTIVE}/> <UserLine name="Tilman Vatteroth" photo="/img/avatar.png" color="blue"
status={ ActiveIndicatorStatus.ACTIVE }/>
</SidebarButton> </SidebarButton>
</SidebarMenu> </SidebarMenu>
</Fragment> </Fragment>

View file

@ -56,7 +56,8 @@ export const Splitter: React.FC<SplitterProps> = ({ containerClassName, left, ri
return ( return (
<div ref={ splitContainer } className={ `flex-fill flex-row d-flex ${ containerClassName || '' }` } <div ref={ splitContainer } className={ `flex-fill flex-row d-flex ${ containerClassName || '' }` }
onMouseUp={ stopResizing } onTouchEnd={ stopResizing } onMouseMove={ onMouseMove } onTouchMove={ onTouchMove }> onMouseUp={ stopResizing } onTouchEnd={ stopResizing } onMouseMove={ onMouseMove } onTouchMove={ onTouchMove }>
<div className={`splitter left ${!showLeft ? 'd-none' : ''}`} style={{ flexBasis: `calc(${realSplit}% - 5px)` }}> <div className={ `splitter left ${ !showLeft ? 'd-none' : '' }` }
style={ { flexBasis: `calc(${ realSplit }% - 5px)` } }>
{ left } { left }
</div> </div>
<ShowIf condition={ showLeft && showRight }> <ShowIf condition={ showLeft && showRight }>

View file

@ -19,7 +19,9 @@ export interface TableOfContentsProps {
} }
export const slugify = (content: string): string => { export const slugify = (content: string): string => {
return encodeURIComponent(content.trim().toLowerCase().replace(/\s+/g, '-')) return encodeURIComponent(content.trim()
.toLowerCase()
.replace(/\s+/g, '-'))
} }
const convertLevel = (toc: TocAst, levelsToShowUnderThis: number, headerCounts: Map<string, number>, const convertLevel = (toc: TocAst, levelsToShowUnderThis: number, headerCounts: Map<string, number>,
@ -38,7 +40,8 @@ const convertLevel = (toc: TocAst, levelsToShowUnderThis: number, headerCounts:
const content = ( const content = (
<Fragment> <Fragment>
<ShowIf condition={ toc.l > 0 }> <ShowIf condition={ toc.l > 0 }>
<a href={headlineUrl} title={rawName} onClick={createJumpToMarkClickEventHandler(slug.substr(1))}>{rawName}</a> <a href={ headlineUrl } title={ rawName }
onClick={ createJumpToMarkClickEventHandler(slug.substr(1)) }>{ rawName }</a>
</ShowIf> </ShowIf>
<ShowIf condition={ toc.c.length > 0 }> <ShowIf condition={ toc.c.length > 0 }>
<ul> <ul>
@ -69,7 +72,8 @@ export const TableOfContents: React.FC<TableOfContentsProps> = ({
baseUrl baseUrl
}) => { }) => {
useTranslation() useTranslation()
const tocTree = useMemo(() => convertLevel(ast, maxDepth, new Map<string, number>(), false, baseUrl), [ast, maxDepth, baseUrl]) const tocTree = useMemo(() => convertLevel(ast, maxDepth, new Map<string, number>(), false, baseUrl), [ast, maxDepth,
baseUrl])
return ( return (
<div className={ `markdown-toc ${ className ?? '' }` }> <div className={ `markdown-toc ${ className ?? '' }` }>

View file

@ -4,4 +4,5 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
export const isMac = navigator.platform.toLowerCase().includes('mac') export const isMac = navigator.platform.toLowerCase()
.includes('mac')

View file

@ -41,9 +41,11 @@ export class ErrorBoundary extends Component {
<Container className="text-light d-flex flex-column mvh-100"> <Container className="text-light d-flex flex-column mvh-100">
<div className='text-light d-flex flex-column align-items-center justify-content-center my-5'> <div className='text-light d-flex flex-column align-items-center justify-content-center my-5'>
<h1>An unknown error occurred</h1> <h1>An unknown error occurred</h1>
<p>Don't worry, this happens sometimes. If this is the first time you see this page then try reloading the app.</p> <p>Don't worry, this happens sometimes. If this is the first time you see this page then try reloading the
app.</p>
If you can reproduce this error, then we would be glad if you&#32; If you can reproduce this error, then we would be glad if you&#32;
<ExternalLink text={'open an issue on github'} href={frontendVersion.issueTrackerUrl} className={'text-primary'}/>&#32; <ExternalLink text={ 'open an issue on github' } href={ frontendVersion.issueTrackerUrl }
className={ 'text-primary' }/>&#32;
or <ExternalLink text={ 'contact us on matrix.' } href={ links.chat } className={ 'text-primary' }/> or <ExternalLink text={ 'contact us on matrix.' } href={ links.chat } className={ 'text-primary' }/>
<Button onClick={ () => this.refreshPage() } title={ 'Reload App' } className={ 'mt-4' }> <Button onClick={ () => this.refreshPage() } title={ 'Reload App' } className={ 'mt-4' }>
<ForkAwesomeIcon icon={ 'refresh' }/>&nbsp;Reload App <ForkAwesomeIcon icon={ 'refresh' }/>&nbsp;Reload App

View file

@ -29,7 +29,8 @@ export const EntryMenu: React.FC<EntryMenuProps> = ({ id, title, location, isDar
return ( return (
<Dropdown className={ `d-inline-flex ${ className || '' }` }> <Dropdown className={ `d-inline-flex ${ className || '' }` }>
<Dropdown.Toggle variant={isDark ? 'secondary' : 'light'} id={`dropdown-card-${id}`} className='no-arrow history-menu d-inline-flex align-items-center'> <Dropdown.Toggle variant={ isDark ? 'secondary' : 'light' } id={ `dropdown-card-${ id }` }
className='no-arrow history-menu d-inline-flex align-items-center'>
<ForkAwesomeIcon icon="ellipsis-v" fixedWidth={ true }/> <ForkAwesomeIcon icon="ellipsis-v" fixedWidth={ true }/>
</Dropdown.Toggle> </Dropdown.Toggle>

View file

@ -21,19 +21,22 @@ export const HistoryCard: React.FC<HistoryEntryProps> = ({ entry, onPinClick, on
<Card className="card-min-height" text={ 'dark' } bg={ 'light' }> <Card className="card-min-height" text={ 'dark' } bg={ 'light' }>
<Card.Body className="p-2 d-flex flex-row justify-content-between"> <Card.Body className="p-2 d-flex flex-row justify-content-between">
<div className={ 'd-flex flex-column' }> <div className={ 'd-flex flex-column' }>
<PinButton isDark={false} isPinned={entry.pinned} onPinClick={() => onPinClick(entry.id, entry.location)}/> <PinButton isDark={ false } isPinned={ entry.pinned }
onPinClick={ () => onPinClick(entry.id, entry.location) }/>
</div> </div>
<Link to={ `/n/${ entry.id }` } className="text-decoration-none flex-fill text-dark"> <Link to={ `/n/${ entry.id }` } className="text-decoration-none flex-fill text-dark">
<div className={ 'd-flex flex-column justify-content-between' }> <div className={ 'd-flex flex-column justify-content-between' }>
<Card.Title className="m-0 mt-1dot5">{ entry.title }</Card.Title> <Card.Title className="m-0 mt-1dot5">{ entry.title }</Card.Title>
<div> <div>
<div className="text-black-50 mt-2"> <div className="text-black-50 mt-2">
<ForkAwesomeIcon icon="clock-o"/> {DateTime.fromISO(entry.lastVisited).toRelative()}<br/> <ForkAwesomeIcon icon="clock-o"/> { DateTime.fromISO(entry.lastVisited)
.toRelative() }<br/>
{ formatHistoryDate(entry.lastVisited) } { formatHistoryDate(entry.lastVisited) }
</div> </div>
<div className={ 'card-footer-min-height p-0' }> <div className={ 'card-footer-min-height p-0' }>
{ {
entry.tags.map((tag) => <Badge variant={'dark'} className={'mr-1 mb-1'} key={tag}>{tag}</Badge>) entry.tags.map((tag) => <Badge variant={ 'dark' } className={ 'mr-1 mb-1' }
key={ tag }>{ tag }</Badge>)
} }
</div> </div>
</div> </div>

View file

@ -28,7 +28,8 @@ export const HistoryTableRow: React.FC<HistoryEntryProps> = ({ entry, onPinClick
} }
</td> </td>
<td> <td>
<PinButton isDark={true} isPinned={entry.pinned} onPinClick={() => onPinClick(entry.id, entry.location)} className={'mb-1 mr-1'}/> <PinButton isDark={ true } isPinned={ entry.pinned } onPinClick={ () => onPinClick(entry.id, entry.location) }
className={ 'mb-1 mr-1' }/>
<EntryMenu <EntryMenu
id={ entry.id } id={ entry.id }
title={ entry.title } title={ entry.title }

View file

@ -92,7 +92,8 @@ export const HistoryToolbar: React.FC<HistoryToolbarProps> = ({ onSettingsChange
return ( return (
<Form inline={ true }> <Form inline={ true }>
<InputGroup className={ 'mr-1 mb-1' }> <InputGroup className={ 'mr-1 mb-1' }>
<Typeahead id={'tagsSelection'} options={tags} multiple={true} placeholder={t('landing.history.toolbar.selectTags')} <Typeahead id={ 'tagsSelection' } options={ tags } multiple={ true }
placeholder={ t('landing.history.toolbar.selectTags') }
onChange={ selectedTagsChanged }/> onChange={ selectedTagsChanged }/>
</InputGroup> </InputGroup>
<InputGroup className={ 'mr-1 mb-1' }> <InputGroup className={ 'mr-1 mb-1' }>
@ -103,7 +104,8 @@ export const HistoryToolbar: React.FC<HistoryToolbarProps> = ({ onSettingsChange
/> />
</InputGroup> </InputGroup>
<InputGroup className={ 'mr-1 mb-1' }> <InputGroup className={ 'mr-1 mb-1' }>
<SortButton onDirectionChange={titleSortChanged} direction={state.titleSortDirection} variant={'light'}><Trans <SortButton onDirectionChange={ titleSortChanged } direction={ state.titleSortDirection }
variant={ 'light' }><Trans
i18nKey={ 'landing.history.toolbar.sortByTitle' }/></SortButton> i18nKey={ 'landing.history.toolbar.sortByTitle' }/></SortButton>
</InputGroup> </InputGroup>
<InputGroup className={ 'mr-1 mb-1' }> <InputGroup className={ 'mr-1 mb-1' }>
@ -136,10 +138,12 @@ export const HistoryToolbar: React.FC<HistoryToolbarProps> = ({ onSettingsChange
onChange={ (newViewState: ViewStateEnum) => { onChange={ (newViewState: ViewStateEnum) => {
toggleViewChanged(newViewState) toggleViewChanged(newViewState)
} }> } }>
<ToggleButton className={'btn-light'} value={ViewStateEnum.CARD} title={t('landing.history.toolbar.cards')}> <ToggleButton className={ 'btn-light' } value={ ViewStateEnum.CARD }
title={ t('landing.history.toolbar.cards') }>
<ForkAwesomeIcon icon={ 'sticky-note' } className={ 'fa-fix-line-height' }/> <ForkAwesomeIcon icon={ 'sticky-note' } className={ 'fa-fix-line-height' }/>
</ToggleButton> </ToggleButton>
<ToggleButton className={'btn-light'} value={ViewStateEnum.TABLE} title={t('landing.history.toolbar.table')}> <ToggleButton className={ 'btn-light' } value={ ViewStateEnum.TABLE }
title={ t('landing.history.toolbar.table') }>
<ForkAwesomeIcon icon={ 'table' } className={ 'fa-fix-line-height' }/> <ForkAwesomeIcon icon={ 'table' } className={ 'fa-fix-line-height' }/>
</ToggleButton> </ToggleButton>
</ToggleButtonGroup> </ToggleButtonGroup>

View file

@ -50,5 +50,6 @@ export const SortButton: React.FC<SortButtonProps> = ({ children, variant, onDir
onDirectionChange(toggleDirection(direction)) onDirectionChange(toggleDirection(direction))
} }
return <IconButton onClick={toggleSort} variant={variant} icon={getIcon(direction)} border={true}>{children}</IconButton> return <IconButton onClick={ toggleSort } variant={ variant } icon={ getIcon(direction) }
border={ true }>{ children }</IconButton>
} }

Some files were not shown because too many files have changed in this diff Show more