Refactoring using eslint & prettier

This commit is contained in:
obergodmar
2020-08-19 14:58:49 +03:00
parent 3868d89571
commit 26e9c3afaa
67 changed files with 2068 additions and 2502 deletions
-634
View File
@@ -1,634 +0,0 @@
[*]
charset = utf-8
end_of_line = crlf
indent_size = 4
indent_style = space
insert_final_newline = true
max_line_length = 120
tab_width = 4
trim_trailing_whitespace = true
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_wrap_on_typing = false
[*.css]
ij_css_align_closing_brace_with_properties = false
ij_css_blank_lines_around_nested_selector = 1
ij_css_blank_lines_between_blocks = 1
ij_css_brace_placement = end_of_line
ij_css_enforce_quotes_on_format = false
ij_css_hex_color_long_format = false
ij_css_hex_color_lower_case = false
ij_css_hex_color_short_format = false
ij_css_hex_color_upper_case = false
ij_css_keep_blank_lines_in_code = 2
ij_css_keep_indents_on_empty_lines = false
ij_css_keep_single_line_blocks = false
ij_css_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_use_double_quotes = true
ij_css_value_alignment = do_not_align
[*.feature]
indent_size = 2
ij_gherkin_keep_indents_on_empty_lines = false
[*.haml]
indent_size = 2
ij_haml_keep_indents_on_empty_lines = false
[*.less]
indent_size = 2
ij_less_align_closing_brace_with_properties = false
ij_less_blank_lines_around_nested_selector = 1
ij_less_blank_lines_between_blocks = 1
ij_less_brace_placement = 0
ij_less_enforce_quotes_on_format = false
ij_less_hex_color_long_format = false
ij_less_hex_color_lower_case = false
ij_less_hex_color_short_format = false
ij_less_hex_color_upper_case = false
ij_less_keep_blank_lines_in_code = 2
ij_less_keep_indents_on_empty_lines = false
ij_less_keep_single_line_blocks = false
ij_less_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
ij_less_space_after_colon = true
ij_less_space_before_opening_brace = true
ij_less_use_double_quotes = true
ij_less_value_alignment = 0
[*.sass]
indent_size = 2
ij_sass_align_closing_brace_with_properties = false
ij_sass_blank_lines_around_nested_selector = 1
ij_sass_blank_lines_between_blocks = 1
ij_sass_brace_placement = 0
ij_sass_enforce_quotes_on_format = false
ij_sass_hex_color_long_format = false
ij_sass_hex_color_lower_case = false
ij_sass_hex_color_short_format = false
ij_sass_hex_color_upper_case = false
ij_sass_keep_blank_lines_in_code = 2
ij_sass_keep_indents_on_empty_lines = false
ij_sass_keep_single_line_blocks = false
ij_sass_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
ij_sass_space_after_colon = true
ij_sass_space_before_opening_brace = true
ij_sass_use_double_quotes = true
ij_sass_value_alignment = 0
[*.scss]
indent_size = 2
ij_scss_align_closing_brace_with_properties = false
ij_scss_blank_lines_around_nested_selector = 1
ij_scss_blank_lines_between_blocks = 1
ij_scss_brace_placement = 0
ij_scss_enforce_quotes_on_format = false
ij_scss_hex_color_long_format = false
ij_scss_hex_color_lower_case = false
ij_scss_hex_color_short_format = false
ij_scss_hex_color_upper_case = false
ij_scss_keep_blank_lines_in_code = 2
ij_scss_keep_indents_on_empty_lines = false
ij_scss_keep_single_line_blocks = false
ij_scss_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
ij_scss_space_after_colon = true
ij_scss_space_before_opening_brace = true
ij_scss_use_double_quotes = true
ij_scss_value_alignment = 0
[*.styl]
indent_size = 2
ij_stylus_align_closing_brace_with_properties = false
ij_stylus_blank_lines_around_nested_selector = 1
ij_stylus_blank_lines_between_blocks = 1
ij_stylus_brace_placement = 0
ij_stylus_enforce_quotes_on_format = false
ij_stylus_hex_color_long_format = false
ij_stylus_hex_color_lower_case = false
ij_stylus_hex_color_short_format = false
ij_stylus_hex_color_upper_case = false
ij_stylus_keep_blank_lines_in_code = 2
ij_stylus_keep_indents_on_empty_lines = false
ij_stylus_keep_single_line_blocks = false
ij_stylus_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow
ij_stylus_space_after_colon = true
ij_stylus_space_before_opening_brace = true
ij_stylus_use_double_quotes = true
ij_stylus_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
[{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.rng, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul}]
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = true
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = false
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = normal
[{*.ats, *.ts}]
indent_style = tab
ij_continuation_indent_size = 4
ij_smart_tabs = true
ij_typescript_align_imports = false
ij_typescript_align_multiline_array_initializer_expression = false
ij_typescript_align_multiline_binary_operation = false
ij_typescript_align_multiline_chained_methods = false
ij_typescript_align_multiline_extends_list = false
ij_typescript_align_multiline_for = true
ij_typescript_align_multiline_parameters = true
ij_typescript_align_multiline_parameters_in_calls = false
ij_typescript_align_multiline_ternary_operation = false
ij_typescript_align_object_properties = 0
ij_typescript_align_union_types = false
ij_typescript_align_var_statements = 0
ij_typescript_array_initializer_new_line_after_left_brace = false
ij_typescript_array_initializer_right_brace_on_new_line = false
ij_typescript_array_initializer_wrap = off
ij_typescript_assignment_wrap = off
ij_typescript_binary_operation_sign_on_next_line = false
ij_typescript_binary_operation_wrap = off
ij_typescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/**
ij_typescript_blank_lines_after_imports = 1
ij_typescript_blank_lines_around_class = 1
ij_typescript_blank_lines_around_field = 0
ij_typescript_blank_lines_around_field_in_interface = 0
ij_typescript_blank_lines_around_function = 1
ij_typescript_blank_lines_around_method = 1
ij_typescript_blank_lines_around_method_in_interface = 1
ij_typescript_block_brace_style = end_of_line
ij_typescript_call_parameters_new_line_after_left_paren = false
ij_typescript_call_parameters_right_paren_on_new_line = false
ij_typescript_call_parameters_wrap = off
ij_typescript_catch_on_new_line = false
ij_typescript_chained_call_dot_on_new_line = true
ij_typescript_class_brace_style = end_of_line
ij_typescript_comma_on_new_line = false
ij_typescript_do_while_brace_force = never
ij_typescript_else_on_new_line = false
ij_typescript_enforce_trailing_comma = remove
ij_typescript_extends_keyword_wrap = off
ij_typescript_extends_list_wrap = off
ij_typescript_field_prefix = _
ij_typescript_file_name_style = relaxed
ij_typescript_finally_on_new_line = false
ij_typescript_for_brace_force = never
ij_typescript_for_statement_new_line_after_left_paren = false
ij_typescript_for_statement_right_paren_on_new_line = false
ij_typescript_for_statement_wrap = off
ij_typescript_force_quote_style = true
ij_typescript_force_semicolon_style = true
ij_typescript_function_expression_brace_style = end_of_line
ij_typescript_if_brace_force = never
ij_typescript_import_merge_members = global
ij_typescript_import_prefer_absolute_path = global
ij_typescript_import_sort_members = true
ij_typescript_import_sort_module_name = false
ij_typescript_import_use_node_resolution = true
ij_typescript_imports_wrap = on_every_item
ij_typescript_indent_case_from_switch = true
ij_typescript_indent_chained_calls = true
ij_typescript_indent_package_children = 0
ij_typescript_jsdoc_include_types = false
ij_typescript_jsx_attribute_value = braces
ij_typescript_keep_blank_lines_in_code = 1
ij_typescript_keep_first_column_comment = true
ij_typescript_keep_indents_on_empty_lines = false
ij_typescript_keep_line_breaks = true
ij_typescript_keep_simple_blocks_in_one_line = false
ij_typescript_keep_simple_methods_in_one_line = false
ij_typescript_line_comment_add_space = true
ij_typescript_line_comment_at_first_column = false
ij_typescript_method_brace_style = end_of_line
ij_typescript_method_call_chain_wrap = off
ij_typescript_method_parameters_new_line_after_left_paren = false
ij_typescript_method_parameters_right_paren_on_new_line = false
ij_typescript_method_parameters_wrap = off
ij_typescript_object_literal_wrap = on_every_item
ij_typescript_parentheses_expression_new_line_after_left_paren = false
ij_typescript_parentheses_expression_right_paren_on_new_line = false
ij_typescript_place_assignment_sign_on_next_line = false
ij_typescript_prefer_as_type_cast = false
ij_typescript_prefer_explicit_types_function_expression_returns = false
ij_typescript_prefer_explicit_types_function_returns = false
ij_typescript_prefer_explicit_types_vars_fields = false
ij_typescript_prefer_parameters_wrap = false
ij_typescript_reformat_c_style_comments = false
ij_typescript_space_after_colon = true
ij_typescript_space_after_comma = true
ij_typescript_space_after_dots_in_rest_parameter = false
ij_typescript_space_after_generator_mult = true
ij_typescript_space_after_property_colon = true
ij_typescript_space_after_quest = true
ij_typescript_space_after_type_colon = true
ij_typescript_space_after_unary_not = false
ij_typescript_space_before_async_arrow_lparen = true
ij_typescript_space_before_catch_keyword = true
ij_typescript_space_before_catch_left_brace = true
ij_typescript_space_before_catch_parentheses = true
ij_typescript_space_before_class_lbrace = true
ij_typescript_space_before_class_left_brace = true
ij_typescript_space_before_colon = true
ij_typescript_space_before_comma = false
ij_typescript_space_before_do_left_brace = true
ij_typescript_space_before_else_keyword = true
ij_typescript_space_before_else_left_brace = true
ij_typescript_space_before_finally_keyword = true
ij_typescript_space_before_finally_left_brace = true
ij_typescript_space_before_for_left_brace = true
ij_typescript_space_before_for_parentheses = true
ij_typescript_space_before_for_semicolon = false
ij_typescript_space_before_function_left_parenth = true
ij_typescript_space_before_generator_mult = false
ij_typescript_space_before_if_left_brace = true
ij_typescript_space_before_if_parentheses = true
ij_typescript_space_before_method_call_parentheses = false
ij_typescript_space_before_method_left_brace = true
ij_typescript_space_before_method_parentheses = false
ij_typescript_space_before_property_colon = false
ij_typescript_space_before_quest = true
ij_typescript_space_before_switch_left_brace = true
ij_typescript_space_before_switch_parentheses = true
ij_typescript_space_before_try_left_brace = true
ij_typescript_space_before_type_colon = false
ij_typescript_space_before_unary_not = false
ij_typescript_space_before_while_keyword = true
ij_typescript_space_before_while_left_brace = true
ij_typescript_space_before_while_parentheses = true
ij_typescript_spaces_around_additive_operators = true
ij_typescript_spaces_around_arrow_function_operator = true
ij_typescript_spaces_around_assignment_operators = true
ij_typescript_spaces_around_bitwise_operators = true
ij_typescript_spaces_around_equality_operators = true
ij_typescript_spaces_around_logical_operators = true
ij_typescript_spaces_around_multiplicative_operators = true
ij_typescript_spaces_around_relational_operators = true
ij_typescript_spaces_around_shift_operators = true
ij_typescript_spaces_around_unary_operator = false
ij_typescript_spaces_within_array_initializer_brackets = false
ij_typescript_spaces_within_brackets = false
ij_typescript_spaces_within_catch_parentheses = false
ij_typescript_spaces_within_for_parentheses = false
ij_typescript_spaces_within_if_parentheses = false
ij_typescript_spaces_within_imports = true
ij_typescript_spaces_within_interpolation_expressions = false
ij_typescript_spaces_within_method_call_parentheses = false
ij_typescript_spaces_within_method_parentheses = false
ij_typescript_spaces_within_object_literal_braces = true
ij_typescript_spaces_within_object_type_braces = true
ij_typescript_spaces_within_parentheses = false
ij_typescript_spaces_within_switch_parentheses = false
ij_typescript_spaces_within_type_assertion = false
ij_typescript_spaces_within_union_types = true
ij_typescript_spaces_within_while_parentheses = false
ij_typescript_special_else_if_treatment = true
ij_typescript_ternary_operation_signs_on_next_line = false
ij_typescript_ternary_operation_wrap = off
ij_typescript_union_types_wrap = on_every_item
ij_typescript_use_chained_calls_group_indents = false
ij_typescript_use_double_quotes = false
ij_typescript_use_explicit_js_extension = global
ij_typescript_use_path_mapping = always
ij_typescript_use_public_modifier = false
ij_typescript_use_semicolon_after_statement = false
ij_typescript_var_declaration_wrap = normal
ij_typescript_while_brace_force = never
ij_typescript_while_on_new_line = false
ij_typescript_wrap_comments = false
[{*.bash, *.sh, *.zsh}]
indent_size = 2
tab_width = 2
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{*.cjs, *.js}]
ij_continuation_indent_size = 4
ij_javascript_align_imports = false
ij_javascript_align_multiline_array_initializer_expression = false
ij_javascript_align_multiline_binary_operation = false
ij_javascript_align_multiline_chained_methods = false
ij_javascript_align_multiline_extends_list = false
ij_javascript_align_multiline_for = true
ij_javascript_align_multiline_parameters = true
ij_javascript_align_multiline_parameters_in_calls = false
ij_javascript_align_multiline_ternary_operation = false
ij_javascript_align_object_properties = 0
ij_javascript_align_union_types = false
ij_javascript_align_var_statements = 0
ij_javascript_array_initializer_new_line_after_left_brace = false
ij_javascript_array_initializer_right_brace_on_new_line = false
ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
ij_javascript_blank_lines_around_function = 1
ij_javascript_blank_lines_around_method = 1
ij_javascript_block_brace_style = end_of_line
ij_javascript_call_parameters_new_line_after_left_paren = false
ij_javascript_call_parameters_right_paren_on_new_line = false
ij_javascript_call_parameters_wrap = off
ij_javascript_catch_on_new_line = false
ij_javascript_chained_call_dot_on_new_line = true
ij_javascript_class_brace_style = end_of_line
ij_javascript_comma_on_new_line = false
ij_javascript_do_while_brace_force = never
ij_javascript_else_on_new_line = false
ij_javascript_enforce_trailing_comma = keep
ij_javascript_extends_keyword_wrap = off
ij_javascript_extends_list_wrap = off
ij_javascript_field_prefix = _
ij_javascript_file_name_style = relaxed
ij_javascript_finally_on_new_line = false
ij_javascript_for_brace_force = never
ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off
ij_javascript_force_quote_style = false
ij_javascript_force_semicolon_style = false
ij_javascript_function_expression_brace_style = end_of_line
ij_javascript_if_brace_force = never
ij_javascript_import_merge_members = global
ij_javascript_import_prefer_absolute_path = global
ij_javascript_import_sort_members = true
ij_javascript_import_sort_module_name = false
ij_javascript_import_use_node_resolution = true
ij_javascript_imports_wrap = on_every_item
ij_javascript_indent_case_from_switch = true
ij_javascript_indent_chained_calls = true
ij_javascript_indent_package_children = 0
ij_javascript_jsx_attribute_value = braces
ij_javascript_keep_blank_lines_in_code = 2
ij_javascript_keep_first_column_comment = true
ij_javascript_keep_indents_on_empty_lines = false
ij_javascript_keep_line_breaks = true
ij_javascript_keep_simple_blocks_in_one_line = false
ij_javascript_keep_simple_methods_in_one_line = false
ij_javascript_line_comment_add_space = true
ij_javascript_line_comment_at_first_column = false
ij_javascript_method_brace_style = end_of_line
ij_javascript_method_call_chain_wrap = off
ij_javascript_method_parameters_new_line_after_left_paren = false
ij_javascript_method_parameters_right_paren_on_new_line = false
ij_javascript_method_parameters_wrap = off
ij_javascript_object_literal_wrap = on_every_item
ij_javascript_parentheses_expression_new_line_after_left_paren = false
ij_javascript_parentheses_expression_right_paren_on_new_line = false
ij_javascript_place_assignment_sign_on_next_line = false
ij_javascript_prefer_as_type_cast = false
ij_javascript_prefer_explicit_types_function_expression_returns = false
ij_javascript_prefer_explicit_types_function_returns = false
ij_javascript_prefer_explicit_types_vars_fields = false
ij_javascript_prefer_parameters_wrap = false
ij_javascript_reformat_c_style_comments = false
ij_javascript_space_after_colon = true
ij_javascript_space_after_comma = true
ij_javascript_space_after_dots_in_rest_parameter = false
ij_javascript_space_after_generator_mult = true
ij_javascript_space_after_property_colon = true
ij_javascript_space_after_quest = true
ij_javascript_space_after_type_colon = true
ij_javascript_space_after_unary_not = false
ij_javascript_space_before_async_arrow_lparen = true
ij_javascript_space_before_catch_keyword = true
ij_javascript_space_before_catch_left_brace = true
ij_javascript_space_before_catch_parentheses = true
ij_javascript_space_before_class_lbrace = true
ij_javascript_space_before_class_left_brace = true
ij_javascript_space_before_colon = true
ij_javascript_space_before_comma = false
ij_javascript_space_before_do_left_brace = true
ij_javascript_space_before_else_keyword = true
ij_javascript_space_before_else_left_brace = true
ij_javascript_space_before_finally_keyword = true
ij_javascript_space_before_finally_left_brace = true
ij_javascript_space_before_for_left_brace = true
ij_javascript_space_before_for_parentheses = true
ij_javascript_space_before_for_semicolon = false
ij_javascript_space_before_function_left_parenth = true
ij_javascript_space_before_generator_mult = false
ij_javascript_space_before_if_left_brace = true
ij_javascript_space_before_if_parentheses = true
ij_javascript_space_before_method_call_parentheses = false
ij_javascript_space_before_method_left_brace = true
ij_javascript_space_before_method_parentheses = false
ij_javascript_space_before_property_colon = false
ij_javascript_space_before_quest = true
ij_javascript_space_before_switch_left_brace = true
ij_javascript_space_before_switch_parentheses = true
ij_javascript_space_before_try_left_brace = true
ij_javascript_space_before_type_colon = false
ij_javascript_space_before_unary_not = false
ij_javascript_space_before_while_keyword = true
ij_javascript_space_before_while_left_brace = true
ij_javascript_space_before_while_parentheses = true
ij_javascript_spaces_around_additive_operators = true
ij_javascript_spaces_around_arrow_function_operator = true
ij_javascript_spaces_around_assignment_operators = true
ij_javascript_spaces_around_bitwise_operators = true
ij_javascript_spaces_around_equality_operators = true
ij_javascript_spaces_around_logical_operators = true
ij_javascript_spaces_around_multiplicative_operators = true
ij_javascript_spaces_around_relational_operators = true
ij_javascript_spaces_around_shift_operators = true
ij_javascript_spaces_around_unary_operator = false
ij_javascript_spaces_within_array_initializer_brackets = false
ij_javascript_spaces_within_brackets = false
ij_javascript_spaces_within_catch_parentheses = false
ij_javascript_spaces_within_for_parentheses = false
ij_javascript_spaces_within_if_parentheses = false
ij_javascript_spaces_within_imports = false
ij_javascript_spaces_within_interpolation_expressions = false
ij_javascript_spaces_within_method_call_parentheses = false
ij_javascript_spaces_within_method_parentheses = false
ij_javascript_spaces_within_object_literal_braces = false
ij_javascript_spaces_within_object_type_braces = true
ij_javascript_spaces_within_parentheses = false
ij_javascript_spaces_within_switch_parentheses = false
ij_javascript_spaces_within_type_assertion = false
ij_javascript_spaces_within_union_types = true
ij_javascript_spaces_within_while_parentheses = false
ij_javascript_special_else_if_treatment = true
ij_javascript_ternary_operation_signs_on_next_line = false
ij_javascript_ternary_operation_wrap = off
ij_javascript_union_types_wrap = on_every_item
ij_javascript_use_chained_calls_group_indents = false
ij_javascript_use_double_quotes = true
ij_javascript_use_explicit_js_extension = global
ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = never
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.cjsx, *.coffee}]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 2
ij_coffeescript_align_function_body = false
ij_coffeescript_align_imports = false
ij_coffeescript_align_multiline_array_initializer_expression = true
ij_coffeescript_align_multiline_parameters = true
ij_coffeescript_align_multiline_parameters_in_calls = false
ij_coffeescript_align_object_properties = 0
ij_coffeescript_align_union_types = false
ij_coffeescript_align_var_statements = 0
ij_coffeescript_array_initializer_new_line_after_left_brace = false
ij_coffeescript_array_initializer_right_brace_on_new_line = false
ij_coffeescript_array_initializer_wrap = normal
ij_coffeescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/**
ij_coffeescript_blank_lines_around_function = 1
ij_coffeescript_call_parameters_new_line_after_left_paren = false
ij_coffeescript_call_parameters_right_paren_on_new_line = false
ij_coffeescript_call_parameters_wrap = normal
ij_coffeescript_chained_call_dot_on_new_line = true
ij_coffeescript_comma_on_new_line = false
ij_coffeescript_enforce_trailing_comma = keep
ij_coffeescript_field_prefix = _
ij_coffeescript_file_name_style = relaxed
ij_coffeescript_force_quote_style = false
ij_coffeescript_force_semicolon_style = false
ij_coffeescript_function_expression_brace_style = end_of_line
ij_coffeescript_import_merge_members = global
ij_coffeescript_import_prefer_absolute_path = global
ij_coffeescript_import_sort_members = true
ij_coffeescript_import_sort_module_name = false
ij_coffeescript_import_use_node_resolution = true
ij_coffeescript_imports_wrap = on_every_item
ij_coffeescript_indent_chained_calls = true
ij_coffeescript_indent_package_children = 0
ij_coffeescript_jsx_attribute_value = braces
ij_coffeescript_keep_blank_lines_in_code = 2
ij_coffeescript_keep_first_column_comment = true
ij_coffeescript_keep_indents_on_empty_lines = false
ij_coffeescript_keep_line_breaks = true
ij_coffeescript_keep_simple_methods_in_one_line = false
ij_coffeescript_method_parameters_new_line_after_left_paren = false
ij_coffeescript_method_parameters_right_paren_on_new_line = false
ij_coffeescript_method_parameters_wrap = off
ij_coffeescript_object_literal_wrap = on_every_item
ij_coffeescript_prefer_as_type_cast = false
ij_coffeescript_prefer_explicit_types_function_expression_returns = false
ij_coffeescript_prefer_explicit_types_function_returns = false
ij_coffeescript_prefer_explicit_types_vars_fields = false
ij_coffeescript_reformat_c_style_comments = false
ij_coffeescript_space_after_comma = true
ij_coffeescript_space_after_dots_in_rest_parameter = false
ij_coffeescript_space_after_generator_mult = true
ij_coffeescript_space_after_property_colon = true
ij_coffeescript_space_after_type_colon = true
ij_coffeescript_space_after_unary_not = false
ij_coffeescript_space_before_async_arrow_lparen = true
ij_coffeescript_space_before_class_lbrace = true
ij_coffeescript_space_before_comma = false
ij_coffeescript_space_before_function_left_parenth = true
ij_coffeescript_space_before_generator_mult = false
ij_coffeescript_space_before_property_colon = false
ij_coffeescript_space_before_type_colon = false
ij_coffeescript_space_before_unary_not = false
ij_coffeescript_spaces_around_additive_operators = true
ij_coffeescript_spaces_around_arrow_function_operator = true
ij_coffeescript_spaces_around_assignment_operators = true
ij_coffeescript_spaces_around_bitwise_operators = true
ij_coffeescript_spaces_around_equality_operators = true
ij_coffeescript_spaces_around_logical_operators = true
ij_coffeescript_spaces_around_multiplicative_operators = true
ij_coffeescript_spaces_around_relational_operators = true
ij_coffeescript_spaces_around_shift_operators = true
ij_coffeescript_spaces_around_unary_operator = false
ij_coffeescript_spaces_within_array_initializer_braces = false
ij_coffeescript_spaces_within_array_initializer_brackets = false
ij_coffeescript_spaces_within_imports = false
ij_coffeescript_spaces_within_index_brackets = false
ij_coffeescript_spaces_within_interpolation_expressions = false
ij_coffeescript_spaces_within_method_call_parentheses = false
ij_coffeescript_spaces_within_method_parentheses = false
ij_coffeescript_spaces_within_object_braces = false
ij_coffeescript_spaces_within_object_literal_braces = false
ij_coffeescript_spaces_within_object_type_braces = true
ij_coffeescript_spaces_within_range_brackets = false
ij_coffeescript_spaces_within_type_assertion = false
ij_coffeescript_spaces_within_union_types = true
ij_coffeescript_union_types_wrap = on_every_item
ij_coffeescript_use_chained_calls_group_indents = false
ij_coffeescript_use_double_quotes = true
ij_coffeescript_use_explicit_js_extension = global
ij_coffeescript_use_path_mapping = always
ij_coffeescript_use_public_modifier = false
ij_coffeescript_use_semicolon_after_statement = false
ij_coffeescript_var_declaration_wrap = normal
[{*.har, *.jsb2, *.jsb3, *.json, .babelrc, .eslintrc, .prettierrc, .stylelintrc, bowerrc, jest.config}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm, *.html, *.ng, *.sht, *.shtm, *.shtml}]
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p
ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span, pre, textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
[{*.yaml, *.yml}]
indent_size = 2
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
+2
View File
@@ -0,0 +1,2 @@
build
coverage
+57
View File
@@ -0,0 +1,57 @@
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
extends: [
"plugin:@typescript-eslint/recommended",
"airbnb-base",
"airbnb/hooks",
"prettier",
"prettier/@typescript-eslint",
"plugin:react/recommended",
"plugin:prettier/recommended",
"plugin:jest/recommended",
],
plugins: ["react", "import", "jest", "jsx-a11y", "prettier"],
env: {
browser: true,
es6: true,
},
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly",
},
settings: {
react: {
version: "detect",
},
},
rules: {
"import/no-extraneous-dependencies": [
"warn",
{
devDependencies: ["**/*.test.js", "**/*.test.jsx", "**/setup-tests.js"],
},
],
"linebreak-style": "off",
"import/extensions": "off",
"import/no-unresolved": "off",
"import/prefer-default-export": "off",
"prettier/prettier": [
"error",
{
endOfLine: "auto",
},
],
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/prefer-to-have-length": "warn",
"jest/valid-expect": "error",
},
};
+1
View File
@@ -3,3 +3,4 @@ package-lock.json
build build
.idea .idea
.firebase .firebase
yarn.lock
+1
View File
@@ -0,0 +1 @@
registry=https://registry.npmjs.com/
+2
View File
@@ -0,0 +1,2 @@
build
coverage
+16
View File
@@ -0,0 +1,16 @@
module.exports = {
extends: [
"stylelint-config-recommended-scss",
"stylelint-config-standard",
"stylelint-config-rational-order",
],
rules: {
indentation: 4,
"rule-empty-line-before": null,
"at-rule-empty-line-before": null,
"declaration-empty-line-before": null,
"no-descending-specificity": null,
"number-leading-zero": "never",
"string-quotes": "double",
},
};
+38 -2
View File
@@ -2,11 +2,15 @@
"name": "wow-best-places", "name": "wow-best-places",
"description": "This app is supposed to make you feel nostalgic", "description": "This app is supposed to make you feel nostalgic",
"version": "1.3.1", "version": "1.3.1",
"license": "MIT",
"author": { "author": {
"name": "obergodmar", "name": "obergodmar",
"email": "obergodmar@gmail.com", "email": "obergodmar@gmail.com",
"url": "https://github.com/obergodmar" "url": "https://github.com/obergodmar"
}, },
"engines": {
"node": "10.18.1"
},
"dependencies": { "dependencies": {
"classnames": "^2.2.6", "classnames": "^2.2.6",
"react": "^16.13.1", "react": "^16.13.1",
@@ -15,18 +19,50 @@
"serve": "^11.3.2" "serve": "^11.3.2"
}, },
"devDependencies": { "devDependencies": {
"@jest/globals": "^26.3.0",
"@types/classnames": "^2.2.10", "@types/classnames": "^2.2.10",
"@types/react": "^16.9.41", "@types/react": "^16.9.41",
"@types/react-dom": "^16.9.8", "@types/react-dom": "^16.9.8",
"@typescript-eslint/eslint-plugin": "^3.9.1",
"@typescript-eslint/parser": "^3.9.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.3",
"enzyme-to-json": "^3.5.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^23.20.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.20.5",
"eslint-plugin-react-hooks": "^4.0.8",
"husky": "^4.2.5",
"jest-css-modules": "^2.1.0",
"node-sass": "^4.14.1", "node-sass": "^4.14.1",
"tslint": "^6.1.2", "prettier": "^2.0.5",
"stylelint": "^13.6.1",
"stylelint-config-rational-order": "^0.1.2",
"stylelint-config-recommended-scss": "^4.2.0",
"stylelint-config-standard": "^20.0.0",
"stylelint-scss": "^3.18.0",
"typescript": "^3.9.5" "typescript": "^3.9.5"
}, },
"scripts": { "scripts": {
"start": "serve ./build", "start": "serve ./build",
"dev": "react-scripts start", "dev": "react-scripts start",
"build": "env GENERATE_SOURCEMAP=false react-scripts build", "build": "env GENERATE_SOURCEMAP=false react-scripts build",
"eject": "react-scripts eject" "eslint": "npx eslint --ext .ts,.tsx ./src",
"eslint:fix": "npx eslint --ext .ts,.tsx . --fix ./src",
"stylelint": "npx stylelint \"src/**/*.scss\"",
"stylelint:fix": "npx stylelint --fix \"src/**/*.scss\"",
"test": "npm run test:u && npm run test:cov",
"test:u": "jest -u",
"test:cov": "jest --coverage"
},
"husky": {
"hooks": {
"pre-commit": "yarn eslint && yarn stylelint"
}
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app" "extends": "react-app"
+239 -187
View File
@@ -1,212 +1,264 @@
import * as React from 'react' import * as React from "react";
import { KeyboardEvent, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import {
KeyboardEvent,
useCallback,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from "react";
import { import {
MainMenuComponent, MainMenuComponent,
MenuItemComponent, MenuItemComponent,
MusicComponent, MusicComponent,
PanelComponent, PanelComponent,
PreviewComponent, PreviewComponent,
SettingsComponent, SettingsComponent,
ViewComponent ViewComponent,
} from '../components' } from "../components";
import places from '../assets' import places from "../assets";
import { delay, soundLoad, UI_SOUND_VOLUME } from '../utils' import { delay, soundLoad, UI_SOUND_VOLUME } from "../utils";
import { useSettings } from '../hooks' import { useSettings } from "../hooks";
import PanelOpenAudio from '../assets/audio/panel-open.ogg' import PanelOpenAudio from "../assets/audio/panel-open.ogg";
import PanelCloseAudio from '../assets/audio/panel-close.ogg' import PanelCloseAudio from "../assets/audio/panel-close.ogg";
import SettingsOpenAudio from '../assets/audio/menu-open.ogg' import SettingsOpenAudio from "../assets/audio/menu-open.ogg";
import SettingsCloseAudio from '../assets/audio/menu-close.ogg' import SettingsCloseAudio from "../assets/audio/menu-close.ogg";
import CheckBoxOnAudio from '../assets/audio/check-box-on.ogg' import CheckBoxOnAudio from "../assets/audio/check-box-on.ogg";
import CheckBoxOffAudio from '../assets/audio/check-box-off.ogg' import CheckBoxOffAudio from "../assets/audio/check-box-off.ogg";
import Sound from '../modules/sound' import Sound from "../modules/sound";
import './style.scss' import "./style.scss";
export default function App() { export default function App(): JSX.Element {
const {settings: {uiSound, musicVolume, language}} = useSettings() const {
const [isSettingsShown, setSettingsShown] = useState(false) settings: { uiSound, musicVolume, language },
const [isLoading, setLoading] = useState(false) } = useSettings();
const [isPlaying, setPlaying] = useState(false) const [isSettingsShown, setSettingsShown] = useState(false);
const [isLeftPanelShown, setLeftPanelShown] = useState(false) const [isLoading, setLoading] = useState(false);
const [isBottomPanelShown, setBottomPanelShown] = useState(false) const [isPlaying, setPlaying] = useState(false);
const [activePlace, setActivePlace] = useState(0) const [isLeftPanelShown, setLeftPanelShown] = useState(false);
const [activeView, setActiveView] = useState(0) const [isBottomPanelShown, setBottomPanelShown] = useState(false);
const [activePlace, setActivePlace] = useState(0);
const [activeView, setActiveView] = useState(0);
const panelOpenSound = useMemo(() => soundLoad(PanelOpenAudio, UI_SOUND_VOLUME), []) const panelOpenSound = useMemo(
const panelCloseSound = useMemo(() => soundLoad(PanelCloseAudio, UI_SOUND_VOLUME), []) () => soundLoad(PanelOpenAudio, UI_SOUND_VOLUME),
const settingsOpenSound = useMemo(() => soundLoad(SettingsOpenAudio, UI_SOUND_VOLUME), []) []
const settingsCloseSound = useMemo(() => soundLoad(SettingsCloseAudio, UI_SOUND_VOLUME), []) );
const checkboxOnSound = useMemo(() => soundLoad(CheckBoxOnAudio, UI_SOUND_VOLUME), []) const panelCloseSound = useMemo(
const checkboxOffSound = useMemo(() => soundLoad(CheckBoxOffAudio, UI_SOUND_VOLUME), []) () => soundLoad(PanelCloseAudio, UI_SOUND_VOLUME),
[]
);
const settingsOpenSound = useMemo(
() => soundLoad(SettingsOpenAudio, UI_SOUND_VOLUME),
[]
);
const settingsCloseSound = useMemo(
() => soundLoad(SettingsCloseAudio, UI_SOUND_VOLUME),
[]
);
const checkboxOnSound = useMemo(
() => soundLoad(CheckBoxOnAudio, UI_SOUND_VOLUME),
[]
);
const checkboxOffSound = useMemo(
() => soundLoad(CheckBoxOffAudio, UI_SOUND_VOLUME),
[]
);
const [currentPlaying, setCurrentPlaying] = useState<Sound>() const [currentPlaying, setCurrentPlaying] = useState<Sound>();
const app = useRef<HTMLDivElement>(null) const app = useRef<HTMLDivElement>(null);
const handleHideLeftPanel = useCallback(() => { const handleHideLeftPanel = useCallback(() => {
setBottomPanelShown(false) setBottomPanelShown(false);
setLeftPanelShown(!isLeftPanelShown) setLeftPanelShown(!isLeftPanelShown);
}, [isLeftPanelShown]) }, [isLeftPanelShown]);
const handleHideBottomPanel = useCallback(() => { const handleHideBottomPanel = useCallback(() => {
setLeftPanelShown(false) setLeftPanelShown(false);
setBottomPanelShown(!isBottomPanelShown) setBottomPanelShown(!isBottomPanelShown);
}, [isBottomPanelShown]) }, [isBottomPanelShown]);
const delayedChange = useCallback((fn: (value: number) => void, value: number) => { const delayedChange = useCallback(
if (isLoading) { (fn: (value: number) => void, value: number) => {
return if (isLoading) {
} return;
fn(value) }
setLoading(true) fn(value);
delay().then(() => { setLoading(true);
setLoading(false) delay().then(() => {
}) setLoading(false);
}, [isLoading]) });
},
[isLoading]
);
const handleLeftPreviewClick = useCallback((value: number) => { const handleLeftPreviewClick = useCallback(
delayedChange(setActivePlace, value) (value: number) => {
setActiveView(0) delayedChange(setActivePlace, value);
}, [delayedChange]) setActiveView(0);
},
[delayedChange]
);
const handleBottomPreviewClick = useCallback((value: number) => { const handleBottomPreviewClick = useCallback(
delayedChange(setActiveView, value) (value: number) => {
}, [delayedChange]) delayedChange(setActiveView, value);
},
[delayedChange]
);
useEffect(() => { useEffect(() => {
if (app && app.current) { if (app && app.current) {
app.current.focus() app.current.focus();
} }
}, [app]) }, [app]);
useLayoutEffect(() => { useLayoutEffect(() => {
document.title = language[`place.${places[activePlace].name}` as keyof typeof language] document.title =
}, [activePlace, language]) language[`place.${places[activePlace].name}` as keyof typeof language];
}, [activePlace, language]);
useEffect(() => { useEffect(() => {
if (!currentPlaying) { if (!currentPlaying) {
return return;
} }
currentPlaying.setVolume(musicVolume) currentPlaying.setVolume(musicVolume);
currentPlaying.playMusic() currentPlaying.playMusic();
}, [currentPlaying, musicVolume]) }, [currentPlaying, musicVolume]);
const appClick = useCallback(() => currentPlaying && currentPlaying.playMusic(), [currentPlaying]) const appClick = useCallback(
() => currentPlaying && currentPlaying.playMusic(),
[currentPlaying]
);
const openCloseSettings = useCallback(() => { const openCloseSettings = useCallback(() => {
setSettingsShown(!isSettingsShown) setSettingsShown(!isSettingsShown);
if (app && app.current) { if (app && app.current) {
app.current.focus() app.current.focus();
} }
if (!uiSound) { if (!uiSound) {
return return;
} }
if (isSettingsShown) { if (isSettingsShown) {
settingsCloseSound.playSound() settingsCloseSound.playSound();
} else { } else {
settingsOpenSound.playSound() settingsOpenSound.playSound();
} }
}, [app, isSettingsShown, uiSound, settingsCloseSound, settingsOpenSound]) }, [app, isSettingsShown, uiSound, settingsCloseSound, settingsOpenSound]);
const handleOpenSettings = useCallback((e: KeyboardEvent) => { const handleOpenSettings = useCallback(
switch (e.keyCode) { (e: KeyboardEvent) => {
case 27: switch (e.keyCode) {
if (isLeftPanelShown || isBottomPanelShown) { case 27:
setLeftPanelShown(false) if (isLeftPanelShown || isBottomPanelShown) {
setBottomPanelShown(false) setLeftPanelShown(false);
break setBottomPanelShown(false);
} break;
openCloseSettings() }
break openCloseSettings();
case 32: break;
if (!currentPlaying) { case 32:
return if (!currentPlaying) {
} return;
if (isPlaying) { }
currentPlaying.pause() if (isPlaying) {
setPlaying(false) currentPlaying.pause();
} else { setPlaying(false);
currentPlaying.playMusic() } else {
} currentPlaying.playMusic();
} }
}, [isLeftPanelShown, isBottomPanelShown, isPlaying, currentPlaying, openCloseSettings]) break;
default:
break;
}
},
[
isLeftPanelShown,
isBottomPanelShown,
isPlaying,
currentPlaying,
openCloseSettings,
]
);
return ( return (
<div <div
ref={app} ref={app}
onClick={appClick} onClick={appClick}
onKeyDown={handleOpenSettings} onKeyDown={handleOpenSettings}
tabIndex={0} tabIndex={0}
className='main' className="main"
> >
<ViewComponent src={places[activePlace].view[activeView]} /> <ViewComponent src={places[activePlace].view[activeView]} />
<MainMenuComponent> <MainMenuComponent>
<div className='author'> <div className="author">
<a href="https://github.com/obergodmar">obergodmar</a> <a href="https://github.com/obergodmar">obergodmar</a>
<span>v1.3.1</span> <span>v1.3.1</span>
</div> </div>
<MenuItemComponent <MenuItemComponent
isActive={isSettingsShown} isActive={isSettingsShown}
handleClick={openCloseSettings} handleClick={openCloseSettings}
/> />
</MainMenuComponent> </MainMenuComponent>
<PanelComponent <PanelComponent
openSoundPlay={panelOpenSound.playSound} openSoundPlay={panelOpenSound.playSound}
closeSoundPlay={panelCloseSound.playSound} closeSoundPlay={panelCloseSound.playSound}
itemsCount={places.length || 0} itemsCount={places.length || 0}
orientation='left' orientation="left"
isShown={isLeftPanelShown} isShown={isLeftPanelShown}
setShown={handleHideLeftPanel} setShown={handleHideLeftPanel}
> >
{places.map((place, index) => ( {places.map((place, index) => (
<PreviewComponent <PreviewComponent
name={`place.${place.name}`} name={`place.${place.name}`}
isLoading={isLoading} isLoading={isLoading}
key={index} key={index}
value={index} value={index}
handleChange={handleLeftPreviewClick} handleChange={handleLeftPreviewClick}
src={place.preview[0]} src={place.preview[0]}
/> />
))} ))}
</PanelComponent> </PanelComponent>
<PanelComponent <PanelComponent
openSoundPlay={panelOpenSound.playSound} openSoundPlay={panelOpenSound.playSound}
closeSoundPlay={panelCloseSound.playSound} closeSoundPlay={panelCloseSound.playSound}
itemsCount={places[activePlace].preview.length || 0} itemsCount={places[activePlace].preview.length || 0}
orientation='bottom' orientation="bottom"
isShown={isBottomPanelShown} isShown={isBottomPanelShown}
setShown={handleHideBottomPanel} setShown={handleHideBottomPanel}
> >
{places[activePlace].preview.map((preview, index) => ( {places[activePlace].preview.map((preview, index) => (
<PreviewComponent <PreviewComponent
isLoading={isLoading} isLoading={isLoading}
key={index} key={index}
value={index} value={index}
handleChange={handleBottomPreviewClick} handleChange={handleBottomPreviewClick}
src={preview} src={preview}
/> />
))} ))}
</PanelComponent> </PanelComponent>
{isSettingsShown && ( {isSettingsShown && (
<SettingsComponent <SettingsComponent
closeSettings={openCloseSettings} closeSettings={openCloseSettings}
checkboxOnSoundPlay={checkboxOnSound.playSound} checkboxOnSoundPlay={checkboxOnSound.playSound}
checkboxOffSoundPlay={checkboxOffSound.playSound} checkboxOffSoundPlay={checkboxOffSound.playSound}
/> />
) )}
} <MusicComponent
<MusicComponent music={places[activePlace].music}
music={places[activePlace].music} setPlaying={setPlaying}
setPlaying={setPlaying} setCurrentPlaying={setCurrentPlaying}
setCurrentPlaying={setCurrentPlaying} />
/> </div>
</div> );
)
} }
App.displayName = 'App' App.displayName = "App";
+61 -61
View File
@@ -1,17 +1,17 @@
@import "../assets/assets"; @import "../assets/assets";
$hoverColor: rgba(173, 154, 32, 0.75); $hoverColor: rgba(173, 154, 32, .75);
$hoverBox: 0 0 4px 2px $hoverColor; $hoverBox: 0 0 4px 2px $hoverColor;
$previewHeight: 180px; $previewHeight: 180px;
$previewWidth: 320px; $previewWidth: 320px;
$font: 'Arial Narrow'; $font: "Arial Narrow";
$fontSpacing: 1.2px; $fontSpacing: 1.2px;
$fontSize: 14px; $fontSize: 14px;
//$fontShadow: 2px 2px 2px #000; //$fontShadow: 2px 2px 2px #000;
$fontShadow: -1px -1px 1px #000, $fontShadow: -1px -1px 1px #000,
1px -1px 1px #000, 1px -1px 1px #000,
-1px 1px 1px #000, -1px 1px 1px #000,
1px 1px 1px #000; 1px 1px 1px #000;
$buttonSmallWidth: 78px; $buttonSmallWidth: 78px;
$buttonSmallHeight: 21px; $buttonSmallHeight: 21px;
$buttonWidth: 125px; $buttonWidth: 125px;
@@ -20,77 +20,77 @@ $fontColor: #eec511;
$fontColorWhite: #fff; $fontColorWhite: #fff;
$transitionDuration: 500ms; $transitionDuration: 500ms;
$transitionType: cubic-bezier(1, .35, .57, 1); $transitionType: cubic-bezier(1, .35, .57, 1);
$settingsBackground: rgba(0, 0, 0, 0.6); $settingsBackground: rgba(0, 0, 0, .6);
body { body {
cursor: $cursor, auto; overflow: hidden;
background-image: $backgroundTexture; background-image: $backgroundTexture;
background-repeat: repeat; background-repeat: repeat;
overflow: hidden; cursor: $cursor, auto;
} }
.main { .main {
width: 100vw; position: relative;
height: 100vh; width: 100vw;
overflow: hidden; height: 100vh;
position: relative; overflow: hidden;
} }
.author { .author {
padding: 0 10px; display: flex;
width: 0; align-items: center;
opacity: 0; justify-content: space-between;
font-family: $font; width: 0;
text-shadow: $fontShadow; padding: 0 10px;
color: $fontColor; color: $fontColor;
font-size: 16px; font-size: 16px;
display: flex; font-family: $font;
align-items: center; text-shadow: $fontShadow;
transition: width $transitionDuration $transitionType, opacity $transitionDuration $transitionType; opacity: 0;
justify-content: space-between; transition: width $transitionDuration $transitionType, opacity $transitionDuration $transitionType;
a { a {
cursor: $cursorPointer, auto; color: inherit;
color: inherit; text-decoration: none;
text-decoration: none; cursor: $cursorPointer, auto;
&:focus { &:focus {
outline: none; outline: none;
box-shadow: $hoverBox; box-shadow: $hoverBox;
}
} }
}
} }
button { button {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; align-items: center;
align-items: center; justify-content: flex-start;
font-family: $font; width: $buttonWidth;
font-size: $fontSize; height: $buttonHeight;
text-shadow: $fontShadow; color: $fontColor;
letter-spacing: $fontSpacing; font-size: $fontSize;
color: $fontColor; font-family: $font;
cursor: $cursor, auto; letter-spacing: $fontSpacing;
width: $buttonWidth; text-shadow: $fontShadow;
height: $buttonHeight; background-color: unset;
border: none; background-image: $buttonUp;
border-radius: 6px; background-position: -2px -2px;
background-color: unset; border: none;
background-image: $buttonUp; border-radius: 6px;
background-position: -2px -2px; cursor: $cursor, auto;
&:hover { &:hover {
background-image: $buttonHover, $buttonUp; background-image: $buttonHover, $buttonUp;
} }
&:focus { &:focus {
outline: none; outline: none;
box-shadow: $hoverBox; box-shadow: $hoverBox;
} }
&:active { &:active {
justify-content: center; justify-content: center;
background-image: $buttonDown; background-image: $buttonDown;
} }
} }
+25 -25
View File
File diff suppressed because one or more lines are too long
+8 -8
View File
@@ -1,10 +1,10 @@
import preview from './preview' import preview from "./preview";
import view from './view' import view from "./view";
import music from './music' import music from "./music";
export default { export default {
name: 'crystalsong-forest', name: "crystalsong-forest",
music, music,
view, view,
preview preview,
} };
+9 -9
View File
@@ -1,11 +1,11 @@
import CrystalsongForest1 from './crystalsong-forest-music-1.ogg' import CrystalsongForest1 from "./crystalsong-forest-music-1.ogg";
import CrystalsongForest2 from './crystalsong-forest-music-2.ogg' import CrystalsongForest2 from "./crystalsong-forest-music-2.ogg";
import CrystalsongForest3 from './crystalsong-forest-music-3.ogg' import CrystalsongForest3 from "./crystalsong-forest-music-3.ogg";
import CrystalsongForest4 from './crystalsong-forest-music-4.ogg' import CrystalsongForest4 from "./crystalsong-forest-music-4.ogg";
export default [ export default [
CrystalsongForest1, CrystalsongForest1,
CrystalsongForest2, CrystalsongForest2,
CrystalsongForest3, CrystalsongForest3,
CrystalsongForest4 CrystalsongForest4,
] ];
+11 -11
View File
@@ -1,13 +1,13 @@
import CrystalsongForest1 from './crystalsong-forest-1.jpg' import CrystalsongForest1 from "./crystalsong-forest-1.jpg";
import CrystalsongForest2 from './crystalsong-forest-2.jpg' import CrystalsongForest2 from "./crystalsong-forest-2.jpg";
import CrystalsongForest3 from './crystalsong-forest-3.jpg' import CrystalsongForest3 from "./crystalsong-forest-3.jpg";
import CrystalsongForest4 from './crystalsong-forest-4.jpg' import CrystalsongForest4 from "./crystalsong-forest-4.jpg";
import CrystalsongForest5 from './crystalsong-forest-5.jpg' import CrystalsongForest5 from "./crystalsong-forest-5.jpg";
export default [ export default [
CrystalsongForest1, CrystalsongForest1,
CrystalsongForest2, CrystalsongForest2,
CrystalsongForest3, CrystalsongForest3,
CrystalsongForest4, CrystalsongForest4,
CrystalsongForest5 CrystalsongForest5,
] ];
+11 -11
View File
@@ -1,13 +1,13 @@
import CrystalsongForest1 from './crystalsong-forest-1.jpg' import CrystalsongForest1 from "./crystalsong-forest-1.jpg";
import CrystalsongForest2 from './crystalsong-forest-2.jpg' import CrystalsongForest2 from "./crystalsong-forest-2.jpg";
import CrystalsongForest3 from './crystalsong-forest-3.jpg' import CrystalsongForest3 from "./crystalsong-forest-3.jpg";
import CrystalsongForest4 from './crystalsong-forest-4.jpg' import CrystalsongForest4 from "./crystalsong-forest-4.jpg";
import CrystalsongForest5 from './crystalsong-forest-5.jpg' import CrystalsongForest5 from "./crystalsong-forest-5.jpg";
export default [ export default [
CrystalsongForest1, CrystalsongForest1,
CrystalsongForest2, CrystalsongForest2,
CrystalsongForest3, CrystalsongForest3,
CrystalsongForest4, CrystalsongForest4,
CrystalsongForest5 CrystalsongForest5,
] ];
+8 -8
View File
@@ -1,10 +1,10 @@
import preview from './preview' import preview from "./preview";
import view from './view' import view from "./view";
import music from './music' import music from "./music";
export default { export default {
name: 'dalaran', name: "dalaran",
music, music,
view, view,
preview preview,
} };
+11 -11
View File
@@ -1,13 +1,13 @@
import DalaranMusic1 from './dalaran-music-1.ogg' import DalaranMusic1 from "./dalaran-music-1.ogg";
import DalaranMusic2 from './dalaran-music-2.ogg' import DalaranMusic2 from "./dalaran-music-2.ogg";
import DalaranMusic3 from './dalaran-music-3.ogg' import DalaranMusic3 from "./dalaran-music-3.ogg";
import DalaranMusic4 from './dalaran-music-4.ogg' import DalaranMusic4 from "./dalaran-music-4.ogg";
import DalaranMusic5 from './dalaran-music-5.ogg' import DalaranMusic5 from "./dalaran-music-5.ogg";
export default [ export default [
DalaranMusic1, DalaranMusic1,
DalaranMusic2, DalaranMusic2,
DalaranMusic3, DalaranMusic3,
DalaranMusic4, DalaranMusic4,
DalaranMusic5 DalaranMusic5,
] ];
+6 -12
View File
@@ -1,13 +1,7 @@
import Dalaran1 from './dalaran-1.jpg' import Dalaran1 from "./dalaran-1.jpg";
import Dalaran2 from './dalaran-2.jpg' import Dalaran2 from "./dalaran-2.jpg";
import Dalaran3 from './dalaran-3.jpg' import Dalaran3 from "./dalaran-3.jpg";
import Dalaran4 from './dalaran-4.jpg' import Dalaran4 from "./dalaran-4.jpg";
import Dalaran5 from './dalaran-5.jpg' import Dalaran5 from "./dalaran-5.jpg";
export default [ export default [Dalaran1, Dalaran2, Dalaran3, Dalaran4, Dalaran5];
Dalaran1,
Dalaran2,
Dalaran3,
Dalaran4,
Dalaran5
]
+6 -12
View File
@@ -1,13 +1,7 @@
import Dalaran1 from './dalaran-1.jpg' import Dalaran1 from "./dalaran-1.jpg";
import Dalaran2 from './dalaran-2.jpg' import Dalaran2 from "./dalaran-2.jpg";
import Dalaran3 from './dalaran-3.jpg' import Dalaran3 from "./dalaran-3.jpg";
import Dalaran4 from './dalaran-4.jpg' import Dalaran4 from "./dalaran-4.jpg";
import Dalaran5 from './dalaran-5.jpg' import Dalaran5 from "./dalaran-5.jpg";
export default [ export default [Dalaran1, Dalaran2, Dalaran3, Dalaran4, Dalaran5];
Dalaran1,
Dalaran2,
Dalaran3,
Dalaran4,
Dalaran5
]
+8 -8
View File
@@ -1,10 +1,10 @@
import preview from './preview' import preview from "./preview";
import view from './view' import view from "./view";
import music from './music' import music from "./music";
export default { export default {
name: 'halls-of-valor', name: "halls-of-valor",
music, music,
view, view,
preview preview,
} };
+2 -4
View File
@@ -1,5 +1,3 @@
import HallsOfValorMusic1 from './halls-of-valor-music-1.mp3' import HallsOfValorMusic1 from "./halls-of-valor-music-1.mp3";
export default [ export default [HallsOfValorMusic1];
HallsOfValorMusic1
]
+5 -10
View File
@@ -1,11 +1,6 @@
import HallsOfValor1 from './halls-of-valor-1.jpg' import HallsOfValor1 from "./halls-of-valor-1.jpg";
import HallsOfValor2 from './halls-of-valor-2.jpg' import HallsOfValor2 from "./halls-of-valor-2.jpg";
import HallsOfValor3 from './halls-of-valor-3.jpg' import HallsOfValor3 from "./halls-of-valor-3.jpg";
import HallsOfValor4 from './halls-of-valor-4.jpg' import HallsOfValor4 from "./halls-of-valor-4.jpg";
export default [ export default [HallsOfValor1, HallsOfValor2, HallsOfValor3, HallsOfValor4];
HallsOfValor1,
HallsOfValor2,
HallsOfValor3,
HallsOfValor4
]
+5 -10
View File
@@ -1,11 +1,6 @@
import HallsOfValor1 from './halls-of-valor-1.jpg' import HallsOfValor1 from "./halls-of-valor-1.jpg";
import HallsOfValor2 from './halls-of-valor-2.jpg' import HallsOfValor2 from "./halls-of-valor-2.jpg";
import HallsOfValor3 from './halls-of-valor-3.jpg' import HallsOfValor3 from "./halls-of-valor-3.jpg";
import HallsOfValor4 from './halls-of-valor-4.jpg' import HallsOfValor4 from "./halls-of-valor-4.jpg";
export default [ export default [HallsOfValor1, HallsOfValor2, HallsOfValor3, HallsOfValor4];
HallsOfValor1,
HallsOfValor2,
HallsOfValor3,
HallsOfValor4
]
+17 -15
View File
File diff suppressed because one or more lines are too long
+8 -8
View File
@@ -1,10 +1,10 @@
import preview from './preview' import preview from "./preview";
import view from './view' import view from "./view";
import music from './music' import music from "./music";
export default { export default {
name: 'nagrand', name: "nagrand",
music, music,
view, view,
preview preview,
} };
+5 -10
View File
@@ -1,11 +1,6 @@
import NagrandMusic1 from './nagrand-music-1.ogg' import NagrandMusic1 from "./nagrand-music-1.ogg";
import NagrandMusic2 from './nagrand-music-2.ogg' import NagrandMusic2 from "./nagrand-music-2.ogg";
import NagrandMusic3 from './nagrand-music-3.ogg' import NagrandMusic3 from "./nagrand-music-3.ogg";
import NagrandMusic4 from './nagrand-music-4.ogg' import NagrandMusic4 from "./nagrand-music-4.ogg";
export default [ export default [NagrandMusic1, NagrandMusic2, NagrandMusic3, NagrandMusic4];
NagrandMusic1,
NagrandMusic2,
NagrandMusic3,
NagrandMusic4
]
+6 -12
View File
@@ -1,13 +1,7 @@
import Nagrand1 from './nagrand-1.jpg' import Nagrand1 from "./nagrand-1.jpg";
import Nagrand2 from './nagrand-2.jpg' import Nagrand2 from "./nagrand-2.jpg";
import Nagrand3 from './nagrand-3.jpg' import Nagrand3 from "./nagrand-3.jpg";
import Nagrand4 from './nagrand-4.jpg' import Nagrand4 from "./nagrand-4.jpg";
import Nagrand5 from './nagrand-5.jpg' import Nagrand5 from "./nagrand-5.jpg";
export default [ export default [Nagrand1, Nagrand2, Nagrand3, Nagrand4, Nagrand5];
Nagrand1,
Nagrand2,
Nagrand3,
Nagrand4,
Nagrand5
]
+6 -12
View File
@@ -1,13 +1,7 @@
import Nagrand1 from './nagrand-1.jpg' import Nagrand1 from "./nagrand-1.jpg";
import Nagrand2 from './nagrand-2.jpg' import Nagrand2 from "./nagrand-2.jpg";
import Nagrand3 from './nagrand-3.jpg' import Nagrand3 from "./nagrand-3.jpg";
import Nagrand4 from './nagrand-4.jpg' import Nagrand4 from "./nagrand-4.jpg";
import Nagrand5 from './nagrand-5.jpg' import Nagrand5 from "./nagrand-5.jpg";
export default [ export default [Nagrand1, Nagrand2, Nagrand3, Nagrand4, Nagrand5];
Nagrand1,
Nagrand2,
Nagrand3,
Nagrand4,
Nagrand5
]
+8 -8
View File
@@ -1,10 +1,10 @@
import preview from './preview' import preview from "./preview";
import view from './view' import view from "./view";
import music from './music' import music from "./music";
export default { export default {
name: 'pandaria', name: "pandaria",
music, music,
view, view,
preview preview,
} };
+5 -10
View File
@@ -1,11 +1,6 @@
import Pandaria1 from './pandaria-music-1.mp3' import Pandaria1 from "./pandaria-music-1.mp3";
import Pandaria2 from './pandaria-music-2.mp3' import Pandaria2 from "./pandaria-music-2.mp3";
import Pandaria3 from './pandaria-music-3.mp3' import Pandaria3 from "./pandaria-music-3.mp3";
import Pandaria4 from './pandaria-music-4.mp3' import Pandaria4 from "./pandaria-music-4.mp3";
export default [ export default [Pandaria1, Pandaria2, Pandaria3, Pandaria4];
Pandaria1,
Pandaria2,
Pandaria3,
Pandaria4
]
+13 -13
View File
@@ -1,15 +1,15 @@
import Pandaria1 from './pandaria-1.jpg' import Pandaria1 from "./pandaria-1.jpg";
import Pandaria2 from './pandaria-2.jpg' import Pandaria2 from "./pandaria-2.jpg";
import Pandaria3 from './pandaria-3.jpg' import Pandaria3 from "./pandaria-3.jpg";
import Pandaria4 from './pandaria-4.jpg' import Pandaria4 from "./pandaria-4.jpg";
import Pandaria5 from './pandaria-5.jpg' import Pandaria5 from "./pandaria-5.jpg";
import Pandaria6 from './pandaria-6.jpg' import Pandaria6 from "./pandaria-6.jpg";
export default [ export default [
Pandaria1, Pandaria1,
Pandaria2, Pandaria2,
Pandaria3, Pandaria3,
Pandaria4, Pandaria4,
Pandaria5, Pandaria5,
Pandaria6 Pandaria6,
] ];
+13 -13
View File
@@ -1,15 +1,15 @@
import Pandaria1 from './pandaria-1.jpg' import Pandaria1 from "./pandaria-1.jpg";
import Pandaria2 from './pandaria-2.jpg' import Pandaria2 from "./pandaria-2.jpg";
import Pandaria3 from './pandaria-3.jpg' import Pandaria3 from "./pandaria-3.jpg";
import Pandaria4 from './pandaria-4.jpg' import Pandaria4 from "./pandaria-4.jpg";
import Pandaria5 from './pandaria-5.jpg' import Pandaria5 from "./pandaria-5.jpg";
import Pandaria6 from './pandaria-6.jpg' import Pandaria6 from "./pandaria-6.jpg";
export default [ export default [
Pandaria1, Pandaria1,
Pandaria2, Pandaria2,
Pandaria3, Pandaria3,
Pandaria4, Pandaria4,
Pandaria5, Pandaria5,
Pandaria6 Pandaria6,
] ];
+8 -8
View File
@@ -1,10 +1,10 @@
import preview from './preview' import preview from "./preview";
import view from './view' import view from "./view";
import music from './music' import music from "./music";
export default { export default {
name: 'stormwind-park', name: "stormwind-park",
music, music,
view, view,
preview preview,
} };
+3 -6
View File
@@ -1,7 +1,4 @@
import StormwindMusic1 from './stormwind-park-music-1.mp3' import StormwindMusic1 from "./stormwind-park-music-1.mp3";
import StormwindMusic2 from './stormwind-park-music-2.mp3' import StormwindMusic2 from "./stormwind-park-music-2.mp3";
export default [ export default [StormwindMusic1, StormwindMusic2];
StormwindMusic1,
StormwindMusic2
]
+19 -19
View File
@@ -1,21 +1,21 @@
import StormwindPark1 from './stormwind-park-1.jpg' import StormwindPark1 from "./stormwind-park-1.jpg";
import StormwindPark2 from './stormwind-park-2.jpg' import StormwindPark2 from "./stormwind-park-2.jpg";
import StormwindPark3 from './stormwind-park-3.jpg' import StormwindPark3 from "./stormwind-park-3.jpg";
import StormwindPark4 from './stormwind-park-4.jpg' import StormwindPark4 from "./stormwind-park-4.jpg";
import StormwindPark5 from './stormwind-park-5.jpg' import StormwindPark5 from "./stormwind-park-5.jpg";
import StormwindPark6 from './stormwind-park-6.jpg' import StormwindPark6 from "./stormwind-park-6.jpg";
import StormwindPark7 from './stormwind-park-7.jpg' import StormwindPark7 from "./stormwind-park-7.jpg";
import StormwindPark8 from './stormwind-park-8.jpg' import StormwindPark8 from "./stormwind-park-8.jpg";
import StormwindPark9 from './stormwind-park-9.jpg' import StormwindPark9 from "./stormwind-park-9.jpg";
export default [ export default [
StormwindPark1, StormwindPark1,
StormwindPark2, StormwindPark2,
StormwindPark3, StormwindPark3,
StormwindPark4, StormwindPark4,
StormwindPark5, StormwindPark5,
StormwindPark6, StormwindPark6,
StormwindPark7, StormwindPark7,
StormwindPark8, StormwindPark8,
StormwindPark9 StormwindPark9,
] ];
+19 -19
View File
@@ -1,21 +1,21 @@
import StormwindPark1 from './stormwind-park-1.jpg' import StormwindPark1 from "./stormwind-park-1.jpg";
import StormwindPark2 from './stormwind-park-2.jpg' import StormwindPark2 from "./stormwind-park-2.jpg";
import StormwindPark3 from './stormwind-park-3.jpg' import StormwindPark3 from "./stormwind-park-3.jpg";
import StormwindPark4 from './stormwind-park-4.jpg' import StormwindPark4 from "./stormwind-park-4.jpg";
import StormwindPark5 from './stormwind-park-5.jpg' import StormwindPark5 from "./stormwind-park-5.jpg";
import StormwindPark6 from './stormwind-park-6.jpg' import StormwindPark6 from "./stormwind-park-6.jpg";
import StormwindPark7 from './stormwind-park-7.jpg' import StormwindPark7 from "./stormwind-park-7.jpg";
import StormwindPark8 from './stormwind-park-8.jpg' import StormwindPark8 from "./stormwind-park-8.jpg";
import StormwindPark9 from './stormwind-park-9.jpg' import StormwindPark9 from "./stormwind-park-9.jpg";
export default [ export default [
StormwindPark1, StormwindPark1,
StormwindPark2, StormwindPark2,
StormwindPark3, StormwindPark3,
StormwindPark4, StormwindPark4,
StormwindPark5, StormwindPark5,
StormwindPark6, StormwindPark6,
StormwindPark7, StormwindPark7,
StormwindPark8, StormwindPark8,
StormwindPark9 StormwindPark9,
] ];
@@ -4,22 +4,22 @@ $borderWidth: 12px;
$borderOutset: 8px; $borderOutset: 8px;
.header { .header {
font-family: $font; display: flex;
font-size: $fontSize; flex-direction: column;
text-shadow: $fontShadow; align-items: center;
letter-spacing: $fontSpacing; justify-content: center;
color: $fontColor; width: 100%;
height: 100%; height: 100%;
width: 100%; padding-bottom: 2px;
display: flex; color: $fontColor;
flex-direction: column; font-size: $fontSize;
justify-content: center; font-family: $font;
align-items: center; letter-spacing: $fontSpacing;
padding-bottom: 2px; text-shadow: $fontShadow;
border: $borderWidth double $fontColor; background-image: $backgroundTexture;
border-image: $border 15 15 15 15 fill; background-repeat: repeat;
border-image-outset: $borderOutset; border: $borderWidth double $fontColor;
border-image-repeat: stretch stretch; border-image: $border 15 15 15 15 fill;
background-image: $backgroundTexture; border-image-outset: $borderOutset;
background-repeat: repeat; border-image-repeat: stretch stretch;
} }
@@ -1,15 +1,13 @@
import * as React from 'react' import * as React from "react";
import './bordered-header.scss' import "./bordered-header.scss";
interface Props { interface Props {
children: React.ReactNode children: React.ReactNode;
} }
export const BorderedHeader = ({children}: Props) => ( export const BorderedHeader: React.FC<Props> = ({ children }: Props) => (
<div className='header'> <div className="header">{children}</div>
{children} );
</div>
)
BorderedHeader.displayName = 'BorderedHeader' BorderedHeader.displayName = "BorderedHeader";
@@ -1,17 +1,17 @@
@import "../../app/style"; @import "../../app/style";
.checkbox { .checkbox {
width: 32px; width: 32px;
height: 32px; height: 32px;
border-radius: 8px; background-image: $checkbox;
background-image: $checkbox; border-radius: 8px;
&:focus { &:focus {
outline: none; outline: none;
box-shadow: inset $hoverBox; box-shadow: inset $hoverBox;
} }
&--checked { &--checked {
background-image: $checkboxCheck, $checkbox; background-image: $checkboxCheck, $checkbox;
} }
} }
@@ -1,32 +1,40 @@
import * as React from 'react' import * as React from "react";
import { KeyboardEvent, useCallback } from 'react' import { KeyboardEvent, useCallback } from "react";
import cn from 'classnames' import cn from "classnames";
import './checkbox-component.scss' import { Settings } from "../../settings-context";
import "./checkbox-component.scss";
interface Props { interface Props {
handleClick: (option: any) => void handleClick: (option: keyof Settings) => void;
optionName: any optionName: keyof Settings;
value: boolean value: boolean;
} }
export const CheckBoxComponent = ({handleClick, optionName, value}: Props) => { export const CheckBoxComponent: React.FC<Props> = ({
handleClick,
optionName,
value,
}: Props) => {
const handleKeyDown = useCallback(
(e: KeyboardEvent, option: keyof Settings) => {
if (e.keyCode !== 13 && e.keyCode !== 32) {
return;
}
handleClick(option);
},
[handleClick]
);
const handleKeyDown = useCallback((e: KeyboardEvent, option: any) => { return (
if (e.keyCode !== 13 && e.keyCode !== 32) { <div
return tabIndex={0}
} onClick={() => handleClick(optionName)}
handleClick(option) onKeyDown={(e) => handleKeyDown(e, optionName)}
}, [handleClick]) className={cn("checkbox", { "checkbox--checked": value })}
/>
);
};
return ( CheckBoxComponent.displayName = "CheckBoxComponent";
<div
tabIndex={0}
onClick={() => handleClick(optionName)}
onKeyDown={(e) => handleKeyDown(e, optionName)}
className={cn('checkbox', {'checkbox--checked': value})}
/>
)
}
CheckBoxComponent.displayName = 'CheckBoxComponent'
+11 -11
View File
@@ -1,11 +1,11 @@
export { ViewComponent } from './view-component/view-component' export { ViewComponent } from "./view-component/view-component";
export { SelectComponent } from './select-component/select-component' export { SelectComponent } from "./select-component/select-component";
export { PanelComponent } from './panel-component/panel-component' export { PanelComponent } from "./panel-component/panel-component";
export { PreviewComponent } from './preview-component/preview-component' export { PreviewComponent } from "./preview-component/preview-component";
export { RangeComponent } from './range-component/range-component' export { RangeComponent } from "./range-component/range-component";
export { SettingsComponent } from './settings-component/settings-component' export { SettingsComponent } from "./settings-component/settings-component";
export { CheckBoxComponent } from './checkbox-component/checkbox-component' export { CheckBoxComponent } from "./checkbox-component/checkbox-component";
export { BorderedHeader } from './bordered-header/bordered-header' export { BorderedHeader } from "./bordered-header/bordered-header";
export { MusicComponent } from './music-component/music-component' export { MusicComponent } from "./music-component/music-component";
export { MainMenuComponent } from './main-menu-component/main-menu-component' export { MainMenuComponent } from "./main-menu-component/main-menu-component";
export { MenuItemComponent } from './menu-item-component/menu-item-component' export { MenuItemComponent } from "./menu-item-component/menu-item-component";
@@ -4,25 +4,25 @@ $menuHeight: 42px;
$menuWidth: 290px; $menuWidth: 290px;
.main-menu { .main-menu {
position: absolute; position: absolute;
right: 0; top: 0;
top: 0; right: 0;
z-index: 3; z-index: 3;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
border: 1px double $fontColor; padding: 2px 3px;
border-image: $rangeBorder 5 5 5 5; background: $panelBackground center repeat;
background: $panelBackground center repeat; border: 1px double $fontColor;
border-image-width: 5px; border-radius: 6px;
border-image-repeat: round round; border-image: $rangeBorder 5 5 5 5;
border-radius: 6px; border-image-width: 5px;
padding: 2px 3px; border-image-repeat: round round;
&:hover { &:hover {
.author { .author {
width: 130px; width: 130px;
opacity: 1; opacity: 1;
}
} }
}
} }
@@ -1,17 +1,13 @@
import * as React from 'react' import * as React from "react";
import './main-menu-component.scss' import "./main-menu-component.scss";
interface Props { interface Props {
children: React.ReactNode children: React.ReactNode;
} }
export const MainMenuComponent = ({children}: Props) => { export const MainMenuComponent: React.FC<Props> = ({ children }: Props) => {
return ( return <div className="main-menu">{children}</div>;
<div className='main-menu'> };
{children}
</div>
)
}
MainMenuComponent.displayName = 'MainMenuComponent' MainMenuComponent.displayName = "MainMenuComponent";
@@ -1,32 +1,32 @@
@import '../../app/style'; @import "../../app/style";
$menuItemWidth: 32px; $menuItemWidth: 32px;
$menuItemHeight: 41px; $menuItemHeight: 41px;
.menu-item { .menu-item {
z-index: 4; z-index: 4;
width: $menuItemWidth - 4px; width: $menuItemWidth - 4px;
height: $menuItemHeight - 4px; height: $menuItemHeight - 4px;
border-radius: 6px; background-image: $helpButton;
background-image: $helpButton; background-repeat: no-repeat;
background-position: center; background-position: center;
background-repeat: no-repeat; background-size: $menuItemWidth $menuItemHeight;
background-size: $menuItemWidth $menuItemHeight; border-radius: 6px;
&--active { &--active {
background-image: $helpButtonClick; background-image: $helpButtonClick;
} }
&:hover { &:hover {
box-shadow: $hoverBox; box-shadow: $hoverBox;
} }
&:focus { &:focus {
outline: none; outline: none;
box-shadow: $hoverBox; box-shadow: $hoverBox;
} }
&:active { &:active {
background-image: $helpButtonClick; background-image: $helpButtonClick;
} }
} }
@@ -1,31 +1,36 @@
import * as React from 'react' import * as React from "react";
import { KeyboardEvent, useCallback } from 'react' import { KeyboardEvent, useCallback } from "react";
import cn from 'classnames' import cn from "classnames";
import './menu-item-component.scss' import "./menu-item-component.scss";
interface Props { interface Props {
isActive: boolean isActive: boolean;
handleClick: () => void handleClick: () => void;
} }
export const MenuItemComponent = ({isActive, handleClick}: Props) => { export const MenuItemComponent: React.FC<Props> = ({
isActive,
handleClick,
}: Props) => {
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (e.keyCode !== 13 && e.keyCode !== 32) {
return;
}
handleClick();
},
[handleClick]
);
const handleKeyDown = useCallback((e: KeyboardEvent) => { return (
if (e.keyCode !== 13 && e.keyCode !== 32) { <div
return tabIndex={0}
} onClick={handleClick}
handleClick() onKeyDown={handleKeyDown}
}, [handleClick]) className={cn("menu-item", { "menu-item--active": isActive })}
/>
);
};
return ( MenuItemComponent.displayName = "MainMenuComponent";
<div
tabIndex={0}
onClick={handleClick}
onKeyDown={handleKeyDown}
className={cn('menu-item', {'menu-item--active': isActive})}
/>
)
}
MenuItemComponent.displayName = 'MainMenuComponent'
@@ -1,42 +1,49 @@
import { useEffect, useMemo } from 'react' import * as React from "react";
import { randomNumber, soundLoad, UI_MUSIC_VOLUME } from '../../utils' import { useEffect, useMemo } from "react";
import Sound from '../../modules/sound' import { randomNumber, soundLoad, UI_MUSIC_VOLUME } from "../../utils";
import Sound from "../../modules/sound";
interface Props { interface Props {
music: string[] music: string[];
setPlaying: (value: boolean) => void setPlaying: (value: boolean) => void;
setCurrentPlaying: (value: Sound | undefined) => void setCurrentPlaying: (value: Sound | undefined) => void;
} }
export const MusicComponent = ({ music, setPlaying, setCurrentPlaying }: Props) => { /* eslint-disable no-param-reassign */
const musicArray = useMemo(() => ( export const MusicComponent: React.FC<Props> = ({
music.map(sound => soundLoad(sound, UI_MUSIC_VOLUME)) music,
), [music]) setPlaying,
setCurrentPlaying,
}: Props) => {
const musicArray = useMemo(
() => music.map((sound) => soundLoad(sound, UI_MUSIC_VOLUME)),
[music]
);
useEffect(() => { useEffect(() => {
musicArray.forEach(sound => { musicArray.forEach((sound) => {
sound.audio.onplay = () => { sound.audio.onplay = () => {
setPlaying(true) setPlaying(true);
setCurrentPlaying(sound) setCurrentPlaying(sound);
} };
sound.audio.onended = () => { sound.audio.onended = () => {
musicArray[randomNumber(0, musicArray.length)].playMusic() musicArray[randomNumber(0, musicArray.length)].playMusic();
} };
}) });
setCurrentPlaying(musicArray[randomNumber(0, musicArray.length)]) setCurrentPlaying(musicArray[randomNumber(0, musicArray.length)]);
return () => { return () => {
musicArray.forEach(({ audio }) => { musicArray.forEach(({ audio }) => {
audio.onplay = null audio.onplay = null;
audio.onended = null audio.onended = null;
audio.pause() audio.pause();
audio.currentTime = 0 audio.currentTime = 0;
}) });
setCurrentPlaying(undefined) setCurrentPlaying(undefined);
} };
}, [musicArray, setPlaying, setCurrentPlaying]) }, [musicArray, setPlaying, setCurrentPlaying]);
return null return null;
} };
MusicComponent.displayName = 'MusicComponent' MusicComponent.displayName = "MusicComponent";
@@ -5,73 +5,73 @@ $panelHeight: $previewHeight + 40px;
$panelBorderSize: 8px; $panelBorderSize: 8px;
.panel { .panel {
z-index: 2;
padding: 20px;
border: none;
position: absolute;
height: $panelHeight;
width: $panelWidth;
background-image: $panelBackground;
background-repeat: repeat;
&-content {
display: flex;
justify-content: flex-start;
align-items: center;
}
button {
z-index: 3;
position: absolute; position: absolute;
} z-index: 2;
width: $panelWidth;
height: $panelHeight;
padding: 20px;
background-image: $panelBackground;
background-repeat: repeat;
border: none;
&--bottom { &-content {
bottom: -$panelHeight + $panelBorderSize; display: flex;
width: 100%; align-items: center;
transition: bottom $transitionDuration $transitionType; justify-content: flex-start;
border-top: $panelBorderSize double $fontColor;
border-image: $borderTop 16 32 16 32;
border-image-outset: $panelBorderSize - 2px 0 0 0;
border-image-width: $panelBorderSize * 2 0 0 100%;
border-image-repeat: round round;
.panel-content {
height: 100%;
} }
button { button {
left: 50%; position: absolute;
transform: translateX(-50%); z-index: 3;
top: -$buttonHeight - 5px;
} }
&--shown { &--bottom {
bottom: 0; bottom: -$panelHeight + $panelBorderSize;
} width: 100%;
} border-top: $panelBorderSize double $fontColor;
border-image: $borderTop 16 32 16 32;
border-image-width: $panelBorderSize * 2 0 0 100%;
border-image-outset: $panelBorderSize - 2px 0 0 0;
border-image-repeat: round round;
transition: bottom $transitionDuration $transitionType;
&--left { .panel-content {
left: -$panelWidth + $panelBorderSize; height: 100%;
height: 100%; }
border-right: $panelBorderSize double $fontColor;
border-image: $borderRight 32 16 0 0;
border-image-outset: 0 $panelBorderSize - 2px 0 0;
border-image-width: 100% $panelBorderSize*2 0 0;
transition: left $transitionDuration $transitionType;
.panel-content { button {
flex-direction: column; top: -$buttonHeight - 5px;
width: 100%; left: 50%;
transform: translateX(-50%);
}
&--shown {
bottom: 0;
}
} }
button { &--left {
top: 50%; left: -$panelWidth + $panelBorderSize;
transform: translateY(-50%) rotate(90deg); height: 100%;
right: -80px; border-right: $panelBorderSize double $fontColor;
} border-image: $borderRight 32 16 0 0;
border-image-width: 100% $panelBorderSize*2 0 0;
border-image-outset: 0 $panelBorderSize - 2px 0 0;
transition: left $transitionDuration $transitionType;
&--shown { .panel-content {
left: 0; flex-direction: column;
width: 100%;
}
button {
top: 50%;
right: -80px;
transform: translateY(-50%) rotate(90deg);
}
&--shown {
left: 0;
}
} }
}
} }
+210 -195
View File
@@ -1,217 +1,232 @@
import * as React from 'react' import * as React from "react";
import { import {
FocusEvent, FocusEvent,
MouseEvent, MouseEvent,
TouchEvent, TouchEvent,
useCallback, useCallback,
useEffect, useEffect,
useMemo, useMemo,
useRef, useRef,
useState, useState,
WheelEvent WheelEvent,
} from 'react' } from "react";
import cn from 'classnames' import cn from "classnames";
import { ANIMATION_DURATION, debounce, PREVIEW_HEIGHT, PREVIEW_WIDTH, SPACE } from '../../utils' import {
import { useSettings } from '../../hooks' ANIMATION_DURATION,
debounce,
PREVIEW_HEIGHT,
PREVIEW_WIDTH,
SPACE,
} from "../../utils";
import { useSettings } from "../../hooks";
import './panel-component.scss' import "./panel-component.scss";
interface Props { interface Props {
orientation: 'bottom' | 'left' orientation: "bottom" | "left";
isShown: boolean isShown: boolean;
itemsCount: number itemsCount: number;
setShown: () => void setShown: () => void;
openSoundPlay: (volume?: number) => void openSoundPlay: (volume?: number) => void;
closeSoundPlay: (volume?: number) => void closeSoundPlay: (volume?: number) => void;
children: React.ReactNode children: React.ReactNode;
} }
export const PanelComponent = ({ export const PanelComponent: React.FC<Props> = ({
isShown, isShown,
setShown, setShown,
children, children,
openSoundPlay, openSoundPlay,
closeSoundPlay, closeSoundPlay,
itemsCount, itemsCount,
orientation orientation,
}: Props) => { }: Props) => {
const {settings: {language, uiSound}} = useSettings() const {
const [isDrag, setDrag] = useState(false) settings: { language, uiSound },
const [trackPosition, setTrackPosition] = useState(0) } = useSettings();
const [position, setPosition] = useState(0) const [isDrag, setDrag] = useState(false);
const [lastPosition, setLastPosition] = useState(0) const [trackPosition, setTrackPosition] = useState(0);
const [position, setPosition] = useState(0);
const [lastPosition, setLastPosition] = useState(0);
const panel = useRef<HTMLInputElement>(null) const panel = useRef<HTMLInputElement>(null);
const isBottom = useMemo(() => orientation === 'bottom', [orientation]) const isBottom = useMemo(() => orientation === "bottom", [orientation]);
const handleClick = (event: MouseEvent) => { const windowOverflow = () => {
event.preventDefault() const { innerWidth, innerHeight } = window;
setShown() const windowSize = isBottom ? innerWidth : innerHeight;
if (!uiSound) { const containerSize =
return itemsCount * ((isBottom ? PREVIEW_WIDTH : PREVIEW_HEIGHT) + 15);
} if (!(containerSize > windowSize)) {
if (isShown) { return 0;
openSoundPlay() }
} else { return Math.abs(containerSize - windowSize);
closeSoundPlay() };
const changePosition = () => {
if (!panel.current) {
return;
}
panel.current.style.transform = `translate${
isBottom ? "X" : "Y"
}(${-position}px)`;
};
const limiter = (value: number, overflow: number, isWheel = false) => {
let diff = (!isWheel ? trackPosition : 0) - value + lastPosition;
if (Math.abs(diff) > overflow + SPACE) {
diff = overflow + SPACE;
} else if (diff < 0) {
diff = 0;
}
return diff;
};
const handleClick = (event: MouseEvent) => {
event.preventDefault();
setShown();
if (!uiSound) {
return;
}
if (isShown) {
openSoundPlay();
} else {
closeSoundPlay();
}
};
const resetPanel = useCallback(
(animate = true) => {
if (!panel.current) {
return;
}
if (animate) {
panel.current.style.transition = `transform 0.5s`;
}
panel.current.style.transform = `unset`;
setTrackPosition(0);
setPosition(0);
setLastPosition(0);
},
[panel]
);
useEffect(() => {
let timeout: NodeJS.Timeout;
const handleResize = debounce(() => {
resetPanel();
timeout = setTimeout(() => {
if (!panel || !panel.current) {
return;
} }
panel.current.style.transition = "unset";
}, ANIMATION_DURATION);
}, 100);
window.addEventListener("resize", handleResize);
return () => {
if (timeout) {
clearTimeout(timeout);
}
window.removeEventListener("resize", handleResize);
};
}, [panel, resetPanel]);
useEffect(() => {
if (!isShown) {
resetPanel(false);
}
}, [isShown, resetPanel]);
const handleMouseMove = (e: MouseEvent) => {
if (!isDrag) {
return;
}
const overflow = windowOverflow();
if (!overflow) {
return;
} }
const resetPanel = useCallback((animate = true) => { const { clientX, clientY } = e;
if (!panel.current) { const value = isBottom ? clientX : clientY;
return const diff = limiter(value, overflow);
} setPosition(diff);
if (animate) { changePosition();
panel.current.style.transition = `transform 0.5s` };
}
panel.current.style.transform = `unset`
setTrackPosition(0)
setPosition(0)
setLastPosition(0)
}, [panel])
useEffect(() => { const handleMouseDown = (e: MouseEvent) => {
let timeout: NodeJS.Timeout const { clientX, clientY } = e;
const handleResize = debounce(() => { e.nativeEvent.stopImmediatePropagation();
resetPanel() setTrackPosition(isBottom ? clientX : clientY);
timeout = setTimeout(() => { setDrag(true);
if (!panel || !panel.current) { };
return
}
panel.current.style.transition = 'unset'
}, ANIMATION_DURATION)
}, 100)
window.addEventListener('resize', handleResize)
return () => {
if (timeout) {
clearTimeout(timeout)
}
window.removeEventListener('resize', handleResize)
}
}, [panel, resetPanel])
useEffect(() => { const handleTouchstart = (e: TouchEvent) => {
if (!isShown) { const { touches } = e;
resetPanel(false) e.nativeEvent.stopImmediatePropagation();
} setTrackPosition(isBottom ? touches[0].clientX : touches[0].clientY);
}, [isShown, resetPanel]) setDrag(true);
};
const handleMouseMove = (e: MouseEvent) => { const handleTouchMove = (e: TouchEvent) => {
if (!isDrag) { const { touches } = e;
return const { clientX, clientY } = touches[0];
} const overflow = windowOverflow();
const overflow = windowOverflow() if (!overflow) {
if (!overflow) { return;
return
}
const {clientX, clientY} = e
const value = isBottom ? clientX : clientY
const diff = limiter(value, overflow)
setPosition(diff)
changePosition()
} }
const windowOverflow = () => { const value = isBottom ? clientX : clientY;
const {innerWidth, innerHeight} = window const diff = limiter(value, overflow);
const windowSize = isBottom ? innerWidth : innerHeight setPosition(diff);
const containerSize = itemsCount * ((isBottom ? PREVIEW_WIDTH : PREVIEW_HEIGHT) + 15) changePosition();
if (!(containerSize > windowSize)) { };
return 0
} const handleFree = (e: MouseEvent | FocusEvent | TouchEvent) => {
return Math.abs(containerSize - windowSize) e.nativeEvent.stopImmediatePropagation();
setDrag(false);
setLastPosition(position);
};
const handleScroll = (e: WheelEvent) => {
const { deltaY } = e;
const overflow = windowOverflow();
if (!overflow) {
return;
} }
const limiter = (value: number, overflow: number, isWheel: boolean = false) => { const value = deltaY > 0 ? -80 : 80;
let diff = (!isWheel ? trackPosition : 0) - value + lastPosition const diff = limiter(value, overflow, true);
if (Math.abs(diff) > overflow + SPACE) { setPosition(diff);
diff = overflow + SPACE changePosition();
} else if (diff < 0) { setLastPosition(position);
diff = 0 };
}
return diff
}
const changePosition = () => { return (
if (!panel.current) { <div
return onMouseDown={handleMouseDown}
} onTouchStart={handleTouchstart}
panel.current.style.transform = `translate${isBottom ? 'X' : 'Y'}(${-position}px)` onTouchMove={handleTouchMove}
} onTouchEnd={handleFree}
onMouseUp={handleFree}
onMouseMove={handleMouseMove}
onMouseLeave={handleFree}
onWheel={handleScroll}
onBlur={handleFree}
className={cn("panel", `panel--${orientation}`, {
[`panel--${orientation}--shown`]: isShown,
})}
>
<div ref={panel} className="panel-content">
{isShown && children}
</div>
<button onClick={handleClick}>
{orientation === "bottom"
? language["ui.button.views"]
: language["ui.button.places"]}
</button>
</div>
);
};
const handleMouseDown = (e: MouseEvent) => { PanelComponent.displayName = "PanelComponent";
const {clientX, clientY} = e
e.nativeEvent.stopImmediatePropagation()
setTrackPosition(isBottom ? clientX : clientY)
setDrag(true)
}
const handleTouchstart = (e: TouchEvent) => {
const {touches} = e
e.nativeEvent.stopImmediatePropagation()
setTrackPosition(isBottom ? touches[0].clientX : touches[0].clientY)
setDrag(true)
}
const handleTouchMove = (e: TouchEvent) => {
const {touches} = e
const {clientX, clientY} = touches[0]
const overflow = windowOverflow()
if (!overflow) {
return
}
const value = isBottom ? clientX : clientY
const diff = limiter(value, overflow)
setPosition(diff)
changePosition()
}
const handleFree = (e: MouseEvent | FocusEvent | TouchEvent) => {
e.nativeEvent.stopImmediatePropagation()
setDrag(false)
setLastPosition(position)
}
const handleScroll = (e: WheelEvent) => {
const {deltaY} = e
const overflow = windowOverflow()
if (!overflow) {
return
}
const value = deltaY > 0 ? -80 : 80
const diff = limiter(value, overflow, true)
setPosition(diff)
changePosition()
setLastPosition(position)
}
return (
<div
onMouseDown={handleMouseDown}
onTouchStart={handleTouchstart}
onTouchMove={handleTouchMove}
onTouchEnd={handleFree}
onMouseUp={handleFree}
onMouseMove={handleMouseMove}
onMouseLeave={handleFree}
onWheel={handleScroll}
onBlur={handleFree}
className={cn('panel', `panel--${orientation}`, {[`panel--${orientation}--shown`]: isShown})}
>
<div
ref={panel}
className='panel-content'
>
{isShown && children}
</div>
<button onClick={handleClick}>
{orientation === 'bottom' ? language['ui.button.views'] : language['ui.button.places']}
</button>
</div>
)
}
PanelComponent.displayName = 'PanelComponent'
@@ -7,46 +7,46 @@ $previewNameWidth: 250px;
$previewNameHeight: 25px; $previewNameHeight: 25px;
.preview { .preview {
z-index: 4; position: relative;
position: relative; z-index: 4;
cursor: $cursorInteract, auto; min-width: $previewWidth;
min-width: $previewWidth; min-height: $previewHeight;
min-height: $previewHeight; margin: 5px;
margin: 5px; background-repeat: no-repeat;
border: $previewBorderWidth double $fontColor; background-position: center;
border-image: $border 12 12 11 12; background-size: $previewWidth $previewHeight;
border-image-outset: $previewBorderWidth / 2; border: $previewBorderWidth double $fontColor;
border-image-repeat: stretch stretch; border-image: $border 12 12 11 12;
background-position: center; border-image-outset: $previewBorderWidth / 2;
background-size: $previewWidth $previewHeight; border-image-repeat: stretch stretch;
background-repeat: no-repeat; cursor: $cursorInteract, auto;
opacity: 1; opacity: 1;
transition: opacity $transitionDuration $transitionType; transition: opacity $transitionDuration $transitionType;
&-name { &-name {
position: absolute; position: absolute;
width: $previewNameWidth; bottom: -$previewNameHeight + 5px;
height: $previewNameHeight; left: 50%;
bottom: -$previewNameHeight + 5px; width: $previewNameWidth;
left: 50%; height: $previewNameHeight;
transform: translateX(-50%); transform: translateX(-50%);
}
&--not-loaded {
background-size: $plugSize;
}
&--loading {
opacity: 0.4;
}
&:hover {
box-shadow: $hoverBox;
.preview-name {
box-shadow: -4px 4px 4px 2px $hoverColor,
4px 0 4px 2px $hoverColor;
} }
}
}
&--not-loaded {
background-size: $plugSize;
}
&--loading {
opacity: .4;
}
&:hover {
box-shadow: $hoverBox;
.preview-name {
box-shadow:
-4px 4px 4px 2px $hoverColor,
4px 0 4px 2px $hoverColor;
}
}
}
@@ -1,66 +1,77 @@
import * as React from 'react' import * as React from "react";
import { useCallback, useEffect, useMemo, useState } from 'react' import { useCallback, useEffect, useMemo, useState } from "react";
import cn from 'classnames' import cn from "classnames";
import { useSettings } from '../../hooks' import { useSettings } from "../../hooks";
import { Plug } from '../../assets' import { Plug } from "../../assets";
import './preview-component.scss' import "./preview-component.scss";
import { BorderedHeader } from '..' import { BorderedHeader } from "..";
interface Props { interface Props {
name?: string name?: string;
isLoading: boolean isLoading: boolean;
src: string src: string;
value: number value: number;
handleChange: (value: number) => void handleChange: (value: number) => void;
} }
export const PreviewComponent = ({name = '', src, value, handleChange, isLoading}: Props) => { export const PreviewComponent: React.FC<Props> = ({
const {settings: {language}} = useSettings() name = "",
const [isLoaded, setLoaded] = useState(false) src,
const image = useMemo(() => { value,
setLoaded(false) handleChange,
const img = new Image() isLoading,
img.src = src }: Props) => {
return img const {
}, [src]) settings: { language },
} = useSettings();
const [isLoaded, setLoaded] = useState(false);
const image = useMemo(() => {
setLoaded(false);
const img = new Image();
img.src = src;
return img;
}, [src]);
useEffect(() => { useEffect(() => {
image.onload = () => { image.onload = () => {
setLoaded(true) setLoaded(true);
} };
return () => { return () => {
image.onload = null image.onload = null;
} };
}, [image]) }, [image]);
const handleClick = useCallback((e: React.MouseEvent) => { const handleClick = useCallback(
e.preventDefault() (e: React.MouseEvent) => {
handleChange(value) e.preventDefault();
}, [handleChange, value]) handleChange(value);
},
[handleChange, value]
);
return ( return (
<div <div
onContextMenu={handleClick} onContextMenu={handleClick}
onClick={handleClick} onClick={handleClick}
style={{ style={{
margin: `${name ? '10px 5px' : '5px'}`, margin: `${name ? "10px 5px" : "5px"}`,
backgroundImage: `url(${isLoaded ? image.src : Plug})` backgroundImage: `url(${isLoaded ? image.src : Plug})`,
}} }}
className={cn('preview', { className={cn("preview", {
'preview--not-loaded': !isLoaded, "preview--not-loaded": !isLoaded,
'preview--loading': isLoading "preview--loading": isLoading,
})} })}
> >
{name && ( {name && (
<div className='preview-name'> <div className="preview-name">
<BorderedHeader> <BorderedHeader>
{language[name as keyof typeof language]} {language[name as keyof typeof language]}
</BorderedHeader> </BorderedHeader>
</div> </div>
)} )}
</div> </div>
) );
} };
PreviewComponent.displayName = 'PreviewComponent' PreviewComponent.displayName = "PreviewComponent";
@@ -4,29 +4,29 @@ $rangeWidth: 90px;
$rangeHeight: 3px; $rangeHeight: 3px;
.range { .range {
position: relative; position: relative;
height: $rangeHeight; width: $rangeWidth;
width: $rangeWidth; height: $rangeHeight;
border: 3px double $fontColor; background: $rangeBackground center repeat;
border-image: $rangeBorder 5 5 5 5; border: 3px double $fontColor;
background: $rangeBackground center repeat; border-radius: 6px;
border-image-width: 4px; border-image: $rangeBorder 5 5 5 5;
border-image-outset: 2px 0; border-image-width: 4px;
border-image-repeat: round round; border-image-outset: 2px 0;
border-radius: 6px; border-image-repeat: round round;
&-stick { &-stick {
position: absolute; position: absolute;
width: 32px; top: 50%;
height: 32px; left: 0;
background-image: $range; width: 32px;
left: 0; height: 32px;
top: 50%; background-image: $range;
transform: translate(0, -50%); transform: translate(0, -50%);
} }
&:focus { &:focus {
outline: none; outline: none;
box-shadow: $hoverBox; box-shadow: $hoverBox;
} }
} }
+146 -124
View File
@@ -1,143 +1,165 @@
import * as React from 'react' import * as React from "react";
import { KeyboardEvent, useCallback, useEffect, useRef, useState, WheelEvent } from 'react' import {
KeyboardEvent,
useCallback,
useEffect,
useRef,
useState,
WheelEvent,
} from "react";
import './range-component.scss' import "./range-component.scss";
interface Props { interface Props {
handleChange: (value: number) => void handleChange: (value: number) => void;
defaultValue: number defaultValue: number;
} }
const MAX = 55 const MAX = 55;
export const RangeComponent = ({handleChange, defaultValue}: Props) => { export const RangeComponent: React.FC<Props> = ({
const [isPressed, setPressed] = useState(false) handleChange,
const [position, setPosition] = useState(defaultValue * MAX) defaultValue,
}: Props) => {
const [isPressed, setPressed] = useState(false);
const [position, setPosition] = useState(defaultValue * MAX);
const stick = useRef<HTMLDivElement>(null) const stick = useRef<HTMLDivElement>(null);
const handleFocus = useCallback(() => setPressed(true), []) const handleFocus = useCallback(() => setPressed(true), []);
const handleFree = useCallback(() => setPressed(false), []) const handleFree = useCallback(() => setPressed(false), []);
const handleKeyDown = (e: KeyboardEvent) => { const limiter = (value: number, width: number) => {
if (!stick || !stick.current || !stick.current.parentNode) { let diff = value;
return if (diff > width - 35) {
} diff = MAX;
const {width} = (stick.current.parentNode as HTMLDivElement).getBoundingClientRect() } else if (diff < 0) {
switch (e.keyCode) { diff = 0;
case 37: }
const minusValue = position - 5 return diff;
const minusDiff = limiter(minusValue, width) };
setPosition(minusDiff) const handleKeyDown = (e: KeyboardEvent) => {
handleChange(minusDiff / MAX) if (!stick || !stick.current || !stick.current.parentNode) {
break return;
case 39:
const plusValue = position + 5
const plusDiff = limiter(plusValue, width)
setPosition(plusDiff)
handleChange(plusDiff / MAX)
break
}
} }
const handlePoint = useCallback((e: React.MouseEvent | MouseEvent) => { const handleChangePosition = (value: number): void => {
if (!stick || !stick.current || !stick.current.parentNode) { setPosition(value);
return handleChange(value / MAX);
} };
const {width, left} = (stick.current.parentNode as HTMLDivElement).getBoundingClientRect()
const {clientX} = e
const value = clientX - left - 20
const diff = limiter(value, width)
setPosition(diff) const { width } = (stick.current
handleChange(diff / MAX) .parentNode as HTMLDivElement).getBoundingClientRect();
}, [stick, handleChange]) switch (e.keyCode) {
case 37:
const handleMouseMove = useCallback((e: MouseEvent) => { handleChangePosition(limiter(position - 5, width));
if (!isPressed) { break;
return case 39:
} handleChangePosition(limiter(position + 5, width));
handlePoint(e) break;
}, [isPressed, handlePoint]) default:
break;
const handleTouchMove = useCallback((e: TouchEvent) => {
if (!isPressed) {
return
}
const {touches} = e
const {clientX} = touches[0]
if (!stick || !stick.current || !stick.current.parentNode) {
return
}
const {width, left} = (stick.current.parentNode as HTMLDivElement).getBoundingClientRect()
const value = clientX - left - 20
const diff = limiter(value, width)
setPosition(diff)
handleChange(diff / MAX)
}, [isPressed, stick, handleChange])
const handleScroll = (e: WheelEvent) => {
if (!stick || !stick.current || !stick.current.parentNode) {
return
}
const range = stick.current.parentNode as HTMLDivElement
const {width} = range.getBoundingClientRect()
range.focus()
const {deltaY} = e
const value = position + (deltaY > 0 ? -5 : 5)
const diff = limiter(value, width)
setPosition(diff)
handleChange(diff / MAX)
} }
};
const limiter = (value: number, width: number) => { const handlePoint = useCallback(
let diff = value (e: React.MouseEvent | MouseEvent) => {
if (diff > width - 35) { if (!stick || !stick.current || !stick.current.parentNode) {
diff = MAX return;
} else if (diff < 0) { }
diff = 0 const { width, left } = (stick.current
} .parentNode as HTMLDivElement).getBoundingClientRect();
return diff const { clientX } = e;
const value = clientX - left - 20;
const diff = limiter(value, width);
setPosition(diff);
handleChange(diff / MAX);
},
[stick, handleChange]
);
const handleMouseMove = useCallback(
(e: MouseEvent) => {
if (!isPressed) {
return;
}
handlePoint(e);
},
[isPressed, handlePoint]
);
const handleTouchMove = useCallback(
(e: TouchEvent) => {
if (!isPressed) {
return;
}
const { touches } = e;
const { clientX } = touches[0];
if (!stick || !stick.current || !stick.current.parentNode) {
return;
}
const { width, left } = (stick.current
.parentNode as HTMLDivElement).getBoundingClientRect();
const value = clientX - left - 20;
const diff = limiter(value, width);
setPosition(diff);
handleChange(diff / MAX);
},
[isPressed, stick, handleChange]
);
const handleScroll = (e: WheelEvent) => {
if (!stick || !stick.current || !stick.current.parentNode) {
return;
} }
const range = stick.current.parentNode as HTMLDivElement;
const { width } = range.getBoundingClientRect();
range.focus();
const { deltaY } = e;
const value = position + (deltaY > 0 ? -5 : 5);
const diff = limiter(value, width);
useEffect(() => { setPosition(diff);
window.addEventListener('mousemove', handleMouseMove) handleChange(diff / MAX);
window.addEventListener('mouseup', handleFree) };
window.addEventListener('touchmove', handleTouchMove)
window.addEventListener('touchend', handleFree)
return () => {
window.removeEventListener('mousemove', handleMouseMove)
window.removeEventListener('mouseup', handleFree)
window.removeEventListener('touchmove', handleTouchMove)
window.removeEventListener('touchend', handleFree)
}
}, [handleMouseMove, handleTouchMove, handleFree])
return ( useEffect(() => {
<div window.addEventListener("mousemove", handleMouseMove);
tabIndex={0} window.addEventListener("mouseup", handleFree);
onKeyDown={handleKeyDown} window.addEventListener("touchmove", handleTouchMove);
onMouseDown={handleFocus} window.addEventListener("touchend", handleFree);
onClick={handlePoint} return () => {
onTouchStart={handleFocus} window.removeEventListener("mousemove", handleMouseMove);
onWheel={handleScroll} window.removeEventListener("mouseup", handleFree);
className='range' window.removeEventListener("touchmove", handleTouchMove);
> window.removeEventListener("touchend", handleFree);
<div };
ref={stick} }, [handleMouseMove, handleTouchMove, handleFree]);
style={{
left: `${position}px`
}}
className='range-stick'
/>
</div>
)
}
RangeComponent.displayName = 'RangeComponent' return (
<div
tabIndex={0}
onKeyDown={handleKeyDown}
onMouseDown={handleFocus}
onClick={handlePoint}
onTouchStart={handleFocus}
onWheel={handleScroll}
className="range"
>
<div
ref={stick}
style={{
left: `${position}px`,
}}
className="range-stick"
/>
</div>
);
};
RangeComponent.displayName = "RangeComponent";
@@ -10,119 +10,125 @@ $DropDownBorder: 10px;
$dropDownOutset: $DropDownBorder / 2; $dropDownOutset: $DropDownBorder / 2;
.select { .select {
color: $fontColorWhite; position: relative;
display: flex;
position: relative;
padding-left: 6px;
justify-content: space-between;
border-radius: 8px;
align-items: center;
width: $selectWidth;
height: $selectHeight;
background-image: $selectBorder;
background-repeat: no-repeat;
background-size: $selectBackgroundWidth $selectBackgroundHeight;
background-position: center top;
&::before {
z-index: -1;
content: '';
position: absolute;
top: 4px;
left: 2px;
width: 75px;
height: 18px;
background-image: $panelBackground;
background-repeat: repeat;
}
&:active:not(.select--opened) {
.select-arrow {
background-image: $selectArrowClick;
}
}
&:focus {
outline: none;
box-shadow: inset $hoverBox;
}
&-arrow {
width: 32px;
height: 32px;
background-image: $selectArrow;
}
&-drop-down {
z-index: 7;
position: absolute;
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
width: $selectWidth + 10px; width: $selectWidth;
top: $selectHeight + 10px; height: $selectHeight;
left: 50%; padding-left: 6px;
transform: translateX(-50%); color: $fontColorWhite;
border: $dropDownOutset double $fontColor; background-image: $selectBorder;
border-image: $border 13 13 13 13; background-repeat: no-repeat;
border-image-width: $DropDownBorder; background-position: center top;
border-image-outset: $dropDownOutset; background-size: $selectBackgroundWidth $selectBackgroundHeight;
border-image-repeat: stretch stretch; border-radius: 8px;
background-color: $settingsBackground;
&:focus {
outline: none;
}
}
&-item {
width: 100%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
height: 20px;
&:hover {
background: linear-gradient(90deg,
rgba(173, 154, 32, 0.1) 0%,
rgba(173, 154, 32, 0.5) 25%,
rgba(173, 154, 32, 0.5) 75%,
rgba(173, 154, 32, 0.1) 100%);
}
&:active {
align-items: flex-end;
}
&:focus {
outline: none;
background: linear-gradient(90deg,
rgba(173, 154, 32, 0.1) 0%,
rgba(173, 154, 32, 0.5) 25%,
rgba(173, 154, 32, 0.5) 75%,
rgba(173, 154, 32, 0.1) 100%);
}
&::before { &::before {
content: ''; position: absolute;
position: absolute; top: 4px;
width: 16px; left: 2px;
height: 16px; z-index: -1;
background: $radio; width: 75px;
left: 0; height: 18px;
background-image: $panelBackground;
background-repeat: repeat;
content: "";
} }
&--selected { &:active:not(.select--opened) {
&::before { .select-arrow {
content: ''; background-image: $selectArrowClick;
position: absolute; }
width: 16px; }
height: 16px;
background: $radio 48px, $radio; &:focus {
left: 0; outline: none;
} box-shadow: inset $hoverBox;
}
&-arrow {
width: 32px;
height: 32px;
background-image: $selectArrow;
}
&-drop-down {
position: absolute;
top: $selectHeight + 10px;
left: 50%;
z-index: 7;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
width: $selectWidth + 10px;
background-color: $settingsBackground;
border: $dropDownOutset double $fontColor;
border-image: $border 13 13 13 13;
border-image-width: $DropDownBorder;
border-image-outset: $dropDownOutset;
border-image-repeat: stretch stretch;
transform: translateX(-50%);
&:focus {
outline: none;
}
}
&-item {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 20px;
text-align: center;
&:hover {
background:
linear-gradient(
90deg,
rgba(173, 154, 32, .1) 0%,
rgba(173, 154, 32, .5) 25%,
rgba(173, 154, 32, .5) 75%,
rgba(173, 154, 32, .1) 100%
);
}
&:active {
align-items: flex-end;
}
&:focus {
background:
linear-gradient(
90deg,
rgba(173, 154, 32, .1) 0%,
rgba(173, 154, 32, .5) 25%,
rgba(173, 154, 32, .5) 75%,
rgba(173, 154, 32, .1) 100%
);
outline: none;
}
&::before {
position: absolute;
left: 0;
width: 16px;
height: 16px;
background: $radio;
content: "";
}
&--selected {
&::before {
position: absolute;
left: 0;
width: 16px;
height: 16px;
background: $radio 48px, $radio;
content: "";
}
}
} }
}
} }
@@ -1,83 +1,95 @@
import * as React from 'react' import * as React from "react";
import { FocusEvent, KeyboardEvent, useCallback, useRef, useState } from 'react' import {
import cn from 'classnames' FocusEvent,
KeyboardEvent,
useCallback,
useRef,
useState,
} from "react";
import cn from "classnames";
import './select-component.scss' import "./select-component.scss";
interface Props { interface Props {
children: React.ReactNode children: React.ReactNode;
options: any[] options: string[];
current: any current: unknown;
handleChange: (value: any) => void handleChange: (value: string) => void;
} }
export const SelectComponent = ({children, options, current, handleChange}: Props) => { export const SelectComponent: React.FC<Props> = ({
const [isSelectShown, setSelectShown] = useState(false) children,
const dropDownRef = useRef<HTMLDivElement>(null) options,
current,
handleChange,
}: Props) => {
const [isSelectShown, setSelectShown] = useState(false);
const dropDownRef = useRef<HTMLDivElement>(null);
const handleSelectClick = useCallback(() => setSelectShown(!isSelectShown), [isSelectShown]) const handleSelectClick = useCallback(() => setSelectShown(!isSelectShown), [
isSelectShown,
]);
const handleBlur = (e: FocusEvent) => { const handleBlur = (e: FocusEvent) => {
if (!dropDownRef || !dropDownRef.current) { if (!dropDownRef || !dropDownRef.current) {
return return;
}
if (dropDownRef.current.contains(e.relatedTarget as Node) ||
e.currentTarget === e.relatedTarget) {
return
}
setSelectShown(!isSelectShown)
} }
if (
const handleKeyDown = (e: KeyboardEvent) => { dropDownRef.current.contains(e.relatedTarget as Node) ||
if (e.keyCode !== 13 && e.keyCode !== 32) { e.currentTarget === e.relatedTarget
return ) {
} return;
setSelectShown(!isSelectShown)
} }
setSelectShown(!isSelectShown);
};
const onItemClick = (itemValue: any) => handleChange(itemValue) const handleKeyDown = (e: KeyboardEvent) => {
if (e.keyCode !== 13 && e.keyCode !== 32) {
const onItemKeyDown = (e: KeyboardEvent, itemValue: any) => { return;
if (e.keyCode !== 13 && e.keyCode !== 32) {
return
}
handleChange(itemValue)
} }
setSelectShown(!isSelectShown);
};
return ( const onItemClick = (itemValue: string) => handleChange(itemValue);
const onItemKeyDown = (e: KeyboardEvent, itemValue: string) => {
if (e.keyCode !== 13 && e.keyCode !== 32) {
return;
}
handleChange(itemValue);
};
return (
<div
onClick={handleSelectClick}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
tabIndex={0}
className={cn("select", {
"select--opened": isSelectShown,
})}
>
{children}
<div className="select-arrow" />
{isSelectShown && (
<div ref={dropDownRef} className="select-drop-down">
{options.map((item, index) => (
<div <div
onClick={handleSelectClick} key={index}
onKeyDown={handleKeyDown} tabIndex={0}
onBlur={handleBlur} onClick={() => onItemClick(item)}
tabIndex={0} onKeyDown={(e) => onItemKeyDown(e, item)}
className={cn('select', { className={cn("select-item", {
'select--opened': isSelectShown "select-item--selected": item === current,
})} })}
> >
{children} {item}
<div className='select-arrow' />
{isSelectShown && (
<div
ref={dropDownRef}
className='select-drop-down'
>
{options.map((item, index) => (
<div
key={index}
tabIndex={0}
onClick={() => onItemClick(item)}
onKeyDown={(e) => onItemKeyDown(e, item)}
className={cn('select-item', {
'select-item--selected': item === current
})}
>
{item}
</div>
))}
</div>
)}
</div> </div>
) ))}
} </div>
)}
</div>
);
};
SelectComponent.displayName = 'SelectComponent' SelectComponent.displayName = "SelectComponent";
@@ -9,51 +9,51 @@ $settingsHeaderWidth: 132px;
$settingsHeaderHeight: 25px; $settingsHeaderHeight: 25px;
.settings { .settings {
z-index: 5;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border: $settingsBorderWidth double $fontColor;
border-image: $border 15 15 15 15 fill;
border-image-outset: $settingsBorderOutset;
border-image-repeat: stretch stretch;
font-family: $font;
font-size: $fontSize;
text-shadow: $fontShadow;
letter-spacing: $fontSpacing;
width: $settingsWidth;
height: $settingsHeight;
background-color: $settingsBackground;
&-header {
z-index: 6;
position: absolute; position: absolute;
top: 50%;
left: 50%; left: 50%;
transform: translateX(-50%); z-index: 5;
top: -$settingsHeaderHeight; width: $settingsWidth;
width: $settingsHeaderWidth; height: $settingsHeight;
height: $settingsHeaderHeight; font-size: $fontSize;
} font-family: $font;
letter-spacing: $fontSpacing;
text-shadow: $fontShadow;
background-color: $settingsBackground;
border: $settingsBorderWidth double $fontColor;
border-image: $border 15 15 15 15 fill;
border-image-outset: $settingsBorderOutset;
border-image-repeat: stretch stretch;
transform: translate(-50%, -50%);
&-content { &-header {
color: $fontColor; position: absolute;
margin-top: 10px; top: -$settingsHeaderHeight;
display: grid; left: 50%;
grid-template-rows: 1fr; z-index: 6;
grid-gap: 15px; width: $settingsHeaderWidth;
} height: $settingsHeaderHeight;
transform: translateX(-50%);
}
&-option { &-content {
display: flex; display: grid;
justify-content: space-between; grid-gap: 15px;
align-items: center; grid-template-rows: 1fr;
} margin-top: 10px;
color: $fontColor;
}
.settings-button { &-option {
position: absolute; display: flex;
bottom: 0; align-items: center;
left: 50%; justify-content: space-between;
transform: translateX(-50%); }
}
.settings-button {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
} }
@@ -1,118 +1,132 @@
import * as React from 'react' import * as React from "react";
import ru from '../../locales/ru.json' import ru from "../../locales/ru.json";
import en from '../../locales/en.json' import en from "../../locales/en.json";
import { useSettings } from '../../hooks' import { useSettings } from "../../hooks";
import { Settings } from '../../settings-context' import { Settings } from "../../settings-context";
import { BorderedHeader, CheckBoxComponent, RangeComponent, SelectComponent } from '..' import {
BorderedHeader,
CheckBoxComponent,
RangeComponent,
SelectComponent,
} from "..";
import './settings-component.scss' import "./settings-component.scss";
interface Props { interface Props {
closeSettings: () => void closeSettings: () => void;
checkboxOnSoundPlay: (volume?: number) => void checkboxOnSoundPlay: (volume?: number) => void;
checkboxOffSoundPlay: (volume?: number) => void checkboxOffSoundPlay: (volume?: number) => void;
} }
export const SettingsComponent = ({closeSettings, checkboxOnSoundPlay, checkboxOffSoundPlay}: Props) => { /* eslint-disable no-unused-expressions */
const {settings, saveSettings} = useSettings() export const SettingsComponent: React.FC<Props> = ({
closeSettings,
checkboxOnSoundPlay,
checkboxOffSoundPlay,
}: Props) => {
const { settings, saveSettings } = useSettings();
const handleCheckboxClick = (option: keyof Settings) => { const handleCheckboxClick = (option: keyof Settings) => {
saveSettings!({...settings, [option]: !settings[option]}) saveSettings?.({ ...settings, [option]: !settings[option] });
if (!settings.uiSound) { if (!settings.uiSound) {
return return;
}
if (settings[option]) {
checkboxOffSoundPlay()
} else {
checkboxOnSoundPlay()
}
} }
if (settings[option]) {
const handleChangeLanguage = (nextLanguage: string) => { checkboxOffSoundPlay();
if (settings.currentLanguage === nextLanguage) { } else {
return checkboxOnSoundPlay();
}
if (nextLanguage === ru['ui.language']) {
saveSettings!({...settings, language: ru, currentLanguage: nextLanguage})
} else {
saveSettings!({...settings, language: en, currentLanguage: nextLanguage})
}
if (!settings.uiSound) {
return
}
checkboxOnSoundPlay()
} }
};
const handleChangeRange = (value: number) => { const handleChangeLanguage = (nextLanguage: string) => {
checkboxOnSoundPlay() if (settings.currentLanguage === nextLanguage) {
saveSettings!({...settings, musicVolume: value}) return;
} }
if (nextLanguage === ru["ui.language"]) {
const chooseOption = (option: keyof Settings) => { saveSettings?.({
const {language} = settings ...settings,
switch (typeof settings[option]) { language: ru,
case 'boolean': currentLanguage: nextLanguage,
return ( });
<CheckBoxComponent } else {
handleClick={handleCheckboxClick} saveSettings?.({
optionName={option} ...settings,
value={settings[option] as boolean} language: en,
/> currentLanguage: nextLanguage,
) });
case 'object':
return (
<SelectComponent
handleChange={handleChangeLanguage}
current={language['ui.language']}
options={settings[option] as []}
>
{language['ui.language']}
</SelectComponent>
)
case 'number':
return (
<RangeComponent
defaultValue={settings[option] as number}
handleChange={handleChangeRange}
/>
)
}
} }
if (!settings.uiSound) {
return;
}
checkboxOnSoundPlay();
};
const renderOption = (option: keyof Settings) => { const handleChangeRange = (value: number) => {
const {language} = settings checkboxOnSoundPlay();
const valueName = `ui.${option}` as keyof typeof language saveSettings?.({ ...settings, musicVolume: value });
};
const chooseOption = (option: keyof Settings): React.ReactNode => {
const { language } = settings;
switch (typeof settings[option]) {
case "boolean":
return ( return (
<div className='settings-option'> <CheckBoxComponent
<div className='settings-option-name'> handleClick={handleCheckboxClick}
{language[valueName]} optionName={option}
</div> value={settings[option] as boolean}
{chooseOption(option)} />
</div> );
) case "object":
return (
<SelectComponent
handleChange={handleChangeLanguage}
current={language["ui.language"]}
options={settings[option] as []}
>
{language["ui.language"]}
</SelectComponent>
);
case "number":
return (
<RangeComponent
defaultValue={settings[option] as number}
handleChange={handleChangeRange}
/>
);
default:
return null;
} }
};
const renderOption = (option: keyof Settings) => {
const { language } = settings;
const valueName = `ui.${option}` as keyof typeof language;
return ( return (
<div className='settings'> <div className="settings-option">
<div className='settings-header'> <div className="settings-option-name">{language[valueName]}</div>
<BorderedHeader> {chooseOption(option)}
{settings.language['ui.main-menu']} </div>
</BorderedHeader> );
</div> };
<div className='settings-content'>
{renderOption('uiLanguage')}
{renderOption('musicVolume')}
{renderOption('uiSound')}
</div>
<button
className='settings-button'
onClick={closeSettings}
>
{settings.language['ui.button.close']}
</button>
</div>
)
}
SettingsComponent.displayName = 'SettingsComponent' return (
<div className="settings">
<div className="settings-header">
<BorderedHeader>{settings.language["ui.main-menu"]}</BorderedHeader>
</div>
<div className="settings-content">
{renderOption("uiLanguage")}
{renderOption("musicVolume")}
{renderOption("uiSound")}
</div>
<button className="settings-button" onClick={closeSettings}>
{settings.language["ui.button.close"]}
</button>
</div>
);
};
SettingsComponent.displayName = "SettingsComponent";
@@ -1,36 +1,36 @@
@import "../../app/style"; @import "../../app/style";
.view { .view {
z-index: 1;
position: absolute;
top: 0;
left: 0;
min-width: 100vw;
min-height: 100vh;
background-repeat: no-repeat;
animation: pulse 10s infinite;
animation-direction: alternate;
&-background {
z-index: 2;
opacity: 1;
position: absolute; position: absolute;
min-width: inherit; top: 0;
min-height: inherit; left: 0;
background: $backgroundTexture; z-index: 1;
transition: opacity $transitionDuration $transitionType; min-width: 100vw;
min-height: 100vh;
background-repeat: no-repeat;
animation: pulse 10s infinite;
animation-direction: alternate;
&--loaded { &-background {
opacity: 0; position: absolute;
z-index: 2;
min-width: inherit;
min-height: inherit;
background: $backgroundTexture;
opacity: 1;
transition: opacity $transitionDuration $transitionType;
&--loaded {
opacity: 0;
}
} }
}
} }
@keyframes pulse { @keyframes pulse {
0% { 0% {
transform: scale(1.02); transform: scale(1.02);
} }
100% { 100% {
transform: scale(1); transform: scale(1);
} }
} }
+149 -141
View File
@@ -1,171 +1,179 @@
import * as React from 'react' import * as React from "react";
import { FocusEvent, MouseEvent, TouchEvent, useCallback, useEffect, useState } from 'react' import {
import cn from 'classnames' FocusEvent,
MouseEvent,
TouchEvent,
useCallback,
useEffect,
useState,
} from "react";
import cn from "classnames";
import { Background } from '../../assets' import { Background } from "../../assets";
import { ANIMATION_DURATION, DEFAULT_HEIGHT, DEFAULT_WIDTH } from '../../utils' import { ANIMATION_DURATION, DEFAULT_HEIGHT, DEFAULT_WIDTH } from "../../utils";
import './view-component.scss' import "./view-component.scss";
interface Props { interface Props {
src: string src: string;
} }
interface Position { interface Position {
x: number x: number;
y: number y: number;
} }
const initialPosition = { const initialPosition = {
x: 0, x: 0,
y: 0 y: 0,
} };
export const ViewComponent = ({src}: Props) => { export const ViewComponent: React.FC<Props> = ({ src }: Props) => {
const [imageSrc, setImageSrc] = useState(Background) const [imageSrc, setImageSrc] = useState(Background);
const [isLoaded, setLoaded] = useState(false) const [isLoaded, setLoaded] = useState(false);
const [isDrag, setDrag] = useState(false) const [isDrag, setDrag] = useState(false);
const [trackPosition, setTrackPosition] = useState(initialPosition) const [trackPosition, setTrackPosition] = useState(initialPosition);
const [position, setPosition] = useState(initialPosition) const [position, setPosition] = useState(initialPosition);
const [lastPosition, setLastPosition] = useState(initialPosition) const [lastPosition, setLastPosition] = useState(initialPosition);
const [isBigScreen, setBigScreen] = useState(false) const [isBigScreen, setBigScreen] = useState(false);
const handleResize = useCallback(() => { const handleResize = useCallback(() => {
const {innerWidth, innerHeight} = window const { innerWidth, innerHeight } = window;
let width = 0 let width = 0;
let height = 0 let height = 0;
setBigScreen(false) setBigScreen(false);
if (innerHeight < DEFAULT_HEIGHT && innerWidth < DEFAULT_WIDTH) { if (innerHeight < DEFAULT_HEIGHT && innerWidth < DEFAULT_WIDTH) {
width = (innerWidth - DEFAULT_WIDTH) / 2 width = (innerWidth - DEFAULT_WIDTH) / 2;
height = (innerHeight - DEFAULT_HEIGHT) / 2 height = (innerHeight - DEFAULT_HEIGHT) / 2;
} else { } else {
setBigScreen(true) setBigScreen(true);
} }
setPosition({x: width, y: height}) setPosition({ x: width, y: height });
setLastPosition({x: width, y: height}) setLastPosition({ x: width, y: height });
}, []) }, []);
useEffect(() => { useEffect(() => {
handleResize() handleResize();
setLoaded(false) setLoaded(false);
const timer = setTimeout(() => { const timer = setTimeout(() => {
const image = new Image() const image = new Image();
image.src = src image.src = src;
image.onload = () => { image.onload = () => {
setImageSrc(src) setImageSrc(src);
setLoaded(true) setLoaded(true);
} };
}, ANIMATION_DURATION) }, ANIMATION_DURATION);
return () => { return () => {
clearTimeout(timer) clearTimeout(timer);
} };
}, [src, handleResize]) }, [src, handleResize]);
useEffect(() => { useEffect(() => {
window.addEventListener('resize', handleResize) window.addEventListener("resize", handleResize);
return () => { return () => {
window.removeEventListener('resize', handleResize) window.removeEventListener("resize", handleResize);
} };
}, [handleResize]) }, [handleResize]);
const handleTouchMove = (e: TouchEvent) => { const limiter = (value: Position, width: number, height: number) => {
const {touches} = e const { x: xValue, y: yValue } = value;
if (isBigScreen) {
return
}
const {innerWidth, innerHeight} = window
const width = DEFAULT_WIDTH - innerWidth
const height = DEFAULT_HEIGHT - innerHeight
const {clientX: x, clientY: y} = touches[0]
const diff = limiter({x, y}, width, height) let x = lastPosition.x - trackPosition.x + xValue;
let y = lastPosition.y - trackPosition.y + yValue;
setPosition(diff) if (x > 0) {
x = 0;
} else if (x < -width) {
x = -width;
} }
const limiter = (value: Position, width: number, height: number) => { if (y > 0) {
const {x: xValue, y: yValue} = value y = 0;
} else if (y < -height) {
let x = lastPosition.x - trackPosition.x + xValue y = -height;
let y = lastPosition.y - trackPosition.y + yValue
if (x > 0) {
x = 0
} else if (x < -width) {
x = -width
}
if (y > 0) {
y = 0
} else if (y < -height) {
y = -height
}
return ({x, y})
} }
const handleTouchstart = (e: TouchEvent) => { return { x, y };
const {touches} = e };
e.nativeEvent.stopImmediatePropagation()
const {clientX: x, clientY: y} = touches[0] const handleTouchMove = (e: TouchEvent) => {
setTrackPosition({x, y}) const { touches } = e;
setDrag(true) if (isBigScreen) {
return;
} }
const { innerWidth, innerHeight } = window;
const width = DEFAULT_WIDTH - innerWidth;
const height = DEFAULT_HEIGHT - innerHeight;
const { clientX: x, clientY: y } = touches[0];
const handleMouseDown = (e: MouseEvent) => { const diff = limiter({ x, y }, width, height);
const {clientX, clientY} = e
e.nativeEvent.stopImmediatePropagation() setPosition(diff);
setTrackPosition({x: clientX, y: clientY}) };
setDrag(true)
const handleTouchstart = (e: TouchEvent) => {
const { touches } = e;
e.nativeEvent.stopImmediatePropagation();
const { clientX: x, clientY: y } = touches[0];
setTrackPosition({ x, y });
setDrag(true);
};
const handleMouseDown = (e: MouseEvent) => {
const { clientX, clientY } = e;
e.nativeEvent.stopImmediatePropagation();
setTrackPosition({ x: clientX, y: clientY });
setDrag(true);
};
const handleFree = (e: MouseEvent | FocusEvent | TouchEvent) => {
e.nativeEvent.stopImmediatePropagation();
setDrag(false);
setLastPosition(position);
};
const handleMouseMove = (e: MouseEvent) => {
if (!isDrag) {
return;
} }
if (isBigScreen) {
const handleFree = (e: MouseEvent | FocusEvent | TouchEvent) => { return;
e.nativeEvent.stopImmediatePropagation()
setDrag(false)
setLastPosition(position)
} }
const { innerWidth, innerHeight } = window;
const width = DEFAULT_WIDTH - innerWidth;
const height = DEFAULT_HEIGHT - innerHeight;
const handleMouseMove = (e: MouseEvent) => { const { clientX: x, clientY: y } = e;
if (!isDrag) { const diff = limiter({ x, y }, width, height);
return setPosition(diff);
} };
if (isBigScreen) {
return
}
const {innerWidth, innerHeight} = window
const width = DEFAULT_WIDTH - innerWidth
const height = DEFAULT_HEIGHT - innerHeight
const {clientX: x, clientY: y} = e return (
const diff = limiter({x, y}, width, height) <div
setPosition(diff) className="view"
} style={{
backgroundImage: `url(${imageSrc})`,
backgroundPosition: `${position.x}px ${position.y}px`,
backgroundSize: `${isBigScreen ? "cover" : "auto"}`,
}}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleFree}
onTouchMove={handleTouchMove}
onTouchStart={handleTouchstart}
onTouchEnd={handleFree}
onMouseLeave={handleFree}
onBlur={handleFree}
>
<div
className={cn("view-background", {
"view-background--loaded": isLoaded,
})}
/>
</div>
);
};
return ( ViewComponent.displayName = "ViewComponent";
<div
className='view'
style={{
backgroundImage: `url(${imageSrc})`,
backgroundPosition: `${position.x}px ${position.y}px`,
backgroundSize: `${isBigScreen ? 'cover' : 'auto'}`
}}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleFree}
onTouchMove={handleTouchMove}
onTouchStart={handleTouchstart}
onTouchEnd={handleFree}
onMouseLeave={handleFree}
onBlur={handleFree}
>
<div className={cn('view-background', {
'view-background--loaded': isLoaded
})}
/>
</div>
)
}
ViewComponent.displayName = 'ViewComponent'
+1 -1
View File
@@ -1 +1 @@
export { useSettings } from './use-settings' export { useSettings } from "./use-settings";
+4 -3
View File
@@ -1,4 +1,5 @@
import { useContext } from 'react' import { useContext } from "react";
import SettingsContext from '../settings-context' import SettingsContext, { SettingsContextType } from "../settings-context";
export const useSettings = () => useContext(SettingsContext) export const useSettings = (): SettingsContextType =>
useContext(SettingsContext);
+17 -17
View File
@@ -1,23 +1,23 @@
import * as React from 'react' import * as React from "react";
import ReactDom from 'react-dom' import ReactDom from "react-dom";
import { Settings, SettingsProvider } from './settings-context' import { Settings, SettingsProvider } from "./settings-context";
import App from './app' import App from "./app";
import ru from './locales/ru.json' import ru from "./locales/ru.json";
import en from './locales/en.json' import en from "./locales/en.json";
const defaultSettings: Settings = { const defaultSettings: Settings = {
language: ru, language: ru,
musicVolume: 1.0, musicVolume: 1.0,
currentLanguage: ru['ui.language'], currentLanguage: ru["ui.language"],
uiLanguage: [ru['ui.language'], en['ui.language']], uiLanguage: [ru["ui.language"], en["ui.language"]],
uiSound: true uiSound: true,
} };
ReactDom.render( ReactDom.render(
<SettingsProvider settings={defaultSettings}> <SettingsProvider settings={defaultSettings}>
<App /> <App />
</SettingsProvider>, </SettingsProvider>,
document.getElementById('root') document.getElementById("root")
) );
+40 -34
View File
@@ -1,43 +1,49 @@
/* eslint-disable no-console */
export default class Sound { export default class Sound {
public audio: HTMLAudioElement public audio: HTMLAudioElement;
private volume: number
constructor(file: string, volumeValue?: number) { private volume: number;
const volume = this.validateVolume(volumeValue)
this.audio = new Audio(file)
this.audio.load()
this.volume = volume
}
public setVolume = (volume: number) => { constructor(file: string, volumeValue?: number) {
this.validateVolume(volume) const volume = this.validateVolume(volumeValue);
this.volume = volume this.audio = new Audio(file);
this.audio.load();
this.volume = volume;
}
return this public setVolume = (volume: number): Sound => {
} this.validateVolume(volume);
this.volume = volume;
public playSound = (volume: number = this.volume) => { return this;
this.audio.volume = this.validateVolume(volume) };
if (!this.audio.readyState) {
return
}
this.audio.play().catch((error: Error) => console.error(`Error playback: ${error}`))
}
public playMusic = (volume: number = this.volume) => { public playSound = (volume: number = this.volume): void => {
this.audio.volume = this.validateVolume(volume) this.audio.volume = this.validateVolume(volume);
if (!this.audio.readyState) { if (!this.audio.readyState) {
return return;
} }
this.audio.play().catch((error: Error) => console.error(`Error playback: ${error}`)) this.audio
} .play()
.catch((error: Error) => console.error(`Error playback: ${error}`));
};
public pause = () => this.audio.pause() public playMusic = (volume: number = this.volume): void => {
this.audio.volume = this.validateVolume(volume);
if (!this.audio.readyState) {
return;
}
this.audio
.play()
.catch((error: Error) => console.error(`Error playback: ${error}`));
};
private validateVolume = (volumeValue: number = 1.0) => { public pause = (): void => this.audio.pause();
if (volumeValue && (volumeValue < 0 || volumeValue > 1)) {
throw Error('"Volume" must be an number between 0.0 and 1.0') private validateVolume = (volumeValue = 1.0) => {
} if (volumeValue && (volumeValue < 0 || volumeValue > 1)) {
return volumeValue throw Error('"Volume" must be an number between 0.0 and 1.0');
} }
return volumeValue;
};
} }
+2 -2
View File
@@ -1,3 +1,3 @@
/// <reference types="react-scripts" /> /// <reference types="react-scripts" />
declare module '*.ogg' declare module "*.ogg";
declare module '*.mp3' declare module "*.mp3";
+42 -37
View File
@@ -1,52 +1,57 @@
import * as React from 'react' import * as React from "react";
import { createContext, useState } from 'react' import { createContext, useState } from "react";
import ru from './locales/ru.json' import ru from "./locales/ru.json";
import en from './locales/en.json' import en from "./locales/en.json";
export interface Settings { export interface Settings {
language: typeof ru | typeof en language: typeof ru | typeof en;
musicVolume: number musicVolume: number;
currentLanguage: string currentLanguage: string;
uiLanguage: string[] uiLanguage: string[];
uiSound: boolean uiSound: boolean;
} }
interface SettingsContextType { export interface SettingsContextType {
settings: Settings settings: Settings;
saveSettings?: (value: Settings) => void saveSettings?: (value: Settings) => void;
} }
interface Props { interface Props {
children: React.ReactNode children: React.ReactNode;
settings: Settings settings: Settings;
} }
const defaultSettings: SettingsContextType = { const defaultSettings: SettingsContextType = {
settings: { settings: {
language: ru, language: ru,
musicVolume: 1.0, musicVolume: 1.0,
currentLanguage: ru['ui.language'], currentLanguage: ru["ui.language"],
uiLanguage: [ru['ui.language'], en['ui.language']], uiLanguage: [ru["ui.language"], en["ui.language"]],
uiSound: true uiSound: true,
} },
} };
const SettingsContext = createContext(defaultSettings) const SettingsContext = createContext(defaultSettings);
export const SettingsProvider = ({children, settings}: Props) => { export const SettingsProvider: React.FC<Props> = ({
const [currentSettings, setCurrentSettings] = useState(settings || defaultSettings) children,
settings,
}: Props) => {
const [currentSettings, setCurrentSettings] = useState(
settings || defaultSettings
);
const saveSettings = (value: Settings) => { const saveSettings = (value: Settings) => {
setCurrentSettings(value) setCurrentSettings(value);
} };
return ( return (
<SettingsContext.Provider <SettingsContext.Provider
value={{settings: currentSettings, saveSettings}} value={{ settings: currentSettings, saveSettings }}
> >
{children} {children}
</SettingsContext.Provider> </SettingsContext.Provider>
) );
} };
export default SettingsContext export default SettingsContext;
+9 -9
View File
@@ -1,9 +1,9 @@
export const ANIMATION_DURATION = 500 export const ANIMATION_DURATION = 500;
export const LOADING_DURATION = 800 export const LOADING_DURATION = 800;
export const PREVIEW_WIDTH = 320 export const PREVIEW_WIDTH = 320;
export const PREVIEW_HEIGHT = 180 export const PREVIEW_HEIGHT = 180;
export const UI_SOUND_VOLUME = 0.2 export const UI_SOUND_VOLUME = 0.2;
export const UI_MUSIC_VOLUME = 1 export const UI_MUSIC_VOLUME = 1;
export const SPACE = 200 export const SPACE = 200;
export const DEFAULT_WIDTH = 1920 export const DEFAULT_WIDTH = 1920;
export const DEFAULT_HEIGHT = 1080 export const DEFAULT_HEIGHT = 1080;
+27 -27
View File
@@ -1,34 +1,34 @@
import { LOADING_DURATION } from './constants' import { LOADING_DURATION } from "./constants";
import Sound from '../modules/sound' import Sound from "../modules/sound";
export { export {
PREVIEW_WIDTH, PREVIEW_WIDTH,
PREVIEW_HEIGHT, PREVIEW_HEIGHT,
UI_MUSIC_VOLUME, UI_MUSIC_VOLUME,
UI_SOUND_VOLUME, UI_SOUND_VOLUME,
LOADING_DURATION, LOADING_DURATION,
ANIMATION_DURATION, ANIMATION_DURATION,
DEFAULT_HEIGHT, DEFAULT_HEIGHT,
DEFAULT_WIDTH, DEFAULT_WIDTH,
SPACE SPACE,
} from './constants' } from "./constants";
export const delay = () => new Promise(resolve => setTimeout(resolve, LOADING_DURATION)) export const delay = (): Promise<unknown> =>
new Promise((resolve) => setTimeout(resolve, LOADING_DURATION));
export const soundLoad = (soundFile: string, soundVolume: number) => ( export const soundLoad = (soundFile: string, soundVolume: number): Sound =>
new Sound(soundFile, soundVolume) new Sound(soundFile, soundVolume);
)
export const randomNumber = (min: number, max: number) => ( export const randomNumber = (min: number, max: number): number =>
Math.floor(Math.random() * (max - min)) + min Math.floor(Math.random() * (max - min)) + min;
)
export function debounce(fn: (args: any) => any, ms: number) { // eslint-disable-next-line
let timer: NodeJS.Timeout export function debounce(fn: (args: any) => unknown, ms: number): any {
return (...args: any) => { let timer: NodeJS.Timeout;
if (timer) { return (...args: [unknown]) => {
clearTimeout(timer) if (timer) {
} clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), ms) }
} timer = setTimeout(() => fn.apply(this, args), ms);
};
} }
-34
View File
@@ -1,34 +0,0 @@
{
"extends": "tslint:recommended",
"rules": {
"max-line-length": {
"options": [
120
]
},
"new-parens": true,
"no-arg": true,
"semicolon": false,
"no-bitwise": false,
"no-conditional-assignment": true,
"no-consecutive-blank-lines": true,
"no-console": {
"severity": "warning",
"options": [
"debug",
"info",
"log",
"time",
"timeEnd",
"trace"
]
}
},
"jsRules": {
"max-line-length": {
"options": [
120
]
}
}
}