From 26e55c08d246fed8c2f38ca617f2c147e85b683b Mon Sep 17 00:00:00 2001 From: Syphax bouazzouni Date: Tue, 5 Dec 2023 23:33:28 +0100 Subject: [PATCH] Merge to master: Release 2.7.0.2 - Adds all the view components, with previews in the lookbook (#336) * Merge pull request #234 from ontoportal-lirmm/feature/update-footer-design Feature: Update footer design * Merge pull request #249 from ontoportal-lirmm/feature/update-account-page-submited-onto Feature: Update account page submitted ontologies * Merge pull request #236 from ontoportal-lirmm/feature/lookbook Feature: Add Lookbook to preview components * Merge pull request #242 from ontoportal-lirmm/feature/lookbook Feature: Add Lookbook to preview view components - fix the new version release * Merge pull request #262 from ontoportal-lirmm/feature/add-rounded-button-component-to-lookbook Feature: Add rounded button to lookbook * Merge pull request #248 from ontoportal-lirmm/feature/add-notification-message-component Feature: Add notification message component * Merge pull request #268 from ontoportal-lirmm/feature/add-submission-fields-components Feature: Add submission fields components * Merge pull request #288 from ontoportal-lirmm/feature/add-upload-ontology-components-to-lookbook Feature: Add form inputs components to lookbook * Merge pull request #284 from ontoportal-lirmm/feature/update-nested-from-input-component-design Feature: Update nested form input component design * Merge pull request #282 from ontoportal-lirmm/feature/extract-search-input-component Feature: Extract search input component * Merge pull request #296 from ontoportal-lirmm/feature/re-organize-lookbook Feature: Re organize lookbook previews * Merge pull request #305 from ontoportal-lirmm/feature/add-table-component Feature: Add table component & Migrate the views to use it * Merge pull request #312 from ontoportal-lirmm/feature/extract-search-input-component Feature: Extract search input component - follow up * Merge pull request #313 from ontoportal-lirmm/fix/nested-from-component-empty-state Fix: Nested form component empty state * Merge pull request #301 from ontoportal-lirmm/feature/add-switch-input-preview Feature: Add switch input preview * Merge pull request #304 from ontoportal-lirmm/feature/add-link-text-components Feature: Add link text components * Merge pull request #310 from ontoportal-lirmm/feature/update-select-component Feature: update select component * Merge pull request #300 from ontoportal-lirmm/feature/add-modal-link-component Feature: Add modal component preview and helpers * Merge pull request #303 from ontoportal-lirmm/feature/add-pill-button Feature: Add pill button * Merge pull request #297 from ontoportal-lirmm/feature/add-tabs-component Feature: Add tabs component * Merge pull request #306 from ontoportal-lirmm/feature/add-circle-progress-bar-component Feature: Add circle progress bar component (style, JS, code and preview) * Merge pull request #247 from ontoportal-lirmm/feature/update-agroportal-primary-color Feature: Update AgroPortal primary color * Merge pull request #319 from ontoportal-lirmm/feature/extract-form-input-components Feature: Extract form input components * Merge pull request #324 from ontoportal-lirmm/feature/add-summary-page-components Feature: Extract summary page components * Merge pull request #314 from ontoportal-lirmm/add-buttons-components-to-lookbook Feature: Add buttons components to lookbook * Feature: Add progress pages component (#328) * add progress pages component * put again the type argument for button component * fix progress pages item not center if test is long * make progress pages container take full width by default * Fix progress item position (first & last one) to be aligned with the content * fix progress item checked state to show the icon and the good background * make the progress page component preview width bigger --------- Co-authored-by: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> * Merge pull request #259 from ontoportal-lirmm/feature/add-other-states-to-card-message-component Feature: Add warning state to card message component * Merge pull request #238 from ontoportal-lirmm/feature/update-nav-bar-design Feature: Update nav bar design * Merge pull request #331 from ontoportal-lirmm/feature/update-404-error-design Feature: Update 404 error design * Merge pull request #263 from ontoportal-lirmm/feature/update-nav-bar-design Fix: replace nav_bar css nav-link to top-nav-nav-link to prevent conflicts --------- Co-authored-by: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> --- Gemfile | 3 +- Gemfile.lock | 2 + app/assets/images/arrow-right-outlined.svg | 3 + app/assets/images/errors/agroportal.svg | 91 +++ app/assets/images/eye.svg | 4 + app/assets/images/icons/alert.svg | 5 + app/assets/images/icons/arrow-left.svg | 4 + app/assets/images/icons/calendar.svg | 3 + app/assets/images/icons/close.svg | 6 + app/assets/images/icons/delete.svg | 3 + app/assets/images/icons/error.svg | 1 + app/assets/images/icons/external-link.svg | 3 + app/assets/images/icons/info.svg | 4 + app/assets/images/icons/internal-link.svg | 3 + app/assets/images/icons/list-tree.svg | 3 + app/assets/images/icons/list.svg | 6 + app/assets/images/icons/loop.svg | 4 + app/assets/images/icons/plus.svg | 3 + app/assets/images/icons/popup-link.svg | 3 + app/assets/images/icons/success.svg | 3 + app/assets/images/icons/white-check.svg | 5 + app/assets/images/json.svg | 3 + app/assets/images/list-tree.svg | 1 - app/assets/images/logo-white.svg | 3 + app/assets/images/logos/ontoportal.svg | 3 + app/assets/images/orange-warning.svg | 5 + app/assets/images/social/github.svg | 3 + app/assets/images/social/people.svg | 3 + app/assets/images/social/twitter.svg | 10 + app/assets/images/summary/arrow-down.svg | 3 + app/assets/images/update.svg | 3 + app/assets/images/upload-file.svg | 3 + app/assets/stylesheets/account.scss | 8 +- .../stylesheets/application.css.scss.erb | 4 +- app/assets/stylesheets/bioportal.scss | 7 + app/assets/stylesheets/components/card.scss | 5 + .../stylesheets/components/card_message.scss | 4 + .../stylesheets/components/chip_button.scss | 27 + .../components/circle_progress_bar.scss | 26 + .../components/concept_details.scss | 11 + .../stylesheets/components/dropdown.scss | 17 + .../components/field_container.scss | 23 + .../components/file_input_loader.scss | 54 ++ app/assets/stylesheets/components/header.scss | 15 + app/assets/stylesheets/components/image.scss | 22 + app/assets/stylesheets/components/index.scss | 27 +- .../stylesheets/components/input_field.scss | 69 +++ app/assets/stylesheets/components/modal.scss | 20 + .../stylesheets/components/nested_form.scss | 50 ++ .../stylesheets/components/notification.scss | 146 +++++ .../components/outline_tabs_container.scss | 27 + .../stylesheets/components/pill_button.scss | 33 ++ .../components/pill_tabs_container.scss | 22 + .../components/progress_pages.scss | 118 ++++ .../components/regular_button.scss | 211 +++++++ .../components/rounded_button.scss | 17 + .../stylesheets/components/search_input.scss | 48 ++ .../components/summary_section.scss | 13 + app/assets/stylesheets/components/switch.scss | 64 ++ app/assets/stylesheets/components/table.scss | 37 ++ .../components/tabs_container.scss | 57 ++ .../components/text_area_field.scss | 14 + app/assets/stylesheets/concepts.scss | 2 +- app/assets/stylesheets/file_uploader.scss | 53 -- app/assets/stylesheets/footer.scss | 58 +- app/assets/stylesheets/home.scss | 457 +++++++++++++++ app/assets/stylesheets/login.scss | 21 +- app/assets/stylesheets/nav_bar.scss | 169 ++++++ app/assets/stylesheets/ontologies.scss | 11 - app/assets/stylesheets/register.scss | 14 +- .../stylesheets/theme-variables.scss.erb | 38 +- .../stylesheets/themes/agroportal/main.scss | 4 +- app/assets/stylesheets/themes/lirmm/main.scss | 19 - .../stylesheets/themes/ontoportal/main.scss | 6 +- .../stylesheets/themes/stageportal/main.scss | 4 +- .../buttons/regular_button_component.rb | 49 ++ .../regular_button_component.html.haml | 11 + app/components/card_message_component.rb | 6 +- .../card_message_component.html.haml | 8 +- .../chip_button_component.html.haml | 5 + app/components/chips_component.rb | 8 +- .../circle_progress_bar_component.rb | 14 + .../circle_progress_bar_component.html.haml | 7 + ...ircle_progress_bar_component_controller.js | 37 ++ app/components/concept_details_component.rb | 27 +- app/components/date_time_field_component.rb | 15 + .../display/button_loader_component.rb | 23 + app/components/display/header_component.rb | 23 + app/components/display/image_component.rb | 34 ++ app/components/dropdown_button_component.rb | 12 + .../dropdown_button_component.html.haml | 8 + .../dropdown_container_component.rb | 10 + .../dropdown_container_component.html.haml | 12 + .../dropdown_section_button_component.rb | 16 + ...ropdown_section_button_component.html.haml | 7 + .../external_link_text_component.rb | 8 + app/components/field_container_component.rb | 15 + .../field_container_component.html.haml | 9 + .../file_input_loader_component.html.haml | 5 - app/components/input/date_component.rb | 11 + app/components/input/email_component.rb | 11 + .../file_input_component.rb} | 2 +- .../file_input_component.html.haml | 5 + .../file_input_loader_component_controller.js | 0 app/components/input/input_field_component.rb | 30 + .../input_field_component.html.haml | 28 + app/components/input/password_component.rb | 11 + app/components/input/select_component.rb | 13 + .../select_component.html.haml | 2 + app/components/input/text_area_component.rb | 8 + .../text_area_component.html.haml | 3 + app/components/input/text_input_component.rb | 11 + app/components/input/url_component.rb | 11 + .../internal_link_text_component.rb | 7 + app/components/label_link_component.rb | 6 +- app/components/language_field_component.rb | 26 + .../language_field_component.html.haml | 5 + app/components/layout/card_component.rb | 13 + .../layout/horizontal_list_component.rb | 18 + app/components/layout/list_component.rb | 20 + .../layout/progress_pages_component.rb | 10 + .../progress_pages_component.html.haml | 32 + .../progress_pages_component_controller.js | 87 +++ app/components/license_field_component.rb | 10 + .../license_field_component.html.haml | 8 + app/components/link_field_component.rb | 15 + .../link_field_component.html.haml | 6 + app/components/link_text_component.rb | 14 + app/components/loader_component.rb | 11 +- .../nested_form_inputs_component.rb | 7 + .../nested_form_inputs_component.html.haml | 35 +- app/components/notification_component.rb | 39 ++ .../notification_component.html.haml | 13 + .../ontology_search_input_component.rb | 10 + .../ontology_search_input_component.html.haml | 11 + .../ontology_subscribe_button_component.rb | 12 +- ...y_subscribe_button_component_controller.js | 11 +- app/components/pill_button_component.rb | 9 + .../pill_button_component.html.haml | 2 + app/components/popup_link_text_component.rb | 9 + app/components/rounded_button_component.rb | 20 + .../rounded_button_component.html.haml | 2 + app/components/search_input_component.rb | 32 + .../search_input_component.html.haml | 20 + .../search_input_component_controller.js | 164 ++++++ app/components/select_input_component.rb | 32 +- .../select_input_component.html.haml | 10 - .../select_input_component_controller.js | 135 +---- app/components/summary_section_component.rb | 17 + .../summary_section_component.html.haml | 19 + app/components/switch_input_component.rb | 2 +- .../switch_input_component.html.haml | 11 +- app/components/tab_item_component.rb | 51 ++ app/components/table_cell_component.rb | 18 + app/components/table_component.rb | 31 + .../table_component/table_component.html.haml | 7 + app/components/table_row_component.rb | 28 + .../table_row_component.html.haml | 4 + app/components/tabs_container_component.rb | 47 ++ .../tabs_container_component.html.haml | 16 + .../tabs_container_component_controller.js | 43 ++ app/components/text_area_field_component.rb | 12 + .../text_area_field_component.html.haml | 5 + app/components/turbo_modal_component.rb | 3 +- .../turbo_modal_component.html.haml | 4 +- .../turbo_modal_component_controller.js | 10 + app/controllers/application_controller.rb | 4 + app/controllers/notes_controller.rb | 2 +- app/controllers/ontologies_controller.rb | 8 +- app/helpers/application_helper.rb | 101 ++-- app/helpers/components_helper.rb | 80 +++ app/helpers/modal_helper.rb | 42 ++ app/helpers/submissions_helper.rb | 11 +- app/javascript/component_controllers/index.js | 13 +- app/javascript/controllers/application.js | 3 +- app/javascript/controllers/index.js | 9 + .../controllers/language_change_controller.js | 19 + .../ontology_viewer_tabs_controller.js | 46 ++ .../controllers/text_truncate_controller.js | 21 + .../topnav_responsiveness_controller.js | 22 + app/views/admin/index.html.haml | 27 +- app/views/annotator/index.html.haml | 2 +- app/views/annotatorplus/index.html.haml | 2 +- app/views/collections/_collection.html.haml | 26 +- app/views/concepts/_details.html.haml | 1 + .../errors/internal_server_error.html.erb | 3 - .../errors/internal_server_error.html.haml | 15 + app/views/errors/not_found.html.erb | 5 - app/views/errors/not_found.html.haml | 12 + app/views/fair_score/_details.html.haml | 2 +- app/views/label_xl/show.html.haml | 21 +- app/views/layouts/_footer.html.haml | 53 +- app/views/layouts/_header.html.erb | 2 +- app/views/layouts/_notices.html.haml | 5 +- app/views/layouts/_ontology_viewer.html.haml | 2 +- app/views/layouts/_topnav.html.haml | 109 ++-- app/views/layouts/appliance.html.haml | 5 +- app/views/layouts/application.html.erb | 2 +- app/views/layouts/component_preview.html.erb | 59 ++ .../component_preview_not_centred.html.erb | 56 ++ app/views/layouts/ontology.html.erb | 2 +- .../layouts/ontology_viewer/_header.html.haml | 34 ++ app/views/login/index.html.haml | 3 +- app/views/mappings/_count.html.haml | 32 +- .../mappings/bulk_loader/_loader.html.haml | 4 +- app/views/mappings/edit.html.haml | 2 +- app/views/mappings/index.html.haml | 2 +- app/views/mappings/new.html.haml | 2 +- app/views/ncbo_annotatorplus/index.html.haml | 2 +- app/views/notes/_new_comment.html.haml | 2 +- app/views/notes/_new_proposal.html.haml | 2 +- app/views/notes/_note_line.html.haml | 25 +- app/views/notes/_notes.html.haml | 44 +- app/views/notes/show.html.haml | 2 +- .../_concepts_browser.html.haml | 7 +- .../ontologies/sections/visualize.html.haml | 2 +- .../_form_edit.html.haml | 2 +- app/views/schemes/_scheme.html.haml | 19 +- app/views/submissions/_form_content.html.haml | 18 +- app/views/users/_form.html.haml | 3 +- app/views/users/show.html.haml | 4 +- config/application.rb | 3 + config/environments/appliance.rb | 2 +- config/locales/en.yml | 545 +++++++++++++++--- config/routes.rb | 5 +- lib/tasks/generate_component_previews.rake | 34 ++ package.json | 4 +- .../file_input_loader_component_spec.rb | 15 - ...logy_subscribe_button_component_preview.rb | 7 + .../buttons/pill_button_component_preview.rb | 8 + .../regular_button_component_preview.rb | 57 ++ .../rounded_button_component_preview.rb | 14 + .../concept_details_component_preview.rb | 33 ++ .../circle_progress_bar_component_preview.rb | 10 + .../date_time_field_component_preview.rb | 9 + .../field_container_component_preview.rb | 11 + .../display/header_component_preview.rb | 10 + .../display/image_component_preview.rb | 7 + .../display/info_tooltip_component_preview.rb | 9 + .../language_field_component_preview.rb | 8 + .../license_field_component_preview.rb | 8 + .../display/link_field_component_preview.rb | 8 + .../display/link_text_component_preview.rb | 25 + .../text_area_field_component_preview.rb | 13 + .../previews/input/chips_component_preview.rb | 10 + .../input/input_field_component_preview.rb | 90 +++ .../nested_form_input_component_preview.rb | 18 + .../input/select_component_preview.rb | 17 + .../input/switch_input_component_preview.rb | 9 + .../previews/layout/card_component_preview.rb | 10 + .../dropdown_container_component_preview.rb | 15 + .../previews/layout/list_component_preview.rb | 19 + .../progress_pages_component_preview.rb | 11 + .../summary_section_component_preview.rb | 14 + .../layout/table_component_preview.rb | 45 ++ .../tabs_container_component_preview.rb | 78 +++ .../layout/turbo_modal_component_preview.rb | 16 + .../previews/loader_component_preview.rb | 12 + .../notification_component_preview.rb | 12 + yarn.lock | 25 + 260 files changed, 5473 insertions(+), 734 deletions(-) create mode 100644 app/assets/images/arrow-right-outlined.svg create mode 100644 app/assets/images/errors/agroportal.svg create mode 100644 app/assets/images/eye.svg create mode 100644 app/assets/images/icons/alert.svg create mode 100644 app/assets/images/icons/arrow-left.svg create mode 100644 app/assets/images/icons/calendar.svg create mode 100644 app/assets/images/icons/close.svg create mode 100644 app/assets/images/icons/delete.svg create mode 100644 app/assets/images/icons/error.svg create mode 100644 app/assets/images/icons/external-link.svg create mode 100644 app/assets/images/icons/info.svg create mode 100644 app/assets/images/icons/internal-link.svg create mode 100644 app/assets/images/icons/list-tree.svg create mode 100644 app/assets/images/icons/list.svg create mode 100644 app/assets/images/icons/loop.svg create mode 100644 app/assets/images/icons/plus.svg create mode 100644 app/assets/images/icons/popup-link.svg create mode 100644 app/assets/images/icons/success.svg create mode 100644 app/assets/images/icons/white-check.svg create mode 100644 app/assets/images/json.svg delete mode 100644 app/assets/images/list-tree.svg create mode 100644 app/assets/images/logo-white.svg create mode 100644 app/assets/images/logos/ontoportal.svg create mode 100644 app/assets/images/orange-warning.svg create mode 100644 app/assets/images/social/github.svg create mode 100644 app/assets/images/social/people.svg create mode 100644 app/assets/images/social/twitter.svg create mode 100644 app/assets/images/summary/arrow-down.svg create mode 100644 app/assets/images/update.svg create mode 100644 app/assets/images/upload-file.svg create mode 100644 app/assets/stylesheets/components/card.scss create mode 100644 app/assets/stylesheets/components/chip_button.scss create mode 100644 app/assets/stylesheets/components/circle_progress_bar.scss create mode 100644 app/assets/stylesheets/components/concept_details.scss create mode 100644 app/assets/stylesheets/components/dropdown.scss create mode 100644 app/assets/stylesheets/components/field_container.scss create mode 100644 app/assets/stylesheets/components/file_input_loader.scss create mode 100644 app/assets/stylesheets/components/header.scss create mode 100644 app/assets/stylesheets/components/image.scss create mode 100644 app/assets/stylesheets/components/input_field.scss create mode 100644 app/assets/stylesheets/components/modal.scss create mode 100644 app/assets/stylesheets/components/nested_form.scss create mode 100644 app/assets/stylesheets/components/notification.scss create mode 100644 app/assets/stylesheets/components/outline_tabs_container.scss create mode 100644 app/assets/stylesheets/components/pill_button.scss create mode 100644 app/assets/stylesheets/components/pill_tabs_container.scss create mode 100644 app/assets/stylesheets/components/progress_pages.scss create mode 100644 app/assets/stylesheets/components/regular_button.scss create mode 100644 app/assets/stylesheets/components/rounded_button.scss create mode 100644 app/assets/stylesheets/components/search_input.scss create mode 100644 app/assets/stylesheets/components/summary_section.scss create mode 100644 app/assets/stylesheets/components/switch.scss create mode 100644 app/assets/stylesheets/components/table.scss create mode 100644 app/assets/stylesheets/components/tabs_container.scss create mode 100644 app/assets/stylesheets/components/text_area_field.scss delete mode 100644 app/assets/stylesheets/file_uploader.scss create mode 100644 app/assets/stylesheets/nav_bar.scss create mode 100644 app/components/buttons/regular_button_component.rb create mode 100644 app/components/buttons/regular_button_component/regular_button_component.html.haml create mode 100644 app/components/chip_button_component/chip_button_component.html.haml create mode 100644 app/components/circle_progress_bar_component.rb create mode 100644 app/components/circle_progress_bar_component/circle_progress_bar_component.html.haml create mode 100644 app/components/circle_progress_bar_component/circle_progress_bar_component_controller.js create mode 100644 app/components/date_time_field_component.rb create mode 100644 app/components/display/button_loader_component.rb create mode 100644 app/components/display/header_component.rb create mode 100644 app/components/display/image_component.rb create mode 100644 app/components/dropdown_button_component.rb create mode 100644 app/components/dropdown_button_component/dropdown_button_component.html.haml create mode 100644 app/components/dropdown_container_component.rb create mode 100644 app/components/dropdown_container_component/dropdown_container_component.html.haml create mode 100644 app/components/dropdown_section_button_component.rb create mode 100644 app/components/dropdown_section_button_component/dropdown_section_button_component.html.haml create mode 100644 app/components/external_link_text_component.rb create mode 100644 app/components/field_container_component.rb create mode 100644 app/components/field_container_component/field_container_component.html.haml delete mode 100644 app/components/file_input_loader_component/file_input_loader_component.html.haml create mode 100644 app/components/input/date_component.rb create mode 100644 app/components/input/email_component.rb rename app/components/{file_input_loader_component.rb => input/file_input_component.rb} (71%) create mode 100644 app/components/input/file_input_component/file_input_component.html.haml rename app/components/{file_input_loader_component => input/file_input_component}/file_input_loader_component_controller.js (100%) create mode 100644 app/components/input/input_field_component.rb create mode 100644 app/components/input/input_field_component/input_field_component.html.haml create mode 100644 app/components/input/password_component.rb create mode 100644 app/components/input/select_component.rb create mode 100644 app/components/input/select_component/select_component.html.haml create mode 100644 app/components/input/text_area_component.rb create mode 100644 app/components/input/text_area_component/text_area_component.html.haml create mode 100644 app/components/input/text_input_component.rb create mode 100644 app/components/input/url_component.rb create mode 100644 app/components/internal_link_text_component.rb create mode 100644 app/components/language_field_component.rb create mode 100644 app/components/language_field_component/language_field_component.html.haml create mode 100644 app/components/layout/card_component.rb create mode 100644 app/components/layout/horizontal_list_component.rb create mode 100644 app/components/layout/list_component.rb create mode 100644 app/components/layout/progress_pages_component.rb create mode 100644 app/components/layout/progress_pages_component/progress_pages_component.html.haml create mode 100644 app/components/layout/progress_pages_component/progress_pages_component_controller.js create mode 100644 app/components/license_field_component.rb create mode 100644 app/components/license_field_component/license_field_component.html.haml create mode 100644 app/components/link_field_component.rb create mode 100644 app/components/link_field_component/link_field_component.html.haml create mode 100644 app/components/link_text_component.rb create mode 100644 app/components/notification_component.rb create mode 100644 app/components/notification_component/notification_component.html.haml create mode 100644 app/components/ontology_search_input_component.rb create mode 100644 app/components/ontology_search_input_component/ontology_search_input_component.html.haml create mode 100644 app/components/pill_button_component.rb create mode 100644 app/components/pill_button_component/pill_button_component.html.haml create mode 100644 app/components/popup_link_text_component.rb create mode 100644 app/components/rounded_button_component.rb create mode 100644 app/components/rounded_button_component/rounded_button_component.html.haml create mode 100644 app/components/search_input_component.rb create mode 100644 app/components/search_input_component/search_input_component.html.haml create mode 100644 app/components/search_input_component/search_input_component_controller.js delete mode 100644 app/components/select_input_component/select_input_component.html.haml create mode 100644 app/components/summary_section_component.rb create mode 100644 app/components/summary_section_component/summary_section_component.html.haml create mode 100644 app/components/tab_item_component.rb create mode 100644 app/components/table_cell_component.rb create mode 100644 app/components/table_component.rb create mode 100644 app/components/table_component/table_component.html.haml create mode 100644 app/components/table_row_component.rb create mode 100644 app/components/table_row_component/table_row_component.html.haml create mode 100644 app/components/tabs_container_component.rb create mode 100644 app/components/tabs_container_component/tabs_container_component.html.haml create mode 100644 app/components/tabs_container_component/tabs_container_component_controller.js create mode 100644 app/components/text_area_field_component.rb create mode 100644 app/components/text_area_field_component/text_area_field_component.html.haml create mode 100644 app/helpers/components_helper.rb create mode 100644 app/helpers/modal_helper.rb create mode 100644 app/javascript/controllers/language_change_controller.js create mode 100644 app/javascript/controllers/ontology_viewer_tabs_controller.js create mode 100644 app/javascript/controllers/text_truncate_controller.js create mode 100644 app/javascript/controllers/topnav_responsiveness_controller.js delete mode 100644 app/views/errors/internal_server_error.html.erb create mode 100644 app/views/errors/internal_server_error.html.haml delete mode 100644 app/views/errors/not_found.html.erb create mode 100644 app/views/errors/not_found.html.haml create mode 100644 app/views/layouts/component_preview.html.erb create mode 100644 app/views/layouts/component_preview_not_centred.html.erb create mode 100644 app/views/layouts/ontology_viewer/_header.html.haml create mode 100644 lib/tasks/generate_component_previews.rake delete mode 100644 spec/components/file_input_loader_component_spec.rb create mode 100644 test/components/previews/buttons/ontology_subscribe_button_component_preview.rb create mode 100644 test/components/previews/buttons/pill_button_component_preview.rb create mode 100644 test/components/previews/buttons/regular_button_component_preview.rb create mode 100644 test/components/previews/buttons/rounded_button_component_preview.rb create mode 100644 test/components/previews/concept_details_component_preview.rb create mode 100644 test/components/previews/display/circle_progress_bar_component_preview.rb create mode 100644 test/components/previews/display/date_time_field_component_preview.rb create mode 100644 test/components/previews/display/field_container_component_preview.rb create mode 100644 test/components/previews/display/header_component_preview.rb create mode 100644 test/components/previews/display/image_component_preview.rb create mode 100644 test/components/previews/display/info_tooltip_component_preview.rb create mode 100644 test/components/previews/display/language_field_component_preview.rb create mode 100644 test/components/previews/display/license_field_component_preview.rb create mode 100644 test/components/previews/display/link_field_component_preview.rb create mode 100644 test/components/previews/display/link_text_component_preview.rb create mode 100644 test/components/previews/display/text_area_field_component_preview.rb create mode 100644 test/components/previews/input/chips_component_preview.rb create mode 100644 test/components/previews/input/input_field_component_preview.rb create mode 100644 test/components/previews/input/nested_form_input_component_preview.rb create mode 100644 test/components/previews/input/select_component_preview.rb create mode 100644 test/components/previews/input/switch_input_component_preview.rb create mode 100644 test/components/previews/layout/card_component_preview.rb create mode 100644 test/components/previews/layout/dropdown_container_component_preview.rb create mode 100644 test/components/previews/layout/list_component_preview.rb create mode 100644 test/components/previews/layout/progress_pages_component_preview.rb create mode 100644 test/components/previews/layout/summary_section_component_preview.rb create mode 100644 test/components/previews/layout/table_component_preview.rb create mode 100644 test/components/previews/layout/tabs_container_component_preview.rb create mode 100644 test/components/previews/layout/turbo_modal_component_preview.rb create mode 100644 test/components/previews/loader_component_preview.rb create mode 100644 test/components/previews/notification_component_preview.rb diff --git a/Gemfile b/Gemfile index 7de2ef3ea..6760c3e10 100644 --- a/Gemfile +++ b/Gemfile @@ -84,7 +84,7 @@ group :staging, :production, :appliance do end group :development do - # Capistrano Deployment + # Capistrano Deployment gem 'bcrypt_pbkdf', '>= 1.0', '< 2.0', require: false # https://github.com/miloserdow/capistrano-deploy/issues/42 gem 'capistrano', '~> 3.11', require: false gem 'capistrano-bundler', require: false @@ -104,6 +104,7 @@ group :development do # Use console on exceptions pages [https://github.com/rails/web-console] gem 'web-console' + gem "lookbook", '~> 1.5.5' end group :test, :development do diff --git a/Gemfile.lock b/Gemfile.lock index 866583577..637f30618 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -426,6 +426,8 @@ GEM zeitwerk (2.6.12) PLATFORMS + ruby + x86_64-darwin-21 x86_64-linux DEPENDENCIES diff --git a/app/assets/images/arrow-right-outlined.svg b/app/assets/images/arrow-right-outlined.svg new file mode 100644 index 000000000..5161a4b17 --- /dev/null +++ b/app/assets/images/arrow-right-outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/errors/agroportal.svg b/app/assets/images/errors/agroportal.svg new file mode 100644 index 000000000..f56db244a --- /dev/null +++ b/app/assets/images/errors/agroportal.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/eye.svg b/app/assets/images/eye.svg new file mode 100644 index 000000000..28889ecc3 --- /dev/null +++ b/app/assets/images/eye.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/images/icons/alert.svg b/app/assets/images/icons/alert.svg new file mode 100644 index 000000000..f944382c5 --- /dev/null +++ b/app/assets/images/icons/alert.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/assets/images/icons/arrow-left.svg b/app/assets/images/icons/arrow-left.svg new file mode 100644 index 000000000..b3c63be0d --- /dev/null +++ b/app/assets/images/icons/arrow-left.svg @@ -0,0 +1,4 @@ + + + diff --git a/app/assets/images/icons/calendar.svg b/app/assets/images/icons/calendar.svg new file mode 100644 index 000000000..7ad6a2f7a --- /dev/null +++ b/app/assets/images/icons/calendar.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/close.svg b/app/assets/images/icons/close.svg new file mode 100644 index 000000000..d3f23c98c --- /dev/null +++ b/app/assets/images/icons/close.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/assets/images/icons/delete.svg b/app/assets/images/icons/delete.svg new file mode 100644 index 000000000..0c3ed5204 --- /dev/null +++ b/app/assets/images/icons/delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/error.svg b/app/assets/images/icons/error.svg new file mode 100644 index 000000000..faf99a789 --- /dev/null +++ b/app/assets/images/icons/error.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/external-link.svg b/app/assets/images/icons/external-link.svg new file mode 100644 index 000000000..4d615c4cd --- /dev/null +++ b/app/assets/images/icons/external-link.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/info.svg b/app/assets/images/icons/info.svg new file mode 100644 index 000000000..4232099d0 --- /dev/null +++ b/app/assets/images/icons/info.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/assets/images/icons/internal-link.svg b/app/assets/images/icons/internal-link.svg new file mode 100644 index 000000000..316ccdb76 --- /dev/null +++ b/app/assets/images/icons/internal-link.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/list-tree.svg b/app/assets/images/icons/list-tree.svg new file mode 100644 index 000000000..eac310be4 --- /dev/null +++ b/app/assets/images/icons/list-tree.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/list.svg b/app/assets/images/icons/list.svg new file mode 100644 index 000000000..4c1b3ded2 --- /dev/null +++ b/app/assets/images/icons/list.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/images/icons/loop.svg b/app/assets/images/icons/loop.svg new file mode 100644 index 000000000..38a8ac694 --- /dev/null +++ b/app/assets/images/icons/loop.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/assets/images/icons/plus.svg b/app/assets/images/icons/plus.svg new file mode 100644 index 000000000..17afc626b --- /dev/null +++ b/app/assets/images/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/popup-link.svg b/app/assets/images/icons/popup-link.svg new file mode 100644 index 000000000..d094245c5 --- /dev/null +++ b/app/assets/images/icons/popup-link.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/success.svg b/app/assets/images/icons/success.svg new file mode 100644 index 000000000..8a7c34c13 --- /dev/null +++ b/app/assets/images/icons/success.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/white-check.svg b/app/assets/images/icons/white-check.svg new file mode 100644 index 000000000..9ef8028d3 --- /dev/null +++ b/app/assets/images/icons/white-check.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/app/assets/images/json.svg b/app/assets/images/json.svg new file mode 100644 index 000000000..e7f7e8898 --- /dev/null +++ b/app/assets/images/json.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/assets/images/list-tree.svg b/app/assets/images/list-tree.svg deleted file mode 100644 index 4180dac32..000000000 --- a/app/assets/images/list-tree.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/images/logo-white.svg b/app/assets/images/logo-white.svg new file mode 100644 index 000000000..f920cd7de --- /dev/null +++ b/app/assets/images/logo-white.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/assets/images/logos/ontoportal.svg b/app/assets/images/logos/ontoportal.svg new file mode 100644 index 000000000..dfb0838d3 --- /dev/null +++ b/app/assets/images/logos/ontoportal.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/orange-warning.svg b/app/assets/images/orange-warning.svg new file mode 100644 index 000000000..bebb56764 --- /dev/null +++ b/app/assets/images/orange-warning.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/assets/images/social/github.svg b/app/assets/images/social/github.svg new file mode 100644 index 000000000..9f2ef1737 --- /dev/null +++ b/app/assets/images/social/github.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/assets/images/social/people.svg b/app/assets/images/social/people.svg new file mode 100644 index 000000000..85f1d5fd0 --- /dev/null +++ b/app/assets/images/social/people.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/assets/images/social/twitter.svg b/app/assets/images/social/twitter.svg new file mode 100644 index 000000000..162e21ae2 --- /dev/null +++ b/app/assets/images/social/twitter.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/images/summary/arrow-down.svg b/app/assets/images/summary/arrow-down.svg new file mode 100644 index 000000000..b07860eea --- /dev/null +++ b/app/assets/images/summary/arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/update.svg b/app/assets/images/update.svg new file mode 100644 index 000000000..29d1f5bcb --- /dev/null +++ b/app/assets/images/update.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/upload-file.svg b/app/assets/images/upload-file.svg new file mode 100644 index 000000000..0693d1e9b --- /dev/null +++ b/app/assets/images/upload-file.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/assets/stylesheets/account.scss b/app/assets/stylesheets/account.scss index 3112a95d4..775a8a89c 100644 --- a/app/assets/stylesheets/account.scss +++ b/app/assets/stylesheets/account.scss @@ -3,7 +3,9 @@ display: flex; justify-content: center; margin: 30px 0; - +} +.account-page-center svg path{ + fill: var(--primary-color) } .account-page-title{ font-size: 18px; @@ -131,10 +133,6 @@ margin-left: 10px; margin-bottom: 5px; } -svg path{ - fill: var(--primary-color); -} - .account-page-subscribe-button{ border: 1px solid var(--primary-color); text-decoration: none; diff --git a/app/assets/stylesheets/application.css.scss.erb b/app/assets/stylesheets/application.css.scss.erb index d78bb5977..fc88dc9a4 100644 --- a/app/assets/stylesheets/application.css.scss.erb +++ b/app/assets/stylesheets/application.css.scss.erb @@ -41,14 +41,16 @@ @import "ontolobridge"; @import "fair_assement"; @import "instances_table"; -@import "file_uploader"; @import "register"; @import "lostpassword"; @import "flatpickr/dist/themes/light"; +@import "tom-select/dist/scss/tom-select"; @import "feedback"; @import "login"; @import "components/index"; @import "account"; +@import "ontology_details_header"; +@import "nav_bar"; @import "browse"; /* Bootstrap and Font Awesome */ diff --git a/app/assets/stylesheets/bioportal.scss b/app/assets/stylesheets/bioportal.scss index fa186b2ea..67a8682a4 100644 --- a/app/assets/stylesheets/bioportal.scss +++ b/app/assets/stylesheets/bioportal.scss @@ -1163,6 +1163,9 @@ a.truncated_less, a.truncated_more { .highlighted .search_ontology_acronym { color: white; } +.hide { + display: none !important; +} .empty-state { display: none; @@ -1179,3 +1182,7 @@ turbo-frame[busy] .hide-if-loading, .show-if-loading { turbo-frame[busy] ~ .show-if-loading { display: inline-block; } + +.hide{ + display:none; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/card.scss b/app/assets/stylesheets/components/card.scss new file mode 100644 index 000000000..825f227cf --- /dev/null +++ b/app/assets/stylesheets/components/card.scss @@ -0,0 +1,5 @@ +.summary-card { + border: 1px solid #dfdfdf; + border-radius: 5px; + margin-top: 20px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/card_message.scss b/app/assets/stylesheets/components/card_message.scss index 0201775d3..9d3332a1c 100644 --- a/app/assets/stylesheets/components/card_message.scss +++ b/app/assets/stylesheets/components/card_message.scss @@ -34,6 +34,10 @@ color: #EE404C !important; border: 1px solid #EE404C; } +.card-message-button-warning { + color: #ff6700 !important; + border: 1px solid #ff6700; +} .card-message-has-title{ color: #666666; font-weight: 400; diff --git a/app/assets/stylesheets/components/chip_button.scss b/app/assets/stylesheets/components/chip_button.scss new file mode 100644 index 000000000..e795c43cc --- /dev/null +++ b/app/assets/stylesheets/components/chip_button.scss @@ -0,0 +1,27 @@ +.chip_button_container { + background-color: #f6f6f6; + padding: 10px; + border-radius: 5px; + color: #777777 !important; + font-weight: 500; + font-size: 15px; + line-height: 44px; + display: inline; +} + +.chip_button_small{ + font-size: 10px; + padding: 5px; + line-height: unset; +} + +.chip_button_container_clickable { + background-color: var(--light-color); + line-height: 44px; + padding: 10px; + border-radius: 5px; + color: var(--primary-color); + font-weight: 500; + font-size: 15px; + cursor: grab; +} diff --git a/app/assets/stylesheets/components/circle_progress_bar.scss b/app/assets/stylesheets/components/circle_progress_bar.scss new file mode 100644 index 000000000..7c5095a64 --- /dev/null +++ b/app/assets/stylesheets/components/circle_progress_bar.scss @@ -0,0 +1,26 @@ +:root { + --circle-progress-bar-width: 50px; + --circle-progress-bar-height: 50px; +} + +.circular-progress { + width: var(--circle-progress-bar-width); + height: var(--circle-progress-bar-height); + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + position: relative; +} +.inner-circle { + position: absolute; + width: 85%; + height: 85%; + border-radius: 50%; +} + +.percentage { + position: relative; + color: rgba(0, 0, 0, 0.8); + margin-bottom: 0; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/concept_details.scss b/app/assets/stylesheets/components/concept_details.scss new file mode 100644 index 000000000..7ae6fef43 --- /dev/null +++ b/app/assets/stylesheets/components/concept_details.scss @@ -0,0 +1,11 @@ + +.concept_details_component .raw-table .dropdown-title-bar p { + padding: 10px 0px; + color: rgb(136, 136, 136); + font-weight: 400; +} + + +.concept_details_component table th { + width: 220px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/dropdown.scss b/app/assets/stylesheets/components/dropdown.scss new file mode 100644 index 000000000..b9c73b7f4 --- /dev/null +++ b/app/assets/stylesheets/components/dropdown.scss @@ -0,0 +1,17 @@ +.dropdown-title-bar { + display: flex; + align-items: center; + font-weight: 550; + justify-content: space-between; + font-size: 16px; + color: #000000; + cursor: pointer; + padding: 0 14px 0 0; +} + +.dropdown-container { + border: 1px solid #dfdfdf; + border-radius: 5px; + margin-bottom: 20px; + margin-top: 20px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/field_container.scss b/app/assets/stylesheets/components/field_container.scss new file mode 100644 index 000000000..cd2b46ea7 --- /dev/null +++ b/app/assets/stylesheets/components/field_container.scss @@ -0,0 +1,23 @@ +.field-container { + margin-bottom: 0.5rem; +} + + +.field-description_text, +.field-description_text a { + color: #888888 !important; + font-size: 15px; + margin-bottom: 0; +} + +.field-description_text { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: var(--read-more-line-clamp, 5); +} + +.field-normal_text { + font-size: 15px; + color: black; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/file_input_loader.scss b/app/assets/stylesheets/components/file_input_loader.scss new file mode 100644 index 000000000..029ab9f71 --- /dev/null +++ b/app/assets/stylesheets/components/file_input_loader.scss @@ -0,0 +1,54 @@ +.file_uploader { + color: #D7D7EF; + font-family: 'Lato', sans-serif; + border: 1px dashed #CFCFCF; + border-radius: 5px; +} + +.file-message { + display: flex; + margin-top: 10px; + font-size: 12px; + color: #888888; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.file_uploader>h2 { + margin: 50px 0; +} + +.file-drop-area { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + padding: 25px; + transition: 0.2s; + position: relative; +} + +.choose-file-button { + flex-shrink: 0; + background-color: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 3px; + padding: 8px 15px; + margin-right: 10px; + font-size: 12px; + text-transform: uppercase; +} + +.file-input { + height: 100%; + width: 100%; + cursor: pointer; + opacity: 0; + position: absolute; +} + +.file-drop-area svg path { + fill: #CECECE; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/header.scss b/app/assets/stylesheets/components/header.scss new file mode 100644 index 000000000..30e464aba --- /dev/null +++ b/app/assets/stylesheets/components/header.scss @@ -0,0 +1,15 @@ +.header-component { + display: flex; + align-items: center; + margin-bottom: 5px; + font-weight: 550; + justify-content: space-between; + font-size: 16px; + color: #000000; + cursor: pointer; + width: 100%; + padding: 14px 20px; + p { + margin-bottom: 0; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/image.scss b/app/assets/stylesheets/components/image.scss new file mode 100644 index 000000000..97414ab03 --- /dev/null +++ b/app/assets/stylesheets/components/image.scss @@ -0,0 +1,22 @@ +.image-container { + position: relative; + .image-content{ + width: 100%; + object-fit: scale-down; + margin-bottom: 30px; + } + .loop_icon { + position: absolute; + width: 50px; + background-color: white; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + height: 50px; + padding: 10px; + bottom: 0; + right: 0; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/index.scss b/app/assets/stylesheets/components/index.scss index c61d4d8dc..23f4da20f 100644 --- a/app/assets/stylesheets/components/index.scss +++ b/app/assets/stylesheets/components/index.scss @@ -1,2 +1,27 @@ @import 'chips'; -@import 'card_message' \ No newline at end of file +@import 'card_message'; +@import "notification"; +@import 'chip_button'; +@import 'rounded_button'; +@import 'summary_section'; +@import 'dropdown'; +@import 'field_container'; +@import 'modal'; +@import 'search_input'; +@import 'nested_form'; +@import 'circle_progress_bar'; +@import 'input_field'; +@import 'file_input_loader'; +@import 'text_area_field'; +@import 'regular_button'; +@import 'tabs_container'; +@import 'pill_tabs_container'; +@import 'outline_tabs_container'; +@import 'pill_button'; +@import "switch"; +@import "table"; +@import "concept_details"; +@import "card"; +@import "header"; +@import "image"; +@import "progress_pages"; \ No newline at end of file diff --git a/app/assets/stylesheets/components/input_field.scss b/app/assets/stylesheets/components/input_field.scss new file mode 100644 index 000000000..9a5ad99c9 --- /dev/null +++ b/app/assets/stylesheets/components/input_field.scss @@ -0,0 +1,69 @@ +.input-field-component { + width: 100%; + font-size: 13px; + padding: 10px; + border: 1px solid #BDBDBD; + border-radius: 5px; + outline: none; + resize: none; +} + +.input-field-component:focus { + border: 1px solid var(--primary-color); +} + +.text-input-label { + font-size: 12px; + color: #666666; + margin-bottom: 5px; +} + +.text-input-error-text { + font-size: 12px; + color: var(--error-color) +} + +.text-input-helper-text { + font-size: 12px; + color: #666666; + margin-top: 5px; +} + +.ts-control { + padding: 12px; + border-radius: 5px; + border-color: #BDBDBD; +} + +.ts-dropdown-content .option { + padding: 12px; +} + +.ts-dropdown .active { + background-color: #f8f8f8; + +} + +.ts-dropdown { + margin: 0; + color: #666666; +} + +.chosen-container { + padding: 0; + border-radius: 5px; +} + +.ts-wrapper.single .ts-control:after { + border-color: #343a40 transparent transparent; + border-style: solid; + border-width: 5px 5px 0; + content: " "; + display: block; + height: 0; + margin-top: -3px; + position: absolute; + right: calc(0.75rem + 5px); + top: 50%; + width: 0; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/modal.scss b/app/assets/stylesheets/components/modal.scss new file mode 100644 index 000000000..2997e12e7 --- /dev/null +++ b/app/assets/stylesheets/components/modal.scss @@ -0,0 +1,20 @@ +.modal-content{ + border-radius: 20px !important; +} + +.modal-title { + text-align: center; + flex: 1px; +} + +.close { + margin-left: 0px; + &:focus{ + outline: none; + } +} + +.shape { + border-radius: 50% !important; + width: 35px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/nested_form.scss b/app/assets/stylesheets/components/nested_form.scss new file mode 100644 index 000000000..137efc358 --- /dev/null +++ b/app/assets/stylesheets/components/nested_form.scss @@ -0,0 +1,50 @@ +.nested-form-input-container .titles{ + display: flex; + font-size: 11px; + color: #666666; + margin-bottom: 5px; + width: 90%; +} + + +.nested-form-input-container input:focus{ + border: 1px solid var(--primary-color) !important; +} + +.nested-form-input-container .delete{ + display: flex; + border: 1px dashed #BDBDBD; + justify-content: center; + align-items: center; + height: 43px; + width: 43px; + border-radius: 5px; + cursor: pointer; +} + +.nested-form-input-container .add-another-object{ + border: 1px dashed #BDBDBD; + border-radius: 5px; + display: flex; + justify-content: center; + align-items: center; + padding: 10px; + cursor: pointer; + margin-top: 10px; +} +.nested-form-input-container svg path{ + fill: #DADADA; +} +.nested-form-input-container .add-another-object div{ + color: #DADADA; + margin-left: 10px; +} + + + + + + + + + diff --git a/app/assets/stylesheets/components/notification.scss b/app/assets/stylesheets/components/notification.scss new file mode 100644 index 000000000..fafecc190 --- /dev/null +++ b/app/assets/stylesheets/components/notification.scss @@ -0,0 +1,146 @@ +.notification { + display: flex; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 50; + padding: 1.5rem 1rem; + justify-content: center; + align-items: flex-end; + pointer-events: none; + transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform; + transition-duration: 1000ms; + transform: translateX(1rem); + opacity: 0; + @media (min-width: 640px) { + padding: 4rem 1.5rem 1.5rem; + justify-content: flex-end; + align-items: flex-start; + } +} + + +.notification-inner { + overflow: hidden; + padding: 1rem; + background-color: #ffffff; + width: 100%; + max-width: 24rem; + border-radius: 0.5rem; + pointer-events: auto; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); +} + +.notification-content { + display: flex; + align-items: flex-start; +} + +.notification-content svg { + width: 1.5rem; + height: 1.5rem; +} + +.notification-text { + padding-top: 0.125rem; + margin-left: 0.75rem; + flex: 1 1 0; + width: 0; +} + +.notification-text p:first-of-type { + color: #111827; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; +} + +.notification-text p:last-of-type { + margin-top: 0.25rem; + color: #6B7280; + font-size: 0.875rem; + line-height: 1.25rem; +} + +.notification-close { + display: inline-flex; + background-color: #ffffff; + color: #9CA3AF; + border: none; + cursor: pointer; +} + +.notification-close svg { + height: 1rem; + outline: none; +} + +.type-success path { + fill: #14a38c; +} + +.type-error { + path:first-of-type { + fill: #f44336; + } + + path { + fill: white; + } +} + +.type-alert path { + fill: #edb464; +} + + +.slide-in-right { + animation-name: slide-in-right; + animation-duration: 0.5s; + animation-delay: 0.5s; + animation-timing-function: cubic-bezier(0.250, 0.460, 0.450, 0.940); + animation-fill-mode: forwards; +} + + +.slide-in-out-right { + animation-name: slide-in-right, slide-out-right; + animation-duration: 0.5s, 0.5s; + animation-delay: 0.5s, 5s; + animation-timing-function: cubic-bezier(0.250, 0.460, 0.450, 0.940), cubic-bezier(0.550, 0.085, 0.680, 0.530); + animation-fill-mode: forwards, forwards; +} + + +@keyframes slide-in-right { + 0% { + transform: translateX(1rem); + opacity: 0; + } + 50% { + opacity: 0.4; + } + 100% { + transform: translateX(0); + opacity: 1; + } +} + +@keyframes slide-out-right { + 0% { + transform: translateX(0); + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + transform: translateX(1rem); + opacity: 0; + } +} + + + diff --git a/app/assets/stylesheets/components/outline_tabs_container.scss b/app/assets/stylesheets/components/outline_tabs_container.scss new file mode 100644 index 000000000..76c390d92 --- /dev/null +++ b/app/assets/stylesheets/components/outline_tabs_container.scss @@ -0,0 +1,27 @@ + +.outline-tabs{ + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25rem 0.25rem 0 0; + padding-top: 1rem; +} +.outline-tabs .tab-items .nav-item{ + margin-right: 0; + +} + +.outline-tabs .tab-items .nav-item.active a{ + color: var(--primary-color) !important; +} + +.outline-tabs .nav-item .tab-link{ + display: block; + padding: 0 1rem 0.2rem 1rem; +} + +.outline-tabs + .tab-content { + .tab-pane{ + border: 1px solid rgba(0, 0, 0, 0.125); + border-top: none ; + border-radius: 0 0 0.25rem 0.25rem; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/pill_button.scss b/app/assets/stylesheets/components/pill_button.scss new file mode 100644 index 000000000..a7060d77f --- /dev/null +++ b/app/assets/stylesheets/components/pill_button.scss @@ -0,0 +1,33 @@ +.pill-button { + color: var(--primary-color); + font-size: 15px; + display: flex; + align-items: center; + border: 1px solid var(--primary-color); + border-radius: 32px; + padding: 10px 20px; + cursor: pointer; + margin-left: 10px; + transition: background-color ease 0.3s; + white-space: nowrap; + background-color: transparent; + &:focus{ + outline: none; + } +} + +.pill-button:hover { + background-color: var(--primary-color); + color: white !important; + a { + color: white !important; + } +} + +.pill-button:hover svg path { + fill: white; +} + +.pill-button svg { + margin-right: 10px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/pill_tabs_container.scss b/app/assets/stylesheets/components/pill_tabs_container.scss new file mode 100644 index 000000000..e03697544 --- /dev/null +++ b/app/assets/stylesheets/components/pill_tabs_container.scss @@ -0,0 +1,22 @@ +.pill-tabs-container { + display: flex; + justify-content: space-between; +} + +.pill-tabs-container .tab-items{ + margin-bottom: 10px; +} + +.pill-tabs-container .nav-item { + display: block; + padding: 0.2rem 1rem; +} + +.pill-tabs-container .nav-item.active { + border-radius: 5px; + background-color: var(--primary-color); + color: white !important; + a { + color: white !important; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/progress_pages.scss b/app/assets/stylesheets/components/progress_pages.scss new file mode 100644 index 000000000..6e3f6cff5 --- /dev/null +++ b/app/assets/stylesheets/components/progress_pages.scss @@ -0,0 +1,118 @@ +.progress-pages-container { + display: flex; + align-items: center; + margin-top: 20px; + margin-bottom: 50px; + width: 100%; +} + +.progress-pages-container hr { + flex-grow: 1; + border: 1px solid #D9D9D9; + margin: 0; +} + +.progress-pages-container hr.active { + border: 1px solid var(--primary-color); +} + +.progress-pages-container .progress-item { + position: relative; + & > div { + position: absolute; + top: -13px; + left: -13px; + display: flex; + flex-direction: column; + align-items: center; + } +} + +.progress-pages-container .progress-item:first-of-type { + & > div { + align-items: start; + left: 0; + } +} + +.progress-pages-container .progress-item:last-of-type { + & > div { + align-items: end; + left: -23px; + } +} + +.progress-pages-container .progress-item div .active:nth-child(2) { + color: var(--primary-color); + font-weight: 600; +} + +.progress-pages-container .progress-item div span:nth-child(2) { + position: absolute; + font-size: 12px; + top: 33px; + white-space: nowrap; + color: #A9A9A9; +} + +.progress-pages-container .progress-content .active:nth-child(2) { + color: var(--primary-color); + font-weight: 600; +} + +.progress-pages-container .progress-content div:nth-child(2) { + position: absolute; + right: -38px; + top: 33px; + +} + + + +.outlined-checked-circle { + border: 2px solid var(--primary-color) !important; + background-color: var(--primary-color) !important; + display: flex; + align-items: center; + justify-content: center; +} + +.outlined-active-circle { + border: 2px solid var(--primary-color) !important; +} + +.outlined-circle { + border: 1px solid #D9D9D9; + border-radius: 13px; + height: 26px; + width: 26px; + background-color: white; + +} + +.outlined-checked-circle img { + display: block !important; +} + +.outlined-active-circle img { + display: none; +} + +.outlined-circle img { + display: none; +} + + + +.progress-pages-actions { + display: flex; + justify-content: flex-end; + margin-top: 20px; +} + +.progress-pages-next-button { + margin-left: 25px; +} + + + diff --git a/app/assets/stylesheets/components/regular_button.scss b/app/assets/stylesheets/components/regular_button.scss new file mode 100644 index 000000000..954165297 --- /dev/null +++ b/app/assets/stylesheets/components/regular_button.scss @@ -0,0 +1,211 @@ +.regular-button { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + font-size: 16px; + height: 60px; + border-radius: 9px; + padding: 0 30px; +} +.regular-button.slim{ + border-radius: 5px; + height: 42px; + padding: 0 15px; +} + +.primary-button { + color: white !important; + background-color: var(--primary-color); + border: none; + transition: background-color ease 0.3s; +} +.primary-button:focus { + outline: none; +} + +.primary-button:hover { + background-color: var(--hover-color); + cursor: pointer; +} + +.primary-button.disabled-button{ + background-color: #a3a3a3; +} +.primary-button.disabled-button:hover { + background-color: #a3a3a3; + cursor:default; +} + +.danger-button.primary-button { + background-color: #F24C3D !important; +} + +.danger-button.primary-button:hover { + background-color: #d74639 !important; +} + +.warning-button.primary-button { + background-color: #F2BE22 !important; +} + +.warning-button.primary-button:hover { + background-color: #dcac1d !important; +} + +.secondary-button { + color: var(--primary-color); + border: 1px solid var(--primary-color); + transition: background-color ease 0.3s; + background-color: rgba(0, 0, 0, 0) !important; +} + +.secondary-button:focus { + outline: none; +} + +.secondary-button:hover { + background-color: var(--primary-color) !important; + cursor: pointer; + color: white !important; + + .secondary-button-icon path { + fill: white; + } +} + +.secondary-button.disabled-button { + border: 1px solid #a3a3a3; + color: #a3a3a3 !important; +} + +.secondary-button.disabled-button:hover { + background-color: rgba(0, 0, 0, 0) !important; + cursor: default; + color: #a3a3a3 !important; +} + +.secondary-button.danger-button { + color: #F24C3D !important; + border: 1px solid #F24C3D; +} +.secondary-button.danger-button:hover { + background-color: #F24C3D !important; + color: white !important; +} +.secondary-button.warning-button { + color: #F2BE22 !important; + border: 1px solid #F2BE22; +} + +.secondary-button.warning-button:hover { + background-color: #dcac1d !important; + color: white !important; +} + +.left-button-icon{ + margin-right: 10px; +} + +.right-button-icon { + margin-left: 10px; +} + +.secondary-button-icon path { + fill: var(--primary-color); +} + +.primary-button-icon path { + fill: white; +} + + +.animation-container { + width: 100%; + height: 60px; + font-size: 16px; + background-color: var(--hover-color); + border: none; + border-radius: 9px; + justify-content: center; + align-items: center; + display: none; +} +.animation-container.slim { + border-radius: 5px; + height: 42px; +} +.animation-container.danger-button{ + background-color: #d74639 !important; +} +.animation-container.warning-button{ + background-color: #dcac1d !important; +} + +.lds-ellipsis { + display: inline-block; + position: relative; + margin-top: 50px; + width: 80px; + height: 80px; + transform: scale(0.7); +} + +.lds-ellipsis div { + position: absolute; + width: 13px; + height: 13px; + border-radius: 50%; + background: white; + animation-timing-function: cubic-bezier(0, 1, 1, 0); +} + +.lds-ellipsis div:nth-child(1) { + left: 8px; + animation: lds-ellipsis1 0.6s infinite; +} + +.lds-ellipsis div:nth-child(2) { + left: 8px; + animation: lds-ellipsis2 0.6s infinite; +} + +.lds-ellipsis div:nth-child(3) { + left: 32px; + animation: lds-ellipsis2 0.6s infinite; +} + +.lds-ellipsis div:nth-child(4) { + left: 56px; + animation: lds-ellipsis3 0.6s infinite; +} + +@keyframes lds-ellipsis1 { + 0% { + transform: scale(0); + } + + 100% { + transform: scale(1); + } +} + +@keyframes lds-ellipsis3 { + 0% { + transform: scale(1); + } + + 100% { + transform: scale(0); + } +} + +@keyframes lds-ellipsis2 { + 0% { + transform: translate(0, 0); + } + + 100% { + transform: translate(24px, 0); + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/rounded_button.scss b/app/assets/stylesheets/components/rounded_button.scss new file mode 100644 index 000000000..41e2b7695 --- /dev/null +++ b/app/assets/stylesheets/components/rounded_button.scss @@ -0,0 +1,17 @@ +.rounded-button { + border: 1px solid var(--primary-color); + display: flex; + align-items: center; + justify-content: center; + right: 40px; + transition: background-color ease 0.3s; +} + +.rounded-button:hover { + background-color: var(--primary-color); + +} + +.rounded-button:hover svg path { + fill: white; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/search_input.scss b/app/assets/stylesheets/components/search_input.scss new file mode 100644 index 000000000..e54d877ea --- /dev/null +++ b/app/assets/stylesheets/components/search_input.scss @@ -0,0 +1,48 @@ +.search-container{ + display: none; + font-size: 16px; + background: white; + width: 100%; + border-radius: 0 0 14px 14px; + border: none; + box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1); +} + +.search-content{ + display: flex; + color: #777777 !important; + justify-content: space-between; + padding: 20px 20px; + cursor: pointer; + border-top: 1px solid #f7f7f7 +} +.search-content:hover{ + background-color: rgba(0, 0, 0, 0.01); +} +.search-content div{ + display: flex; +} +.search-content div img{ + width: 12px; +} +.search-content div p{ + font-weight: 300; + margin-left: 10px; + margin-bottom: 0; +} + +.search-dropdown-active{ + box-shadow: none !important; +} + +.search-element{ + margin-bottom: 0; +} + +.searched-elements{ + margin-bottom: 0; +} + +.search-inputs input { + @extend .form-control !optional; +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/summary_section.scss b/app/assets/stylesheets/components/summary_section.scss new file mode 100644 index 000000000..9592f305b --- /dev/null +++ b/app/assets/stylesheets/components/summary_section.scss @@ -0,0 +1,13 @@ +.card_title { + display: flex; + font-size: 18px; + margin-top: 40px; + margin-bottom: 20px; + + span:nth-child(1){ + text-decoration: underline; + text-underline-offset: 12px; + text-decoration-color: var(--primary-color); + text-decoration-thickness: 2px; + } +} diff --git a/app/assets/stylesheets/components/switch.scss b/app/assets/stylesheets/components/switch.scss new file mode 100644 index 000000000..5a70e0fe9 --- /dev/null +++ b/app/assets/stylesheets/components/switch.scss @@ -0,0 +1,64 @@ + +.switch-filter{ + display:flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20px; +} +.switch-filter p{ + font-size: 16px; + color: #666666; + margin-bottom: 0; + margin-right: 10px; +} + + + +/* Toggle switch css */ +.switch { + position: relative; + display: inline-block; + width: 40px; + height: 20px; + margin-bottom: 0; +} +.switch input { + opacity: 0; + width: 0; + height: 0; +} +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; + border-radius: 34px; +} +.slider:before { + position: absolute; + content: ""; + height: 13px; + width: 13px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; + border-radius: 50%; +} +input:checked + .slider { + background-color: var(--primary-color); +} +input:focus + .slider { + box-shadow: 0 0 1px var(--primary-color); +} +input:checked + .slider:before { + -webkit-transform: translateX(19px); + -ms-transform: translateX(19px); + transform: translateX(19px); +} \ No newline at end of file diff --git a/app/assets/stylesheets/components/table.scss b/app/assets/stylesheets/components/table.scss new file mode 100644 index 000000000..27869d6ee --- /dev/null +++ b/app/assets/stylesheets/components/table.scss @@ -0,0 +1,37 @@ +.table-content{ + border-collapse: collapse; + width: 100%; + border-spacing: 0; +} + +.table-layout-fixed{ + table-layout: fixed; +} + +.table-content thead th{ + background-color: hsl(0, 0%, 100%); + border-bottom: 1px solid hsl(240, 4%, 85%); + font-weight: 700; + color: hsl(230, 13%, 9%); +} + +.table-content-borderless thead th { + border-bottom: none !important; +} + +.table-content td, .table-content th{ + padding: 0.75rem; + vertical-align: top; +} + + +.table-content-stripped tbody tr:nth-child(odd) { + background-color: #FAFAFA; +} + +.table-content tbody th:first-child { + color: #888888; + font-weight: 400; +} + + diff --git a/app/assets/stylesheets/components/tabs_container.scss b/app/assets/stylesheets/components/tabs_container.scss new file mode 100644 index 000000000..422a29872 --- /dev/null +++ b/app/assets/stylesheets/components/tabs_container.scss @@ -0,0 +1,57 @@ +.tabs-container { + border-bottom: 1px solid #DFDFDF; + display: flex; + justify-content: space-between; + & > div { + display: flex; + justify-content: space-between; + width: 100%; + } +} + +.tabs-container hr { + border: 1px solid #f3f3f3; + width: 100%; + margin: 0; +} + +.tabs-container .tab-items { + display: flex; + margin: 0; + position: relative; +} + +.tabs-container .tab-items div { + font-size: 16px; + font-weight: 400; + color: #5e5e5e; + margin-right: 50px; + cursor: pointer; + opacity: 60%; + transition: opacity 0.3s ease; + + a { + color: #5e5e5e !important; + } +} + +.tabs-container .tab-items div:hover { + + opacity: 100%; +} + +.tabs-container .tab-items div hr { + display: none; + margin-top: 10px; +} + +.tabs-container .tab-items .active { + font-weight: 500; + opacity: 100%; +} + +.tabs-container .tab-items .active hr { + display: block; + border: 1px solid var(--primary-color); + opacity: 100%; +} diff --git a/app/assets/stylesheets/components/text_area_field.scss b/app/assets/stylesheets/components/text_area_field.scss new file mode 100644 index 000000000..6f50aa4bc --- /dev/null +++ b/app/assets/stylesheets/components/text_area_field.scss @@ -0,0 +1,14 @@ +.text-content { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: var(--read-more-line-clamp, 5); +} + + +.see_more_text { + color: var(--primary-color); + font-size: 15px; + margin-top: 10px; + text-align: end; +} \ No newline at end of file diff --git a/app/assets/stylesheets/concepts.scss b/app/assets/stylesheets/concepts.scss index 7f3bc860d..ee9b298cb 100644 --- a/app/assets/stylesheets/concepts.scss +++ b/app/assets/stylesheets/concepts.scss @@ -14,7 +14,7 @@ } a.btn.btn-link { - padding: 0; + padding: 0; } } diff --git a/app/assets/stylesheets/file_uploader.scss b/app/assets/stylesheets/file_uploader.scss deleted file mode 100644 index 96c03f823..000000000 --- a/app/assets/stylesheets/file_uploader.scss +++ /dev/null @@ -1,53 +0,0 @@ -.file_uploader { - color: #D7D7EF; - font-family: 'Lato', sans-serif; -} - -.file_uploader > h2 { - margin: 50px 0; -} - - -.file-drop-area { - position: relative; - display: flex; - align-items: center; - width: 450px; - max-width: 100%; - padding: 25px; - border: 1px dashed rgba(255, 255, 255, 0.4); - border-radius: 3px; - transition: 0.2s; - -} - -.choose-file-button { - flex-shrink: 0; - background-color: rgba(255, 255, 255, 0.04); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 3px; - padding: 8px 15px; - margin-right: 10px; - font-size: 12px; - text-transform: uppercase; -} - -.file-message { - font-size: small; - font-weight: 300; - line-height: 1.4; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.file-input { - position: absolute; - left: 0; - top: 0; - height: 100%; - width: 100%; - cursor: pointer; - opacity: 0; - -} \ No newline at end of file diff --git a/app/assets/stylesheets/footer.scss b/app/assets/stylesheets/footer.scss index 927971394..dec58f53f 100644 --- a/app/assets/stylesheets/footer.scss +++ b/app/assets/stylesheets/footer.scss @@ -1,3 +1,55 @@ -.legal-text { - font-size: 0.9rem; -} \ No newline at end of file +.footer-container{ + display: flex; + justify-content: center; + background-color: var(--primary-color); +} +footer{ + width: 1280px; + background-color: var(--primary-color); + padding: 40px 100px; +} + +.footer-header{ + display: flex; + justify-content: space-between; + margin-bottom: 40px; +} +.footer-logo{ + color: white; + display: flex; + align-items: center; +} +.footer-logo p{ + margin-bottom: 0; + font-weight: 700; + font-size: 18px; + margin-left: 20px; +} +.footer-social-media-links a{ + margin-left: 20px; +} +.footer-nav-links{ + display: flex; + flex-wrap: wrap; + justify-content: space-between; +} +.footer-nav-links div h2{ + font-size: 21px; + font-weight: 700; + color: white; + margin-bottom: 10px; +} +.footer-nav-links div div{ + display:flex; + flex-direction: column; +} +.footer-nav-links div a{ + font-size: 16px; + font-weight: 400; + color: white !important; + margin-bottom: 10px; + opacity: 60%; +} +.footer-nav-links div a:hover{ + opacity: 100%; +} diff --git a/app/assets/stylesheets/home.scss b/app/assets/stylesheets/home.scss index f26409b71..562a5575c 100644 --- a/app/assets/stylesheets/home.scss +++ b/app/assets/stylesheets/home.scss @@ -2,3 +2,460 @@ i.fa.fa-caret-square-o-down { vertical-align: middle; margin-left: 2px; } + + + +.home-header-container{ + height: 310px; +} + +.home-header-background{ + background-color: var(--primary-color);; + width: 100%; + height: 309px; + position: absolute; + z-index: 0; +} + +.home-bubbles{ + display: flex; + justify-content: center; +} +.home-bubble{ + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + background-color: rgba(255, 255, 255, 0.4); + position: absolute; + box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.05); + transform: scale(0.1); + animation: scale-up 1s ease forwards; +} +.home-bubble-one{ + width: 232px; + height: 232px; + border-radius: 116px; + z-index: 1; + margin-left: 622px; +} +.home-bubble-two{ + width: 194px; + height: 194px; + border-radius: 97px; + z-index: 2; + margin-left: 387px; + margin-top: 161px; +} +.home-bubble-three{ + width: 130px; + height: 130px; + border-radius: 65px; + z-index: 3; + margin-left: 656px; + margin-top: 192px; +} +.home-bubble-four{ + width: 70px; + height: 70px; + border-radius: 35px; + z-index: 4; + margin-left: 815px; + margin-top: 189px; + transform: scale(1); + +} + +.home-bubble h5{ + color: white; + font-size: 18px; + margin: 0; + font-weight: 600; +} +.home-bubble p{ + color: white; + font-size: 15px; + margin: 0; +} +.home-random-bubbles{ + position: absolute; + transform: scale(0.1); + animation: scale-up-random 1s ease forwards; +} +.home-header-title-container{ + display: flex; + justify-content: center; +} +.home-header-title{ + position: absolute; + z-index: 4; + width: 481px; + margin-right: 664px; + margin-top: 123px; + opacity: 0; + transform: translateY(-100%); + animation: slide-and-fade 1s ease forwards; +} +.home-header-title h4{ + font-size: 40px; + font-weight: 800; + color: white; +} + +.home-header-title > p{ + font-size: 20px; + font-weight: 400; + color: white; +} + +.home-header-title input{ + font-size: 16px; + outline: none; + padding: 20px; + width: 100%; + margin-top: 20px; + border-radius: 14px; + border: none; + box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1); +} +.home-header-title input:focus{ + box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.15); +} + + +.home-body-container{ + display: flex; + flex-direction: column; + align-items: center; +} +.home-section{ + margin-top: 70px; + width: 1138px; +} +.home-section > h4{ + font-size: 20px; + margin-bottom: 5px; + font-weight: 700; +} + +.home-section-line{ + width: 60px; + margin-top: 3px; + border: 0.5px solid var(--primary-color);; + border-radius: 5px; + margin-bottom: 20px; +} +.home-statistics{ + display: flex; + justify-content: space-between; +} +.home-statistics-container{ + border-radius: 8px; + box-shadow: 2px 0px 60px rgba(0, 0, 0, 0.10); + padding: 30px 40px; + +} +.home-statistics-container > div { + display: flex; + align-items: center; + +} +.home-agroportal-figures{ + margin-bottom: 20px; +} + +.home-statistics-container > div > p { + font-size: 20px; + font-weight: 600; + margin-left: 18px; + margin-bottom: 0; +} +.home-statistics-item{ + display: flex; + align-items: center; + +} +.home-statistics-item hr{ + height: 83px; + width: 0px; + border: 2px solid var(--primary-color);; + border-radius: 5px; + margin-right: 15px; + margin-top: 0; + margin-bottom: 0; +} +.home-statistics-item h4{ + font-size: 30px; + font-weight: 600; + line-height: 1.2; + margin: 0; +} +.home-statistics-item p{ + font-size: 18px; + font-weight: 400; + margin: 0; + color: #888; +} +.home-section > p { + font-size: 16px; + color: #888888; + margin-bottom: 9px; +} +.home-upload-benifits{ + display: flex; + flex-wrap: wrap; +} +.home-upload-benifits div{ + display: flex; + width: 455px; + align-items: flex-start; + margin-right: 57px; + margin-top: 15px +} + +.home-upload-benifits div p{ + margin-left: 17px; + font-size: 16px; + color: #888888; + margin-bottom: 0; +} +.home-upload-benifits div img{ + margin-top: 3px +} +.home-upload-ontology-button{ + margin-top: 30px; + text-decoration: none; + color: var(--primary-color); + display: flex; + justify-content: space-between; + align-items: center; + width: 193px; + padding: 15px 25px; + border: 1px solid var(--primary-color); + border-radius: 8px; + font-size: 15px; + transition: background-color 0.3s ease; +} +.home-upload-ontology-button:hover{ + color: white !important; + background-color: var(--primary-color); +} +.home-upload-ontology-button:hover .home-upload-icon path{ + fill: white; +} + + +.home-recommendations-and-annotations{ + font-size: 16px; + outline: none; + padding: 20px; + width: 100%; + resize: none; + border-radius: 14px; + border: none; + +} +.home-services-buttons{ + background-color: white; + border-radius: 8px; + padding: 20px; + display: flex; + justify-content: flex-end; + align-items: center; +} +.home-card{ + border-radius: 8px; + box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1); +} +.home-get-annotations{ + cursor: pointer; + color: white; + background-color: var(--primary-color); + display: flex; + width: fit-content; + align-items: center; + padding: 15px 20px; + border-radius: 8px; + margin-left: 10px; + transition: background-color 0.3s ease; +} +.home-get-annotations:hover{ + background-color: var(--hover-color); +} +.home-get-annotations p{ + margin-right: 20px; + margin-bottom: 0; +} +.home-get-recommendations{ + cursor: pointer; + color: var(--primary-color); + display: flex; + width: fit-content; + height: fit-content; + align-items: center; + padding: 15px 20px; + border-radius: 8px; + border: 1px solid var(--primary-color); + transition: background-color 0.3s ease; +} +.home-get-recommendations:hover{ + color: white !important; + background-color: var(--primary-color); +} +.home-get-recommendations:hover .home-play-icon path{ + fill: white; +} +.home-get-recommendations p{ + margin-right: 20px; + margin-bottom: 0; +} +.home-section-sub-sections-container{ + display: flex; + justify-content: space-between; +} +.home-sub-section-left{ + width: 533px; +} +.home-sub-section-right{ + width: 533px; +} +.home-sub-section-left h4, .home-sub-section-right h4{ + font-size: 20px; + margin-bottom: 5px; + font-weight: 700; +} +.home-fair-scores{ + height: 349px; + padding-top: 35px; +} +.home-twitter-news{ + height: 349px; +} +.home-fair-scores a{ + text-decoration: none; + +} +.home-fair-details{ + margin-right: 25px !important; +} +.home-fair-scores div{ + display: flex; + justify-content: flex-end; + align-items: center; + margin-right: 20px; + margin-left: 27px; + margin-bottom: 14px; + color: var(--primary-color); +} +.home-fair-scores div p{ + margin-right: 10px; + margin-bottom: 0; +} +.home-logos{ + height: 138px; + display: flex; + align-items: center; + overflow: auto; + +} +.home-logos img{ + margin-left: 60px; +} + +#home-search-drop-down{ + display: none; + font-size: 16px; + background: white; + width: 100%; + border-radius: 0 0 14px 14px; + border: none; + box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1); +} + +.home-search-ontology-content{ + display: flex; + color: #777777 !important; + justify-content: space-between; + padding: 20px 20px; + cursor: pointer; + border-top: 1px solid #f7f7f7 +} +.home-search-ontology-content:hover{ + background-color: rgba(0, 0, 0, 0.01); +} +.home-search-ontology-content div{ + display: flex; + margin-left: 20px; +} +.home-search-ontology-content div img{ + width: 12px; +} +.home-search-ontology-content div p{ + font-weight: 300; + margin-left: 10px; + margin-bottom: 0; +} + +.home-dropdown-active{ + box-shadow: none !important; +} +#seached-ontology{ + margin-bottom: 0; +} +#seached-ontologies{ + margin-bottom: 0; +} + +.home-support-title{ + display: flex; + justify-content: center; + flex-direction: column; + +} +.home-support-items{ + display: flex; + justify-content: center; + flex-wrap: wrap; + +} +.home-support-items > *:not(:first-child){ + margin-left: 40px; +} +.home-support-items a{ + margin-bottom: 40px; + opacity: 85%; + transition: opacity 0.3s ease; +} +.home-support-items a:hover{ + opacity: 100%; +} +.home-result-type{ + font-weight: 300; + margin-bottom: 0; +} + +.home-searched-ontology{ + margin-bottom: 0; + word-wrap: break-word; + max-width: 400px; + margin-right: 20px; + +} + +@keyframes scale-up { + from { transform: scale(0.1); } + to { transform: scale(1); } +} + +@keyframes scale-up-random { + from { transform: scale(0.1); } + to { transform: scale(1.06); } +} + +@keyframes slide-and-fade { + from { opacity: 0; transform: translateY(-100%); } + to { opacity: 1; transform: translateY(0); } +} + + + diff --git a/app/assets/stylesheets/login.scss b/app/assets/stylesheets/login.scss index f2d68c91d..f26d33e6a 100644 --- a/app/assets/stylesheets/login.scss +++ b/app/assets/stylesheets/login.scss @@ -41,24 +41,13 @@ text-decoration:none; font-size: 13px; } -.login-button{ - margin-top: 10px; - width: 357px; - font-size: 16px; - color: white; - padding: 17px; - background-color: var(--primary-color); - border: none; - border-radius: 9px; - margin-bottom: 20px; -} -.login-button:hover{ - background-color: var(--hover-color); - cursor: pointer; -} - .dont-have-account{ font-size: 15px; font-weight: 600; text-align: center; } +.login-button-container{ + margin-top: 10px; + margin-bottom: 20px; + width: 357px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/nav_bar.scss b/app/assets/stylesheets/nav_bar.scss new file mode 100644 index 000000000..53c18c245 --- /dev/null +++ b/app/assets/stylesheets/nav_bar.scss @@ -0,0 +1,169 @@ +.nav-container{ + display: flex; + justify-content: center; + background-color: var(--primary-color); +} +.top-nav{ + display: flex !important; + justify-content: space-between; + background-color: var(--primary-color); + align-items: center; + height: 62px; + padding: 8px 50px; + width: 1280px; +} +.nav-responsiveness-container{ + display: flex; + justify-content: space-between; +} +.nav-logo{ + display: flex; + align-items: center; +} +.nav-logo p{ + margin-left: 10px; + color: white; + font-size: 16px; + font-weight: 700; + margin-bottom: 0; +} +.nav-items{ + display: flex; + justify-content: space-between; + align-items:center; + width: 85%; +} +.nav-items > ul { + display: flex; + list-style: none; + margin-bottom: 0; +} + +.nav-items > ul > li { + margin-left: 20px; +} + +.nav-items > ul > li > a { + color: white !important; + font-size: 15px; + opacity: 60%; + font-weight: 300; + transition: opacity 0.2s ease-in-out; +} +.nav-items > ul > li > a:hover{ + opacity: 100%; +} +.nav-items > ul > li > a.active{ + opacity: 100%; + font-weight: 500; +} +.nav-search-container > input { + height: 33px; + width: 228px; + outline: none; + opacity: 60%; + border: 1px solid white; + background-color: var(--primary-color); + color: white; + border-radius: 5px; + font-size: 14px; + padding: 0 10px; +} +.nav-search-container > input:focus{ + opacity: 100%; + border-radius: 5px 5px 0 0; +} +.nav-search-container > input::placeholder{ + color: white; + opacity: 60%; +} +.nav-search-container > input::-ms-input-placeholder{ + color: white; + opacity: 60%; +} +.nav-language{ + background-color: transparent; + width: 47px; + color: white; + border: none; + outline: none; + cursor: pointer; + +} +.nav-language option{ + background-color: white; + color: black; +} +.nav-items > a{ + padding: 3px 34px; + border: 1px solid white; + border-radius: 5px; + color: white !important; + transition: background-color 0.2s ease-in-out; +} +.nav-items > a:hover{ + background-color: rgba(255, 255, 255, 0.1); +} + +.top-nav .menu-btn i{ + color: #fff; + font-size: 22px; + cursor: pointer; + display: none; +} +.top-nav input[type="checkbox"]{ + display: none; +} + +.top-nav-nav-link{ + color: white !important; + padding: 0 !important; +} + +.nav-search-drop-down{ + position: absolute; + z-index: 9999; + font-size: 12px !important; + width: 228px !important; +} + +@media (max-width: 1200px){ + .top-nav .menu-btn i{ + display: block; + } + #nav-menu:checked ~ .menu-btn i:before{ + content: "\f00d"; + } + .nav-items{ + display: none; + } + .menu-btn{ + position: absolute; + right: 40px; + } + +} +.top-nav.show-responsive { + display: block !important; + background-color: var(--primary-color); + height: unset; +} + +.top-nav-ul.show-responsive { + display: block; +} + +.nav-items.show-responsive { + flex-direction: column; + width: unset; + display: flex; + align-items: flex-start; +} + +.show-responsive { + margin: 15px 0 !important; +} + +.supportMenuDropdownLink.show-responsive { + margin-bottom: 15px; +} diff --git a/app/assets/stylesheets/ontologies.scss b/app/assets/stylesheets/ontologies.scss index 231642f4a..98dde97ea 100644 --- a/app/assets/stylesheets/ontologies.scss +++ b/app/assets/stylesheets/ontologies.scss @@ -1,21 +1,11 @@ $ont-metadata-bg-color: #e2ebf0; $widget-table-border-color: #EFEFEF; -$ont-show-bg-color: #e9ecef; - -.ontologies.show { - background-color: $ont-show-bg-color; - - #bd { - background-color: $ont-show-bg-color; - } -} svg path { fill: var(--primary-color); } .ontologies.show .gutter { - background-color: rgba(0, 0, 0, 0.03); background-repeat: no-repeat; background-position: center; @@ -275,4 +265,3 @@ svg path { flex-direction: row; } - diff --git a/app/assets/stylesheets/register.scss b/app/assets/stylesheets/register.scss index 6db658b3a..2f9f1b305 100644 --- a/app/assets/stylesheets/register.scss +++ b/app/assets/stylesheets/register.scss @@ -83,22 +83,10 @@ margin-top: 14px; } -.register-button{ +.register-button-container{ margin-top: 20px; - width: 363px; - font-size: 16px; - color: white; - padding: 17px; - background-color: var(--primary-color); - border: none; - border-radius: 9px; - } -.register-button:hover{ - background-color: var(--hover-color); - cursor: pointer; -} #user_register_mail_list{ margin-top: 14px; accent-color: #8E8E8E; diff --git a/app/assets/stylesheets/theme-variables.scss.erb b/app/assets/stylesheets/theme-variables.scss.erb index 4a7c79a68..9c467c8af 100644 --- a/app/assets/stylesheets/theme-variables.scss.erb +++ b/app/assets/stylesheets/theme-variables.scss.erb @@ -3,28 +3,54 @@ case ui_theme when "agroportal" %> :root{ - --primary-color: #31B404; - --hover-color: #40C811; + --primary-color: #3CB371; + --hover-color: #41C67C; --secondary-color: #ffc107; + --light-color: #F1FAED; + --admin-color: #145FF4; + --error-color: #EB4335; } <% when "stageportal" %> :root{ - --primary-color: #76A7CC; - --hover-color: #6B96B7; + --primary-color: #3CB371; + --hover-color: #41C67C; --secondary-color: #ffc107; + --admin-color: #145FF4; + --light-color: #F1F6FA; + --error-color: #EB4335; } <% when "bioportal" %> :root{ --primary-color: #76A7CC; --hover-color: #6B96B7; --secondary-color: #ffc107; + --light-color: #F0F5F6; + --admin-color: #145FF4; + } + <% when "testportal" %> + :root{ + --primary-color: #3CB371; + --hover-color: #41C67C; + --secondary-color: #ffc107; + --admin-color: #145FF4; + --light-color: #F1F6FA; + --error-color: #EB4335; } + <% when "ontoportal" %> :root{ - --primary-color: #6E98A2; - --hover-color: #7BABB6; + --primary-color: #3CB371; + --hover-color: #41C67C; --secondary-color: #ffc107; + --light-color: #F0F5F6; + --error-color: #EB4335; } <%# Here to add a new theme ... %> <% end %> <% end %> + + + + + + diff --git a/app/assets/stylesheets/themes/agroportal/main.scss b/app/assets/stylesheets/themes/agroportal/main.scss index 4ada63be6..1a58350cb 100644 --- a/app/assets/stylesheets/themes/agroportal/main.scss +++ b/app/assets/stylesheets/themes/agroportal/main.scss @@ -1,6 +1,6 @@ -$color-primary: #31B404; +$color-primary: #3CB371; $color-secondary: #EFFFEF; -$color-links: #215B04; +$color-links: #3CB371; $color-warning: #ffc107; @import "../lirmm/main"; @import "search"; \ No newline at end of file diff --git a/app/assets/stylesheets/themes/lirmm/main.scss b/app/assets/stylesheets/themes/lirmm/main.scss index e50dcf48d..d5bb078c1 100644 --- a/app/assets/stylesheets/themes/lirmm/main.scss +++ b/app/assets/stylesheets/themes/lirmm/main.scss @@ -241,22 +241,3 @@ div.logos a { } } -/************************************ - * FOOTER -************************************/ -footer, .footer { - background-color: $color-secondary !important; - position: relative !important; -} - -footer img { - height: 32px; -} - -footer a.logo.connect img { - margin-right: 10px; -} - -.legal-text { - font-size: 0.9rem; -} diff --git a/app/assets/stylesheets/themes/ontoportal/main.scss b/app/assets/stylesheets/themes/ontoportal/main.scss index 2130fbeb5..d84ce5ba2 100644 --- a/app/assets/stylesheets/themes/ontoportal/main.scss +++ b/app/assets/stylesheets/themes/ontoportal/main.scss @@ -1,6 +1,6 @@ -$color-primary: rgb(110, 152, 162); -$color-secondary: #F7FDFC; -$color-links: rgb(144, 188, 185); +$color-primary: #3CB371; +$color-secondary: #E4F1FB; +$color-links: #3CB371; $color-warning: #ffc107; @import "../lirmm/main"; @import "search"; \ No newline at end of file diff --git a/app/assets/stylesheets/themes/stageportal/main.scss b/app/assets/stylesheets/themes/stageportal/main.scss index a56992679..d84ce5ba2 100644 --- a/app/assets/stylesheets/themes/stageportal/main.scss +++ b/app/assets/stylesheets/themes/stageportal/main.scss @@ -1,6 +1,6 @@ -$color-primary: #76A7CC; +$color-primary: #3CB371; $color-secondary: #E4F1FB; -$color-links: #76A7CC; +$color-links: #3CB371; $color-warning: #ffc107; @import "../lirmm/main"; @import "search"; \ No newline at end of file diff --git a/app/components/buttons/regular_button_component.rb b/app/components/buttons/regular_button_component.rb new file mode 100644 index 000000000..c40a9f67b --- /dev/null +++ b/app/components/buttons/regular_button_component.rb @@ -0,0 +1,49 @@ +class Buttons::RegularButtonComponent < ViewComponent::Base + renders_one :icon_left + renders_one :icon_right + + def initialize(id: , value:, variant: "primary", color: "normal", href: "", size: "normal", state: "animate", type: 'button') + @id = id + @value = value + @variant = variant + @color = color + @href = href + @size = size + @state = state + @type = type + end + + def button_label + hide_icon_left = icon_left == nil ? "hide" : " " + hide_icon_right = icon_right == nil ? "hide" : " " + content_tag(:span, icon_left, class: "#{@variant}-button-icon left-button-icon #{hide_icon_left}") + @value + content_tag(:span, icon_right, class: "#{@variant}-button-icon right-button-icon #{hide_icon_right}") + end + + def button_elem + slim_class = @size == "slim" ? "slim " : " " + danger_class = @color == "danger" ? "danger-button " : " " + warning_class = @color == "warning" ? "warning-button " : " " + disabled_class = @state == "disabled" ? "disabled-button " : " " + class_style = "#{@variant}-button regular-button " + danger_class + warning_class + disabled_class + slim_class + on_click_event = load_animation? ? "displayAnimation(this)" : '' + + if link? + link_to(@href, class: class_style, onclick: on_click_event, id: @id) do + button_label + end + else + button_tag(type: @type, class: class_style, onclick: on_click_event, id: @id) do + button_label + end + end + end + + def link? + @href && !@href.empty? + end + + def load_animation? + @state == "animate" + end + +end diff --git a/app/components/buttons/regular_button_component/regular_button_component.html.haml b/app/components/buttons/regular_button_component/regular_button_component.html.haml new file mode 100644 index 000000000..17c8f3c42 --- /dev/null +++ b/app/components/buttons/regular_button_component/regular_button_component.html.haml @@ -0,0 +1,11 @@ +.button-container + = button_elem + +- if load_animation? + = render Display::ButtonLoaderComponent.new(id: @id + '-loading-animation', slim: @size.eql?('slim'), color: @color) + :javascript + function displayAnimation(element){ + const loading = document.getElementById("#{@id}-loading-animation") + element.style.display = 'none'; + loading.style.display = 'flex'; + } \ No newline at end of file diff --git a/app/components/card_message_component.rb b/app/components/card_message_component.rb index 255372d5d..d0f15d062 100644 --- a/app/components/card_message_component.rb +++ b/app/components/card_message_component.rb @@ -1,10 +1,10 @@ class CardMessageComponent < ViewComponent::Base - def initialize(title: nil ,message:, button_text: nil, type:) + def initialize(title: nil ,message:, button_text: nil, button_link: "/" ,type:) @title = title @message = message @button_text = button_text @type = type - + @button_link = button_link end def no_title? @@ -21,6 +21,8 @@ def icon "green-check.svg" when "failure" "red-warning.svg" + when "warning" + "orange-warning.svg" end end end diff --git a/app/components/card_message_component/card_message_component.html.haml b/app/components/card_message_component/card_message_component.html.haml index 4eb55723a..bc7641ee1 100644 --- a/app/components/card_message_component/card_message_component.html.haml +++ b/app/components/card_message_component/card_message_component.html.haml @@ -13,8 +13,12 @@ - unless no_button? - case @type - when "success" - %a.card-message-button.card-message-button-success{:href => "/"} + %a.card-message-button.card-message-button-success{:href => @button_link} = @button_text - when "failure" - %a.card-message-button.card-message-button-failure{:href => "/"} + %a.card-message-button.card-message-button-failure{:href => @button_link} = @button_text + - when "warning" + %a.card-message-button.card-message-button-warning{:href => @button_link} + = @button_text + diff --git a/app/components/chip_button_component/chip_button_component.html.haml b/app/components/chip_button_component/chip_button_component.html.haml new file mode 100644 index 000000000..f735a6833 --- /dev/null +++ b/app/components/chip_button_component/chip_button_component.html.haml @@ -0,0 +1,5 @@ +- if @type == "static" + %span.chip_button_container + = @text +- else + %a.chip_button_container_clickable{href: @url}= @text diff --git a/app/components/chips_component.rb b/app/components/chips_component.rb index ced043f2e..83ad63f6c 100644 --- a/app/components/chips_component.rb +++ b/app/components/chips_component.rb @@ -1,6 +1,12 @@ class ChipsComponent < ViewComponent::Base - def initialize(name:, value:) + def initialize(id: '', name:, value:, checked: false) + @id = id || name @name = name @value = value + @checked = checked + end + + def checked? + @checked end end \ No newline at end of file diff --git a/app/components/circle_progress_bar_component.rb b/app/components/circle_progress_bar_component.rb new file mode 100644 index 000000000..e3e746b60 --- /dev/null +++ b/app/components/circle_progress_bar_component.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class CircleProgressBarComponent < ViewComponent::Base + + def initialize(count: , max: ) + super + @count = count + @max = max + end + + def value + ((@count.to_f / @max) * 100).to_i + end +end diff --git a/app/components/circle_progress_bar_component/circle_progress_bar_component.html.haml b/app/components/circle_progress_bar_component/circle_progress_bar_component.html.haml new file mode 100644 index 000000000..a319fba65 --- /dev/null +++ b/app/components/circle_progress_bar_component/circle_progress_bar_component.html.haml @@ -0,0 +1,7 @@ +.circular-progress{ data: { controller: 'circle-progress-bar', 'circle-progress-bar': { + 'circle-color-value': 'white', 'percentage-value': value, + 'progress-color-value': "var(--primary-color)", 'bg-color-value': 'white' +}}} + .inner-circle{'data-circle-progress-bar-target': 'innerCircle'} + %p.percentage{'data-circle-progress-bar-target': 'percentage'} + 0% diff --git a/app/components/circle_progress_bar_component/circle_progress_bar_component_controller.js b/app/components/circle_progress_bar_component/circle_progress_bar_component_controller.js new file mode 100644 index 000000000..932b1d82a --- /dev/null +++ b/app/components/circle_progress_bar_component/circle_progress_bar_component_controller.js @@ -0,0 +1,37 @@ +import { Controller } from "@hotwired/stimulus" + +// Connects to data-controller="circle-progress-bar" +export default class extends Controller { + static targets = ['percentage', 'innerCircle'] + static values = { + percentage: Number, + progressColor: String, + bgColor: String, + circleColor: String + } + + connect() { + const progressBar = this.element; + const progressValue = this.percentageTarget; + const innerCircle = this.innerCircleTarget; + let startValue = 0, + endValue = this.percentageValue, + speed = 30, + progressColor = this.progressColorValue; + + const progress = setInterval(() => { + startValue++; + progressValue.textContent = `${startValue}%`; + progressValue.style.color = `${progressColor}`; + + innerCircle.style.backgroundColor = `${this.circleColorValue}`; + + progressBar.style.background = `conic-gradient(${progressColor} ${ + startValue * 3.6 + }deg,${this.bgColorValue} 0deg)`; + if (startValue === endValue) { + clearInterval(progress); + } + }, speed); + } +} diff --git a/app/components/concept_details_component.rb b/app/components/concept_details_component.rb index 380427a3c..07b3f2a9d 100644 --- a/app/components/concept_details_component.rb +++ b/app/components/concept_details_component.rb @@ -3,8 +3,8 @@ class ConceptDetailsComponent < ViewComponent::Base include ApplicationHelper - renders_one :header - renders_many :sections + renders_one :header, TableComponent + renders_many :sections, TableRowComponent attr_reader :concept_properties @@ -19,8 +19,20 @@ def initialize(id:, acronym:, properties:, top_keys:, bottom_keys:, exclude_keys @concept_properties = concept_properties2hash(@properties) if @properties end - def render_properties(properties_set, ontology_acronym, &block) - out = '' + def add_sections(keys, &block) + scheme_set = properties_set_by_keys(keys, concept_properties) + rows = row_hash_properties(scheme_set, concept_properties, &block) + + rows.each do |row| + section do |table_row| + table_row.create(*row) + end + end + + end + + def row_hash_properties(properties_set, ontology_acronym, &block) + out = [] properties_set&.each do |key, data| next if exclude_relation?(key) || !data[:values] @@ -45,7 +57,7 @@ def render_properties(properties_set, ontology_acronym, &block) EOS out += line end - raw out + out end def properties_set_by_keys(keys, concept_properties, exclude_keys = []) @@ -64,10 +76,11 @@ def filter_properties(top_keys, bottom_keys, exclude_keys, concept_properties) end private + def concept_properties2hash(properties) # NOTE: example properties # - #properties + # properties #=> # "collapse", "data-target" => "##{@id}"} + = render Display::HeaderComponent.new(text: @title, tooltip: @tooltip) + = image_tag("summary/arrow-down.svg", class: 'ml-2') + + .collapse{id: @id} + - if content && !content.empty? + = content + - else + = render Layout::ListComponent.new do |l| + - l.row do + = empty_state || 'no data' diff --git a/app/components/dropdown_section_button_component.rb b/app/components/dropdown_section_button_component.rb new file mode 100644 index 000000000..c46074f75 --- /dev/null +++ b/app/components/dropdown_section_button_component.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class DropdownSectionButtonComponent < ViewComponent::Base + + renders_one :header + renders_many :items + + def initialize(divide: true) + super + @divide = divide + end + + def show_divider? + @divide + end +end diff --git a/app/components/dropdown_section_button_component/dropdown_section_button_component.html.haml b/app/components/dropdown_section_button_component/dropdown_section_button_component.html.haml new file mode 100644 index 000000000..3070f75de --- /dev/null +++ b/app/components/dropdown_section_button_component/dropdown_section_button_component.html.haml @@ -0,0 +1,7 @@ +- if show_divider? + %div.dropdown-divider +- if header? + %h6.dropdown-header= header +- items.each do |i| + %span.dropdown-item + = i \ No newline at end of file diff --git a/app/components/external_link_text_component.rb b/app/components/external_link_text_component.rb new file mode 100644 index 000000000..3bb0babb4 --- /dev/null +++ b/app/components/external_link_text_component.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class ExternalLinkTextComponent < LinkTextComponent + + def initialize(text:) + super(text: text, icon: 'icons/external-link') + end +end diff --git a/app/components/field_container_component.rb b/app/components/field_container_component.rb new file mode 100644 index 000000000..d45e42e0e --- /dev/null +++ b/app/components/field_container_component.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class FieldContainerComponent < ViewComponent::Base + + renders_one :label + def initialize(label: nil, value: nil) + super + @label = label + @value = value + end + + def show? + content && !content.strip.empty? || (!@value.nil? && !@value.strip.empty?) + end +end diff --git a/app/components/field_container_component/field_container_component.html.haml b/app/components/field_container_component/field_container_component.html.haml new file mode 100644 index 000000000..c7da1e602 --- /dev/null +++ b/app/components/field_container_component/field_container_component.html.haml @@ -0,0 +1,9 @@ +- if show? + %div.field-container + %p.field-description_text + = label || @label.humanize + - if content + = content + - else + %span.field-normal_text + = @value diff --git a/app/components/file_input_loader_component/file_input_loader_component.html.haml b/app/components/file_input_loader_component/file_input_loader_component.html.haml deleted file mode 100644 index 8c807b7e2..000000000 --- a/app/components/file_input_loader_component/file_input_loader_component.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -.file_uploader.d-flex.justify-content-center.p-2.bg-secondary{data: {controller: "file-input"}} - .file-drop-area.w-100 - %span.choose-file-button Choose file - %span.file-message{data:{'file-input': {target: 'message'}}} or drag and drop file here - = file_field_tag @name, class: 'file-input', data:{'file-input-target': 'input', action: 'file-input#updateMessage'} diff --git a/app/components/input/date_component.rb b/app/components/input/date_component.rb new file mode 100644 index 000000000..fe85fa892 --- /dev/null +++ b/app/components/input/date_component.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Input::DateComponent < Input::InputFieldComponent + def initialize(label: '', name:, value: Date.today, placeholder: '', error_message: '', helper_text: '') + super(label: label, name: name, value: value, placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + def call + render Input::InputFieldComponent.new(label: @label, name: @name, value: @value, placeholder: @placeholder, error_message: @error_message, helper_text: @helper_text, type: 'date') + end +end diff --git a/app/components/input/email_component.rb b/app/components/input/email_component.rb new file mode 100644 index 000000000..8d68ba3bc --- /dev/null +++ b/app/components/input/email_component.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Input::EmailComponent < Input::InputFieldComponent + def initialize(label: '', name:, value: nil, placeholder: '', error_message: '', helper_text: '') + super(label: label, name: name, value: value, placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + def call + render Input::InputFieldComponent.new(label: @label, name: @name, value: @value, placeholder: @placeholder, error_message: @error_message, helper_text: @helper_text, type: "email") + end +end diff --git a/app/components/file_input_loader_component.rb b/app/components/input/file_input_component.rb similarity index 71% rename from app/components/file_input_loader_component.rb rename to app/components/input/file_input_component.rb index a7e960ade..41de28bce 100644 --- a/app/components/file_input_loader_component.rb +++ b/app/components/input/file_input_component.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class FileInputLoaderComponent < ViewComponent::Base +class Input::FileInputComponent < ViewComponent::Base def initialize(name:, html_options: '') @name = name @html_options = html_options diff --git a/app/components/input/file_input_component/file_input_component.html.haml b/app/components/input/file_input_component/file_input_component.html.haml new file mode 100644 index 000000000..47c406905 --- /dev/null +++ b/app/components/input/file_input_component/file_input_component.html.haml @@ -0,0 +1,5 @@ +.file_uploader{data: {controller: "file-input"}} + .file-drop-area.w-100 + = inline_svg_tag "upload-file.svg" + %span.file-message{data:{'file-input': {target: 'message'}}} Drop your file here or, browse files on your device. + = file_field_tag @name, class: 'file-input', data:{'file-input-target': 'input', action: 'file-input#updateMessage'} \ No newline at end of file diff --git a/app/components/file_input_loader_component/file_input_loader_component_controller.js b/app/components/input/file_input_component/file_input_loader_component_controller.js similarity index 100% rename from app/components/file_input_loader_component/file_input_loader_component_controller.js rename to app/components/input/file_input_component/file_input_loader_component_controller.js diff --git a/app/components/input/input_field_component.rb b/app/components/input/input_field_component.rb new file mode 100644 index 000000000..01ed85ef6 --- /dev/null +++ b/app/components/input/input_field_component.rb @@ -0,0 +1,30 @@ +class Input::InputFieldComponent < ViewComponent::Base + def initialize(label: "" , name:, value: 'Syphax', type: 'text', placeholder: "", error_message: "", helper_text: "") + @label = label + @name = name + @placeholder = placeholder + @error_message = error_message + @helper_text = helper_text + @value = value + @type = type + end + + + def error_style + "border-color: var(--error-color);" if error? + end + + def error? + !@error_message.empty? + end + + def help? + !@helper_text.empty? + end + + def label? + !@label.empty? + end +end + + diff --git a/app/components/input/input_field_component/input_field_component.html.haml b/app/components/input/input_field_component/input_field_component.html.haml new file mode 100644 index 000000000..0bd9f9a10 --- /dev/null +++ b/app/components/input/input_field_component/input_field_component.html.haml @@ -0,0 +1,28 @@ +%div + - if label? + .text-input-label + = @label + + - if content + = content + - else + %input.input-field-component.text-input{name: @name, type: @type, placeholder: @placeholder, style: error_style, value: @value} + + + + - if error? + .text-input-error-text + = @error_message + - if help? + .text-input-helper-text + = @helper_text + + + + + + + + + + diff --git a/app/components/input/password_component.rb b/app/components/input/password_component.rb new file mode 100644 index 000000000..435692a5b --- /dev/null +++ b/app/components/input/password_component.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Input::PasswordComponent < Input::InputFieldComponent + def initialize(label: '', name:, value: nil, placeholder: '', error_message: '', helper_text: '') + super(label: label, name: name, value: value, placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + def call + render Input::InputFieldComponent.new(label: @label, name: @name, value: @value, placeholder: @placeholder, error_message: @error_message, helper_text: @helper_text, type: "password") + end +end diff --git a/app/components/input/select_component.rb b/app/components/input/select_component.rb new file mode 100644 index 000000000..e9f8e9b33 --- /dev/null +++ b/app/components/input/select_component.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Input::SelectComponent < Input::InputFieldComponent + + def initialize(id: nil, label: '', name:, value: [], selected: '', placeholder: '', error_message: '', helper_text: '', multiple: false, open_to_add_values: false) + super(label: label, name: name, value: value, placeholder: placeholder, error_message: error_message, helper_text: helper_text) + @values = value + @selected = selected + @open_to_add_values = open_to_add_values + @multiple = multiple + @id = id + end +end diff --git a/app/components/input/select_component/select_component.html.haml b/app/components/input/select_component/select_component.html.haml new file mode 100644 index 000000000..242f79405 --- /dev/null +++ b/app/components/input/select_component/select_component.html.haml @@ -0,0 +1,2 @@ += render Input::InputFieldComponent.new(name: @name, error_message: @error_message, helper_text: @helper_text, label: @label) do + = render SelectInputComponent.new(id: @id, name: @name, values: @values , selected: @selected , multiple: @multiple, open_to_add_values: @open_to_add_values ) \ No newline at end of file diff --git a/app/components/input/text_area_component.rb b/app/components/input/text_area_component.rb new file mode 100644 index 000000000..940a8b935 --- /dev/null +++ b/app/components/input/text_area_component.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class Input::TextAreaComponent < Input::InputFieldComponent + def initialize(label: '', name:, value: nil, placeholder: '', error_message: '', helper_text: '', rows: "5") + super(label: label, name: name, value: value, placeholder: placeholder, error_message: error_message, helper_text: helper_text) + @rows = rows + end +end diff --git a/app/components/input/text_area_component/text_area_component.html.haml b/app/components/input/text_area_component/text_area_component.html.haml new file mode 100644 index 000000000..d2dd1b5d8 --- /dev/null +++ b/app/components/input/text_area_component/text_area_component.html.haml @@ -0,0 +1,3 @@ += render Input::InputFieldComponent.new(label: @label, name: @name, value: @value, placeholder: @placeholder, error_message: @error_message, helper_text: @helper_text) do + %textarea.input-field-component{name: @name, rows: @rows, placeholder: @placeholder, style: error_style} + = @value \ No newline at end of file diff --git a/app/components/input/text_input_component.rb b/app/components/input/text_input_component.rb new file mode 100644 index 000000000..7a38b3de0 --- /dev/null +++ b/app/components/input/text_input_component.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Input::TextInputComponent < Input::InputFieldComponent + def initialize(label: '', name:, value: nil, placeholder: '', error_message: '', helper_text: '') + super(label: label, name: name, value: value, placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + def call + render Input::InputFieldComponent.new(label: @label, name: @name, value: @value, placeholder: @placeholder, error_message: @error_message, helper_text: @helper_text, type: @type) + end +end diff --git a/app/components/input/url_component.rb b/app/components/input/url_component.rb new file mode 100644 index 000000000..01db0eb68 --- /dev/null +++ b/app/components/input/url_component.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Input::UrlComponent < Input::InputFieldComponent + def initialize(label: '', name:, value: nil, placeholder: '', error_message: '', helper_text: '') + super(label: label, name: name, value: value, placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + def call + render Input::InputFieldComponent.new(label: @label, name: @name, value: @value, placeholder: @placeholder, error_message: @error_message, helper_text: @helper_text, type: "url") + end +end diff --git a/app/components/internal_link_text_component.rb b/app/components/internal_link_text_component.rb new file mode 100644 index 000000000..308eb4b38 --- /dev/null +++ b/app/components/internal_link_text_component.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class InternalLinkTextComponent < LinkTextComponent + def initialize(text:) + super(text: text, icon: 'icons/internal-link') + end +end diff --git a/app/components/label_link_component.rb b/app/components/label_link_component.rb index 77a3642a6..dd00d289e 100644 --- a/app/components/label_link_component.rb +++ b/app/components/label_link_component.rb @@ -2,7 +2,7 @@ class LabelLinkComponent < ViewComponent::Base - def initialize(id:, text:, icon: 'fas fa-external-link-alt') + def initialize(id:, text:, icon: 'open-popup') @id = id @text = text @icon = icon @@ -10,9 +10,9 @@ def initialize(id:, text:, icon: 'fas fa-external-link-alt') def call if @id.eql?(@text) - @text + ExternalLinkTextComponent.new(text: @text).call else - @text + "" + InternalLinkTextComponent.new(text: @text).call end end diff --git a/app/components/language_field_component.rb b/app/components/language_field_component.rb new file mode 100644 index 000000000..6922f855e --- /dev/null +++ b/app/components/language_field_component.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class LanguageFieldComponent < ViewComponent::Base + + LEXVO_TO_FLAG = { 'http://lexvo.org/id/iso639-3/aar' => 'aa', 'http://lexvo.org/id/iso639-3/abk' => 'ab', + 'http://lexvo.org/id/iso639-3/ave' => 'ae', 'http://lexvo.org/id/iso639-3/afr' => 'af', + 'http://lexvo.org/id/iso639-3/aka' => 'ak', 'http://lexvo.org/id/iso639-3/amh' => 'am', + 'http://lexvo.org/id/iso639-3/arg' => 'an', 'http://lexvo.org/id/iso639-3/ara' => 'ar', 'http://lexvo.org/id/iso639-3/asm' => 'as', 'http://lexvo.org/id/iso639-3/ava' => 'av', 'http://lexvo.org/id/iso639-3/aym' => 'ay', 'http://lexvo.org/id/iso639-3/aze' => 'az', 'http://lexvo.org/id/iso639-3/bak' => 'ba', 'http://lexvo.org/id/iso639-3/bel' => 'be', 'http://lexvo.org/id/iso639-3/bul' => 'bg', 'http://lexvo.org/id/iso639-3/bis' => 'bi', 'http://lexvo.org/id/iso639-3/bam' => 'bm', 'http://lexvo.org/id/iso639-3/ben' => 'bn', 'http://lexvo.org/id/iso639-3/bod' => 'bo', 'http://lexvo.org/id/iso639-3/bre' => 'br', 'http://lexvo.org/id/iso639-3/bos' => 'bs', 'http://lexvo.org/id/iso639-3/cat' => 'ca', 'http://lexvo.org/id/iso639-3/che' => 'ce', 'http://lexvo.org/id/iso639-3/cha' => 'ch', 'http://lexvo.org/id/iso639-3/cos' => 'co', 'http://lexvo.org/id/iso639-3/cre' => 'cr', 'http://lexvo.org/id/iso639-3/ces' => 'cs', 'http://lexvo.org/id/iso639-3/chu' => 'cu', 'http://lexvo.org/id/iso639-3/chv' => 'cv', 'http://lexvo.org/id/iso639-3/cym' => 'cy', 'http://lexvo.org/id/iso639-3/dan' => 'da', 'http://lexvo.org/id/iso639-3/deu' => 'de', 'http://lexvo.org/id/iso639-3/div' => 'dv', 'http://lexvo.org/id/iso639-3/dzo' => 'dz', 'http://lexvo.org/id/iso639-3/ewe' => 'ee', 'http://lexvo.org/id/iso639-3/ell' => 'el', 'http://lexvo.org/id/iso639-3/eng' => 'en', 'http://lexvo.org/id/iso639-3/epo' => 'eo', 'http://lexvo.org/id/iso639-3/spa' => 'es', 'http://lexvo.org/id/iso639-3/est' => 'et', 'http://lexvo.org/id/iso639-3/eus' => 'eu', 'http://lexvo.org/id/iso639-3/fas' => 'fa', 'http://lexvo.org/id/iso639-3/ful' => 'ff', 'http://lexvo.org/id/iso639-3/fin' => 'fi', 'http://lexvo.org/id/iso639-3/fij' => 'fj', 'http://lexvo.org/id/iso639-3/fao' => 'fo', 'http://lexvo.org/id/iso639-3/fra' => 'fr', 'http://lexvo.org/id/iso639-3/fry' => 'fy', 'http://lexvo.org/id/iso639-3/gle' => 'ga', 'http://lexvo.org/id/iso639-3/gla' => 'gd', 'http://lexvo.org/id/iso639-3/glg' => 'gl', 'http://lexvo.org/id/iso639-3/grn' => 'gn', 'http://lexvo.org/id/iso639-3/guj' => 'gu', 'http://lexvo.org/id/iso639-3/glv' => 'gv', 'http://lexvo.org/id/iso639-3/hau' => 'ha', 'http://lexvo.org/id/iso639-3/heb' => 'he', 'http://lexvo.org/id/iso639-3/hin' => 'hi', 'http://lexvo.org/id/iso639-3/hmo' => 'ho', 'http://lexvo.org/id/iso639-3/hrv' => 'hr', 'http://lexvo.org/id/iso639-3/hat' => 'ht', 'http://lexvo.org/id/iso639-3/hun' => 'hu', 'http://lexvo.org/id/iso639-3/hye' => 'hy', 'http://lexvo.org/id/iso639-3/her' => 'hz', 'http://lexvo.org/id/iso639-3/ina' => 'ia', 'http://lexvo.org/id/iso639-3/ind' => 'id', 'http://lexvo.org/id/iso639-3/ile' => 'ie', 'http://lexvo.org/id/iso639-3/ibo' => 'ig', 'http://lexvo.org/id/iso639-3/iii' => 'ii', 'http://lexvo.org/id/iso639-3/ipk' => 'ik', 'http://lexvo.org/id/iso639-3/ido' => 'io', 'http://lexvo.org/id/iso639-3/isl' => 'is', 'http://lexvo.org/id/iso639-3/ita' => 'it', 'http://lexvo.org/id/iso639-3/iku' => 'iu', 'http://lexvo.org/id/iso639-3/jpn' => 'ja', 'http://lexvo.org/id/iso639-3/jav' => 'jv', 'http://lexvo.org/id/iso639-3/kat' => 'ka', 'http://lexvo.org/id/iso639-3/kon' => 'kg', 'http://lexvo.org/id/iso639-3/kik' => 'ki', 'http://lexvo.org/id/iso639-3/kua' => 'kj', 'http://lexvo.org/id/iso639-3/kaz' => 'kk', 'http://lexvo.org/id/iso639-3/kal' => 'kl', 'http://lexvo.org/id/iso639-3/khm' => 'km', 'http://lexvo.org/id/iso639-3/kan' => 'kn', 'http://lexvo.org/id/iso639-3/kor' => 'ko', 'http://lexvo.org/id/iso639-3/kau' => 'kr', 'http://lexvo.org/id/iso639-3/kas' => 'ks', 'http://lexvo.org/id/iso639-3/kur' => 'ku', 'http://lexvo.org/id/iso639-3/kom' => 'kv', 'http://lexvo.org/id/iso639-3/cor' => 'kw', 'http://lexvo.org/id/iso639-3/kir' => 'ky', 'http://lexvo.org/id/iso639-3/lat' => 'la', 'http://lexvo.org/id/iso639-3/ltz' => 'lb', 'http://lexvo.org/id/iso639-3/lug' => 'lg', 'http://lexvo.org/id/iso639-3/lim' => 'li', 'http://lexvo.org/id/iso639-3/lin' => 'ln', 'http://lexvo.org/id/iso639-3/lao' => 'lo', 'http://lexvo.org/id/iso639-3/lit' => 'lt', 'http://lexvo.org/id/iso639-3/lub' => 'lu', 'http://lexvo.org/id/iso639-3/lav' => 'lv', 'http://lexvo.org/id/iso639-3/mlg' => 'mg', 'http://lexvo.org/id/iso639-3/mah' => 'mh', 'http://lexvo.org/id/iso639-3/mri' => 'mi', 'http://lexvo.org/id/iso639-3/mkd' => 'mk', 'http://lexvo.org/id/iso639-3/mal' => 'ml', 'http://lexvo.org/id/iso639-3/mon' => 'mn', 'http://lexvo.org/id/iso639-3/mar' => 'mr', 'http://lexvo.org/id/iso639-3/msa' => 'ms', 'http://lexvo.org/id/iso639-3/mlt' => 'mt', 'http://lexvo.org/id/iso639-3/mya' => 'my', 'http://lexvo.org/id/iso639-3/nau' => 'na', 'http://lexvo.org/id/iso639-3/nob' => 'nb', 'http://lexvo.org/id/iso639-3/nde' => 'nd', 'http://lexvo.org/id/iso639-3/nep' => 'ne', 'http://lexvo.org/id/iso639-3/ndo' => 'ng', 'http://lexvo.org/id/iso639-3/nld' => 'nl', 'http://lexvo.org/id/iso639-3/nno' => 'nn', 'http://lexvo.org/id/iso639-3/nor' => 'no', 'http://lexvo.org/id/iso639-3/nbl' => 'nr', 'http://lexvo.org/id/iso639-3/nav' => 'nv', 'http://lexvo.org/id/iso639-3/nya' => 'ny', 'http://lexvo.org/id/iso639-3/oci' => 'oc', 'http://lexvo.org/id/iso639-3/oji' => 'oj', 'http://lexvo.org/id/iso639-3/orm' => 'om', 'http://lexvo.org/id/iso639-3/ori' => 'or', 'http://lexvo.org/id/iso639-3/oss' => 'os', 'http://lexvo.org/id/iso639-3/pan' => 'pa', 'http://lexvo.org/id/iso639-3/pli' => 'pi', 'http://lexvo.org/id/iso639-3/pol' => 'pl', 'http://lexvo.org/id/iso639-3/pus' => 'ps', 'http://lexvo.org/id/iso639-3/por' => 'pt', 'http://lexvo.org/id/iso639-3/que' => 'qu', 'http://lexvo.org/id/iso639-3/roh' => 'rm', 'http://lexvo.org/id/iso639-3/run' => 'rn', 'http://lexvo.org/id/iso639-3/ron' => 'ro', 'http://lexvo.org/id/iso639-3/rus' => 'ru', 'http://lexvo.org/id/iso639-3/kin' => 'rw', 'http://lexvo.org/id/iso639-3/san' => 'sa', 'http://lexvo.org/id/iso639-3/srd' => 'sc', 'http://lexvo.org/id/iso639-3/snd' => 'sd', 'http://lexvo.org/id/iso639-3/sme' => 'se', 'http://lexvo.org/id/iso639-3/sag' => 'sg', 'http://lexvo.org/id/iso639-3/hbs' => 'sh', 'http://lexvo.org/id/iso639-3/sin' => 'si', 'http://lexvo.org/id/iso639-3/slk' => 'sk', 'http://lexvo.org/id/iso639-3/slv' => 'sl', 'http://lexvo.org/id/iso639-3/smo' => 'sm', 'http://lexvo.org/id/iso639-3/sna' => 'sn', 'http://lexvo.org/id/iso639-3/som' => 'so', 'http://lexvo.org/id/iso639-3/sqi' => 'sq', 'http://lexvo.org/id/iso639-3/srp' => 'sr', 'http://lexvo.org/id/iso639-3/ssw' => 'ss', 'http://lexvo.org/id/iso639-3/sot' => 'st', 'http://lexvo.org/id/iso639-3/sun' => 'su', 'http://lexvo.org/id/iso639-3/swe' => 'sv', 'http://lexvo.org/id/iso639-3/swa' => 'sw', 'http://lexvo.org/id/iso639-3/tam' => 'ta', 'http://lexvo.org/id/iso639-3/tel' => 'te', 'http://lexvo.org/id/iso639-3/tgk' => 'tg', 'http://lexvo.org/id/iso639-3/tha' => 'th', 'http://lexvo.org/id/iso639-3/tir' => 'ti', 'http://lexvo.org/id/iso639-3/tuk' => 'tk', 'http://lexvo.org/id/iso639-3/tgl' => 'tl', 'http://lexvo.org/id/iso639-3/tsn' => 'tn', 'http://lexvo.org/id/iso639-3/ton' => 'to', 'http://lexvo.org/id/iso639-3/tur' => 'tr', 'http://lexvo.org/id/iso639-3/tso' => 'ts', 'http://lexvo.org/id/iso639-3/tat' => 'tt', 'http://lexvo.org/id/iso639-3/twi' => 'tw', 'http://lexvo.org/id/iso639-3/tah' => 'ty', 'http://lexvo.org/id/iso639-3/uig' => 'ug', 'http://lexvo.org/id/iso639-3/ukr' => 'uk', 'http://lexvo.org/id/iso639-3/urd' => 'ur', 'http://lexvo.org/id/iso639-3/uzb' => 'uz', 'http://lexvo.org/id/iso639-3/ven' => 've', 'http://lexvo.org/id/iso639-3/vie' => 'vi', 'http://lexvo.org/id/iso639-3/vol' => 'vo', 'http://lexvo.org/id/iso639-3/wln' => 'wa', 'http://lexvo.org/id/iso639-3/wol' => 'wo', 'http://lexvo.org/id/iso639-3/xho' => 'xh', 'http://lexvo.org/id/iso639-3/yid' => 'yi', 'http://lexvo.org/id/iso639-3/yor' => 'yo', 'http://lexvo.org/id/iso639-3/zha' => 'za', 'http://lexvo.org/id/iso639-3/zho' => 'zh', 'http://lexvo.org/id/iso639-3/zul' => 'zu' } + + + def initialize(value: ) + super + @lang_code = lang_codes_init(value) + end + + def lang_codes_init(lang) + if lang.to_s.eql?("en") || lang.to_s.eql?("eng") || lang.to_s.eql?("http://lexvo.org/id/iso639-3/eng") + lang_codes = "gb" + elsif lang.to_s.start_with?("http://lexvo.org") + lang_codes = LEXVO_TO_FLAG[lang] + else + lang_codes = lang + end + lang_codes + end +end diff --git a/app/components/language_field_component/language_field_component.html.haml b/app/components/language_field_component/language_field_component.html.haml new file mode 100644 index 000000000..a6b431565 --- /dev/null +++ b/app/components/language_field_component/language_field_component.html.haml @@ -0,0 +1,5 @@ +- if @lang_code.length == 2 + %div.f32 + %span.flag{:class => " #{@lang_code}", :style => "margin-right: 0.5em;"} +- else + = render ChipButtonComponent.new(text: @lang_code) \ No newline at end of file diff --git a/app/components/layout/card_component.rb b/app/components/layout/card_component.rb new file mode 100644 index 000000000..ceebc820c --- /dev/null +++ b/app/components/layout/card_component.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Layout::CardComponent < ViewComponent::Base + renders_one :header, Display::HeaderComponent + + def call + content_tag(:div, class: 'summary-card') do + out = '' + out = header if header? + raw(out.to_s + content) + end + end +end diff --git a/app/components/layout/horizontal_list_component.rb b/app/components/layout/horizontal_list_component.rb new file mode 100644 index 000000000..aed504b7a --- /dev/null +++ b/app/components/layout/horizontal_list_component.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class Layout::HorizontalListComponent < ViewComponent::Base + renders_many :elements + + def call + return if elements.empty? + + content_tag(:div, class: 'd-flex flex-wrap') do + out = '' + elements.each do |element| + out = out + content_tag(:div, element, class: 'mr-1 mb-1 text-truncate overflow-hidden') + end + raw out + end + end + +end diff --git a/app/components/layout/list_component.rb b/app/components/layout/list_component.rb new file mode 100644 index 000000000..edf75b865 --- /dev/null +++ b/app/components/layout/list_component.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class Layout::ListComponent < ViewComponent::Base + + renders_many :rows + + def call + return if rows.map(&:to_s).reject(&:empty?).empty? + + content_tag(:div, style: 'padding: 0px 20px 20px 20px;') do + out = "" + rows.each do |row| + next if row.nil? || row.to_s.empty? + out = out + content_tag(:div, row.to_s, class: 'mb-1') + end + out.html_safe + end + end + +end diff --git a/app/components/layout/progress_pages_component.rb b/app/components/layout/progress_pages_component.rb new file mode 100644 index 000000000..1680e4e49 --- /dev/null +++ b/app/components/layout/progress_pages_component.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class Layout::ProgressPagesComponent < ViewComponent::Base + + renders_many :pages + def initialize(pages_title: []) + super + @pages_title = pages_title + end +end diff --git a/app/components/layout/progress_pages_component/progress_pages_component.html.haml b/app/components/layout/progress_pages_component/progress_pages_component.html.haml new file mode 100644 index 000000000..f6b02cd67 --- /dev/null +++ b/app/components/layout/progress_pages_component/progress_pages_component.html.haml @@ -0,0 +1,32 @@ +%div.w-100{'data-controller': 'progress-pages'} + %div + .d-flex.justify-content-center.flex-column + .progress-pages-container + - @pages_title.each_with_index do |key, index| + .progress-item{'data-progress-pages-target': 'pageItem'} + %div + .outlined-circle{class: index.zero? ? 'outlined-active-circle' : ''} + = image_tag("icons/white-check.svg") + %span{class: index.zero? ? 'active' : ''} + = key.humanize + - if index < (@pages_title.size-1) + %hr.line + %div + - pages.each_with_index do |page, index| + %div.progress-content{{'data-progress-pages-target': 'pageContent'}, class: index.zero? ? '' : 'hide'} + = page + + + .progress-pages-actions + .progress-pages-back-button.hide{'data-action': "click->progress-pages#navigateBack", 'data-progress-pages-target': 'backBtn'} + = render Buttons::RegularButtonComponent.new(id: 'progress-pages-back-button', value: "Back", variant: "secondary", size: 'slim',state: 'regular') do |btn| + - btn.icon_left do + = inline_svg "icons/arrow-left.svg" + .progress-pages-next-button{'data-action': "click->progress-pages#navigateNext", 'data-progress-pages-target': 'nextBtn'} + = render Buttons::RegularButtonComponent.new(id: 'progress-pages-next-button', value: "Next", size: 'slim', state: 'regular') do |btn| + - btn.icon_right do + = inline_svg "arrow-right.svg" + .progress-pages-next-button.hide{ 'data-progress-pages-target': 'finishBtn'} + = render Buttons::RegularButtonComponent.new(id: 'progress-pages-finish-button', value: "Finish", size: 'slim', type: 'submit') do |btn| + - btn.icon_right do + = inline_svg "icons/white-check.svg" \ No newline at end of file diff --git a/app/components/layout/progress_pages_component/progress_pages_component_controller.js b/app/components/layout/progress_pages_component/progress_pages_component_controller.js new file mode 100644 index 000000000..146922311 --- /dev/null +++ b/app/components/layout/progress_pages_component/progress_pages_component_controller.js @@ -0,0 +1,87 @@ +import {Controller} from "@hotwired/stimulus"; + +export default class extends Controller { + static targets = ['pageItem','pageContent' ,'backBtn', 'nextBtn', 'finishBtn'] + connect() { + this.pagesItems = this.pageItemTargets + this.buttons = [this.backBtnTarget, this.nextBtnTarget, this.finishBtnTarget] + this.currentForm = 1 + } + + navigateBack(){ + this.navigateForm('back') + } + navigateNext(){ + this.navigateForm('next') + } + + navigateForm(direction) { + if (direction === "next" && this.currentForm < this.pagesItems.length) { + this.currentForm += 1 + this.showForm() + } else if (direction === "back" && this.currentForm > 1){ + this.currentForm -= 1 + this.showForm() + } + } + + showForm(){ + const targetForm = this.currentForm + for (let index = 1; index <= this.pagesItems.length; index++) { + + const targetFormDOM = this.pageContentTargets[index - 1]; + + const isCurrentForm = targetForm === index; + + targetFormDOM.classList.toggle("hide", !isCurrentForm); + + if (isCurrentForm) { + this.updateProgressBar(targetForm); + this.updateButtons(targetForm); + } + + } + + } + updateProgressBar(targetForm) { + const progressItemsDOM = document.querySelectorAll(".progress-item > div"); + const line = document.querySelectorAll(".line"); + + progressItemsDOM.forEach((item, index) => { + const isPassedSection = index + 1 < targetForm; + const isCurrentSection = index + 1 === targetForm; + + item.children[0].classList.toggle("outlined-checked-circle", isPassedSection); + item.children[0].classList.toggle("outlined-active-circle", isCurrentSection); + + + item.children[1].classList.toggle("active", isCurrentSection || isPassedSection); + + + line[index]?.classList.toggle("active", isPassedSection); + }); + } + + updateButtons(targetForm) { + + switch (targetForm) { + case 1: + this.showBtn([this.buttons[1]]); + break; + case this.pagesItems.length: + this.showBtn([this.buttons[0], this.buttons[2]]); + break; + default: + this.showBtn([this.buttons[0], this.buttons[1]]); + } + + } + + showBtn(btnIds = []) { + this.buttons.forEach((btn) => { + const targetBtnDOM = btn; + const shouldShowBtn = btnIds.includes(btn); + targetBtnDOM.classList.toggle("hide", !shouldShowBtn); + }); + } +} diff --git a/app/components/license_field_component.rb b/app/components/license_field_component.rb new file mode 100644 index 000000000..6baf0f86f --- /dev/null +++ b/app/components/license_field_component.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class LicenseFieldComponent < ViewComponent::Base + + def initialize(value: ) + super + @value = value + end + +end diff --git a/app/components/license_field_component/license_field_component.html.haml b/app/components/license_field_component/license_field_component.html.haml new file mode 100644 index 000000000..2969701a7 --- /dev/null +++ b/app/components/license_field_component/license_field_component.html.haml @@ -0,0 +1,8 @@ +- if @value.to_s.start_with?("http://creativecommons.org/licenses") || @value.to_s.start_with?("https://creativecommons.org/licenses") + %a{:rel => "license", :alt => "Creative Commons License", :href => "#{@value}", :target => "_blank", :style => "border-width:0", :title => "#{@value}"} + %img{:rel => "license", :alt => "Creative Commons License", :title => "#{@value}", :style => "border-width:0", :src => "https://i.creativecommons.org/l/by/4.0/88x31.png"} +- elsif @value.to_s.start_with?("http://opensource.org/licenses") || @value.to_s.start_with?("https://opensource.org/licenses") + %a{:rel => "license", :alt => "Open Source License", :href => "#{@value}", :title => "#{@value}", :target => "_blank", :style => "border-width:0;", :src => "https://opensource.org/files/osi_logo_bold_100X133_90ppi.png"} + %img{:rel => "license", :alt => "Open Source License", :title => "#{@value}", :style => "height: 80px; border-width:0;", :src => "https://opensource.org/files/osi_logo_bold_100X133_90ppi.png"} +- else + %a{:rel => "license", :href => "#{@value}", :target => "_blank"}= @value \ No newline at end of file diff --git a/app/components/link_field_component.rb b/app/components/link_field_component.rb new file mode 100644 index 000000000..8a499f8ad --- /dev/null +++ b/app/components/link_field_component.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class LinkFieldComponent < ViewComponent::Base + + def initialize(value:) + super + @value = value + end + + + def internal_link? + @value.to_s.include?(URI.parse($REST_URL).hostname) || @value.to_s.include?($UI_HOSTNAME) + end + +end diff --git a/app/components/link_field_component/link_field_component.html.haml b/app/components/link_field_component/link_field_component.html.haml new file mode 100644 index 000000000..4e7879a7c --- /dev/null +++ b/app/components/link_field_component/link_field_component.html.haml @@ -0,0 +1,6 @@ +- if internal_link? + = render ChipButtonComponent.new(url: @value.to_s.sub("data.", ""), text: @value.to_s.split("/").last, type: "clickable") +- elsif @value.to_s =~ /\A#{URI::regexp(%w[http https])}\z/ + = render ChipButtonComponent.new(url: @value.to_s, text: @value.to_s, type: "clickable") +- else + = render ChipButtonComponent.new( text: @value.to_s, type: "static") \ No newline at end of file diff --git a/app/components/link_text_component.rb b/app/components/link_text_component.rb new file mode 100644 index 000000000..ffd3b8b08 --- /dev/null +++ b/app/components/link_text_component.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class LinkTextComponent < ViewComponent::Base + + def initialize(text:, icon: nil) + @text = text + @icon = icon + end + + def call + svg_icon = !@icon&.empty? ? inline_svg(@icon) : '' + "#{@text}#{svg_icon}".html_safe + end +end diff --git a/app/components/loader_component.rb b/app/components/loader_component.rb index 8052650b7..a17b9f8b6 100644 --- a/app/components/loader_component.rb +++ b/app/components/loader_component.rb @@ -3,9 +3,18 @@ class LoaderComponent < ViewComponent::Base include ActionView::Helpers::TagHelper + def initialize(small: false) + super + @small = small + end + + def small_class + @small ? 'spinner-border-sm' : '' + end + def call content_tag(:div, class: 'd-flex align-items-center flex-column') do - content_tag(:div, class:'spinner-border') do + content_tag(:div, class: "spinner-border #{small_class}") do content_tag(:span) do 'Loading' end diff --git a/app/components/nested_form_inputs_component.rb b/app/components/nested_form_inputs_component.rb index 880cfe91d..39a9be53e 100644 --- a/app/components/nested_form_inputs_component.rb +++ b/app/components/nested_form_inputs_component.rb @@ -3,5 +3,12 @@ class NestedFormInputsComponent < ViewComponent::Base renders_one :template + renders_one :header renders_many :rows + renders_one :empty_state + + def initialize(object_name: '') + super + @object_name = object_name + end end diff --git a/app/components/nested_form_inputs_component/nested_form_inputs_component.html.haml b/app/components/nested_form_inputs_component/nested_form_inputs_component.html.haml index 986284231..78a23641d 100644 --- a/app/components/nested_form_inputs_component/nested_form_inputs_component.html.haml +++ b/app/components/nested_form_inputs_component/nested_form_inputs_component.html.haml @@ -1,21 +1,34 @@ -%div{data: {controller: "nested-form"}} +%div.nested-form-input-container{data: {controller: "nested-form"}} %template{'data-nested-form-target':"template"} - %div.d-flex.align-items-center.nested-form-wrapper{'data-new-record': 'true'} + %div.d-flex.align-items-center.nested-form-wrapper.my-1{'data-new-record': 'true'} %div{style: 'width: 90%'} = template %div.d-flex.justify-content-end{style: 'width: 10%'} - %button.btn.btn-danger{data: {action:"nested-form#remove"}} - %i.fas.fa-minus.fa-lg + %div.delete{data: {action:"click->nested-form#remove"}} + = inline_svg 'icons/delete.svg' + + %div.titles + = header + %div.d-none + = empty_state - rows.each_with_index do |row , index| - %div.d-flex.align-items-center.nested-form-wrapper{'data-new-record': 'true'} + %div.d-flex.align-items-center.nested-form-wrapper.my-1{'data-new-record': 'true'} %div{style: 'width: 90%'} = row %div.d-flex.justify-content-end{style: 'width: 10%'} - - unless index == 0 - %button.btn.btn-danger{data: {action:"nested-form#remove"}} - %i.fas.fa-minus.fa-lg + %div.delete{data: {action:"click->nested-form#remove"}} + = inline_svg 'icons/delete.svg' + + - if rows.empty? + %div.d-flex.align-items-center.nested-form-wrapper.my-1{'data-new-record': 'true'} + %div{style: 'width: 90%'} + = template + %div.d-flex.justify-content-end{style: 'width: 10%'} + %div.delete{data: {action:"click->nested-form#remove"}} + = inline_svg 'icons/delete.svg' %div{'data-nested-form-target': "target"} - %div.float-right - %button.btn.btn-success{data: {action:"nested-form#add"}} - %i.fas.fa-plus.fa-lg \ No newline at end of file + %div.add-another-object{data: {action:"click->nested-form#add"}} + = inline_svg 'icons/plus.svg' + %div + Add another #{@object_name} \ No newline at end of file diff --git a/app/components/notification_component.rb b/app/components/notification_component.rb new file mode 100644 index 000000000..49f82354a --- /dev/null +++ b/app/components/notification_component.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class NotificationComponent < ViewComponent::Base + + def initialize(title:, comment: '', type: 'success', auto_remove: true) + super + @title = title + @comment = comment + @type = type + @auto_remove = auto_remove + end + + def auto_remove? + @auto_remove + end + + def notification_type_icon + svg_icon(@type) + end + + def notification_animation_class + auto_remove? ? 'slide-in-out-right' : 'slide-in-right' + end + + def notification_type_class + "type-#{@type}" + end + + def notification_class + notification_animation_class + end + + private + def svg_icon(name) + inline_svg_tag("icons/#{name}.svg", class: notification_type_class) + end + + +end diff --git a/app/components/notification_component/notification_component.html.haml b/app/components/notification_component/notification_component.html.haml new file mode 100644 index 000000000..92962db54 --- /dev/null +++ b/app/components/notification_component/notification_component.html.haml @@ -0,0 +1,13 @@ +.notification{class: notification_class} + .notification-inner + .notification-content + %span + = notification_type_icon + .notification-text + %p.text-sm.font-medium.text-gray-900 + = @title + %p + = @comment + .ml-4.flex-shrink-0.d-flex + %button.notification-close{"onClick": "this.parentElement.parentElement.parentElement.style.opacity = 0"} + = svg_icon('close') \ No newline at end of file diff --git a/app/components/ontology_search_input_component.rb b/app/components/ontology_search_input_component.rb new file mode 100644 index 000000000..6a4895601 --- /dev/null +++ b/app/components/ontology_search_input_component.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class OntologySearchInputComponent < ViewComponent::Base + + def initialize(name: 'search', placeholder: 'Search for an ontology or concept (Ex: Agrovoc ...)', scroll_down: true) + @name = name + @placeholder = placeholder + @scroll_down = scroll_down + end +end diff --git a/app/components/ontology_search_input_component/ontology_search_input_component.html.haml b/app/components/ontology_search_input_component/ontology_search_input_component.html.haml new file mode 100644 index 000000000..74ca0d36c --- /dev/null +++ b/app/components/ontology_search_input_component/ontology_search_input_component.html.haml @@ -0,0 +1,11 @@ += render SearchInputComponent.new(placeholder: @placeholder, + name: @name, scroll_down: @scroll_down, ajax_url: '/ajax/ontologies?acronym=', + item_base_url: '/ontologies/', id_key:'acronym', + actions_links: {search_ontology_content: "/search?query=o", see_all_ontologies: "/ontologies?search=o"}) do |s| + + - s.template do + %a{href: "LINK", class: "search-content", 'data-turbo-frame': '_top'} + %p.search-element.home-searched-ontology + NAME(ACRONYM) + %p.home-result-type + TYPE \ No newline at end of file diff --git a/app/components/ontology_subscribe_button_component.rb b/app/components/ontology_subscribe_button_component.rb index 282c569a3..e300c0efa 100644 --- a/app/components/ontology_subscribe_button_component.rb +++ b/app/components/ontology_subscribe_button_component.rb @@ -1,17 +1,19 @@ # frozen_string_literal: true class OntologySubscribeButtonComponent < ViewComponent::Base - def initialize(ontology_id: , subscribed: , user_id:) + def initialize(ontology_id:, subscribed:, user_id:, count: 0, link: 'javascript:void(0);') super - @sub_text = subscribed ? "Unsubscribe" : "Subscribe" - @controller_params = { + @sub_text = subscribed ? 'UnWatch' : 'Watch' + @controller_params = { data: { controller: 'subscribe-notes', - 'subscribe-notes-ontology-id-value': ontology_id, + 'subscribe-notes-ontology-id-value': ontology_id, 'subscribe-notes-is-subbed-value': subscribed.to_s, - 'subscribe-notes-user-id-value': user_id, + 'subscribe-notes-user-id-value': user_id, action: 'click->subscribe-notes#subscribeToNotes' } } + @link = link + @count = count end end diff --git a/app/components/ontology_subscribe_button_component/ontology_subscribe_button_component_controller.js b/app/components/ontology_subscribe_button_component/ontology_subscribe_button_component_controller.js index 99b8e190f..94cdaf900 100644 --- a/app/components/ontology_subscribe_button_component/ontology_subscribe_button_component_controller.js +++ b/app/components/ontology_subscribe_button_component/ontology_subscribe_button_component_controller.js @@ -8,7 +8,7 @@ export default class extends Controller { isSubbed: Boolean, userId: String } - static targets = ["error", "loader"] + static targets = ["error", "loader", "text" ,"count"] subscribeToNotes() { let ontologyId = this.ontologyIdValue @@ -30,9 +30,12 @@ export default class extends Controller { this.isSubbedValue = !isSubbed // Change button text - let txt = linkElement.html(); - let newButtonText = txt.match("Unsubscribe") ? txt.replace("Unsubscribe", "Subscribe") : txt.replace("Subscribe", "Unsubscribe"); - linkElement.html(newButtonText); + let txt = this.textTarget.innerHTML + let count = parseInt(this.countTarget.innerHTML) + + let newButtonText = txt.match("UnWatch") ? txt.replace("UnWatch", "Watch") : txt.replace("Watch", "UnWatch"); + this.textTarget.innerHTML = newButtonText + this.countTarget.innerHTML = newButtonText.match("UnWatch") ? (count + 1) : (count - 1) }, error: () => { this.#hideSpinner() diff --git a/app/components/pill_button_component.rb b/app/components/pill_button_component.rb new file mode 100644 index 000000000..5371bee43 --- /dev/null +++ b/app/components/pill_button_component.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class PillButtonComponent < ViewComponent::Base + + def initialize(text: nil) + super + @text = text + end +end diff --git a/app/components/pill_button_component/pill_button_component.html.haml b/app/components/pill_button_component/pill_button_component.html.haml new file mode 100644 index 000000000..ffcb9ff34 --- /dev/null +++ b/app/components/pill_button_component/pill_button_component.html.haml @@ -0,0 +1,2 @@ +%button.pill-button + = @text || content \ No newline at end of file diff --git a/app/components/popup_link_text_component.rb b/app/components/popup_link_text_component.rb new file mode 100644 index 000000000..c1fa3412b --- /dev/null +++ b/app/components/popup_link_text_component.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class PopupLinkTextComponent < LinkTextComponent + + def initialize(text:) + super(text: text, icon: 'icons/popup-link') + end + +end diff --git a/app/components/rounded_button_component.rb b/app/components/rounded_button_component.rb new file mode 100644 index 000000000..47983fce1 --- /dev/null +++ b/app/components/rounded_button_component.rb @@ -0,0 +1,20 @@ +class RoundedButtonComponent < ViewComponent::Base + def initialize(icon: "json.svg", link: "#", size: "small", target: '') + @icon = icon + @link = link + @size = size + @target = target + end + + def size + case @size + when "small" + ["32px", "1", "16px"] + when "medium" + ["64px", "2", "32px"] + when "big" + ["100px", "2.5", "50px"] + end + end + +end \ No newline at end of file diff --git a/app/components/rounded_button_component/rounded_button_component.html.haml b/app/components/rounded_button_component/rounded_button_component.html.haml new file mode 100644 index 000000000..4baa20df9 --- /dev/null +++ b/app/components/rounded_button_component/rounded_button_component.html.haml @@ -0,0 +1,2 @@ +%a.rounded-button{:href => @link, style: "height:"+size[0]+"; width:"+size[0]+"; border-radius:"+size[2]+";", target:@target} + = inline_svg_tag @icon, style: "transform: scale("+size[1]+");" diff --git a/app/components/search_input_component.rb b/app/components/search_input_component.rb new file mode 100644 index 000000000..047b83b6b --- /dev/null +++ b/app/components/search_input_component.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +class SearchInputComponent < ViewComponent::Base + + renders_one :template + + def initialize(name: '', placeholder: '', actions_links: {}, + scroll_down: true, use_cache: true, + ajax_url:, + item_base_url:, + id_key:, + links_target: '_top') + super + @name = name + @placeholder = placeholder + @actions_links = actions_links + @use_cache = use_cache + @scroll_down = scroll_down + @ajax_url = ajax_url + @item_base_url = item_base_url + @id_key = id_key + @links_target = links_target + end + + def action_link_info(value) + if value.is_a?(Hash) + [value[:link] , value[:target]] + else + [value, '_top'] + end + end +end diff --git a/app/components/search_input_component/search_input_component.html.haml b/app/components/search_input_component/search_input_component.html.haml new file mode 100644 index 000000000..6a0a5657a --- /dev/null +++ b/app/components/search_input_component/search_input_component.html.haml @@ -0,0 +1,20 @@ +%div.search-inputs{'data-controller': 'search-input', + 'data-search-input-ajax-url-value': @ajax_url, + 'data-search-input-item-link-base-value': @item_base_url, + 'data-search-input-id-key-value': @id_key, + 'data-search-input-cache-value': @use_cache.to_s, + 'data-search-input-scroll-down-value': @scroll_down.to_s} + %input#home-search{:name => @name, :placeholder => @placeholder, + :type => "text", 'data-action': 'input->search-input#search blur->search-input#blur', + 'data-search-input-target': 'input'} + .search-container{'data-search-input-target': 'dropDown', 'data-action': 'mousedown->search-input#prevent'} + - @actions_links.each do |key, value| + - link, target = action_link_info(value) + %a.search-content#search-content{href: link, 'data-turbo-frame': target, 'data-search-input-target': 'actionLink'} + %p.mb-0 + %div + %img{src: asset_path("loop.svg")}/ + %p + =key.to_s.humanize + %template{'data-search-input-target': 'template'} + = template \ No newline at end of file diff --git a/app/components/search_input_component/search_input_component_controller.js b/app/components/search_input_component/search_input_component_controller.js new file mode 100644 index 000000000..2d2e624e2 --- /dev/null +++ b/app/components/search_input_component/search_input_component_controller.js @@ -0,0 +1,164 @@ +import {Controller} from "@hotwired/stimulus" +import useAjax from "../../javascript/mixins/useAjax"; + +// Connects to data-controller="search-input" +export default class extends Controller { + static targets = ["input", "dropDown", "actionLink", "template"] + static values = { + items: Array, + ajaxUrl: String, + itemLinkBase: String, + idKey: String, + cache: {type: Boolean, default: true}, + scrollDown: {type: Boolean, default: true} + } + + connect() { + this.input = this.inputTarget + this.dropDown = this.dropDownTarget + this.actionLinks = this.actionLinkTargets + this.items = this.itemsValue + } + + search() { + this.#searchInput() + } + + prevent(event){ + event.preventDefault(); + } + blur() { + this.dropDown.style.display = "none"; + this.input.classList.remove("home-dropdown-active"); + } + + #inputValue() { + return this.input.value.trim() + } + + #useCache() { + return this.cacheValue + } + #scrollDownEnabled(){ + return this.scrollDownValue + } + + #scrollDown(currentScroll) { + const startPosition = window.pageYOffset; + const distance = 300 - currentScroll; + const duration = 1000; + let start = null; + + function scrollAnimation(timestamp) { + if (!start) start = timestamp; + const progress = timestamp - start; + const scrollPosition = startPosition + easeInOutCubic(progress, 0, distance, duration); + window.scrollTo(0, scrollPosition); + if (progress < duration) { + window.requestAnimationFrame(scrollAnimation); + } + } + + function easeInOutCubic(t, b, c, d) { + t /= d / 2; + if (t < 1) return c / 2 * t * t * t + b; + t -= 2; + return c / 2 * (t * t * t + 2) + b; + } + + window.requestAnimationFrame(scrollAnimation); + } + + #fetchItems() { + if (this.items.length !== 0 && this.#useCache()) { + this.#renderLines() + } else { + useAjax({ + type: "GET", + url: this.ajaxUrlValue + this.#inputValue(), + dataType: "json", + success: (data) => { + this.items = data.map(x => { return {...x, link: (this.itemLinkBaseValue + x[this.idKeyValue])}} ) + this.#renderLines() + }, + error: () => { + console.log("error") + //TODO show errors + } + }) + } + } + + #renderLines() { + const inputValue = this.#inputValue(); + let results_list = [] + if (inputValue.length > 0) { + + this.actionLinks.forEach(action => { + const content = action.querySelector('p') + content.innerHTML = inputValue + const currentURL = new URL(action.href, document.location) + currentURL.searchParams.set(currentURL.searchParams.keys().next().value, inputValue) + action.href = currentURL.pathname + currentURL.search + }) + + this.dropDown.innerHTML = "" + let breaker = 0 + for (let i = 0; i < this.items.length; i++) { + if (breaker === 4) { + break; + } + // Get the current item from the ontologies array + const item = this.items[i]; + + let text = Object.values(item).reduce((acc, value) => acc + value, "") + + + // Check if the item contains the substring + if (text.toLowerCase().includes(inputValue.toLowerCase())) { + results_list.push(item); + breaker = breaker + 1 + } + } + + results_list.forEach((item) => { + let link = this.#renderLine(item); + this.dropDown.appendChild(link); + }); + + this.actionLinks.forEach(x => this.dropDown.appendChild(x)) + this.dropDown.style.display = "block"; + + this.input.classList.add("home-dropdown-active"); + if ((window.scrollY < 300) && this.#scrollDownEnabled()) { + this.#scrollDown(window.scrollY); + } + + } else { + this.dropDown.style.display = "none"; + this.input.classList.remove("home-dropdown-active"); + } + + } + + #renderLine(item) { + let template = this.templateTarget.content + let newElement = template.firstElementChild + let string = newElement.outerHTML + + Object.entries(item).forEach( ([key, value]) => { + key = key.toString().toUpperCase() + if (key === 'TYPE'){ + value = value.toString().split('/').slice(-1) + } + const regex = new RegExp('\\b' + key + '\\b', 'gi'); + string = string.replace(regex, value.toString()) + }) + + return new DOMParser().parseFromString(string, "text/html").body.firstElementChild + } + + #searchInput() { + this.#fetchItems() + } +} diff --git a/app/components/select_input_component.rb b/app/components/select_input_component.rb index 9bcfe5d1d..611cd3bdc 100644 --- a/app/components/select_input_component.rb +++ b/app/components/select_input_component.rb @@ -2,21 +2,37 @@ class SelectInputComponent < ViewComponent::Base - def initialize(id:, name:, values:, selected:, multiple: false, open_to_add_values: false) + def initialize(id:, name:, values:, selected:, multiple: false, open_to_add_values: true) super - @id = id + @id = id || "" @name = name @values = values @selected = selected @multiple = multiple @open_to_add_values = open_to_add_values end + + def call + select_input_tag(@id, @values, @selected, multiple: @multiple, open_to_add_values: @open_to_add_values) + end + + private + + def select_input_tag(id, values, selected, options = {}) + multiple = options[:multiple] || false + open_to_add_values = options[:open_to_add_values] || false - def options_values - if @selected.nil? || @selected.empty? - @selected = 0 - @values.unshift('') - end - options_for_select(@values, @selected) + select_html_options = { + id: "select_#{id}", + autocomplete: "off", + multiple: multiple, + data: { + controller: "select-input", + 'select-input-multiple-value': multiple, + 'select-input-open-add-value': open_to_add_values + } + } + #binding.pry + select_tag(id, options_for_select(values, selected), select_html_options) end end diff --git a/app/components/select_input_component/select_input_component.html.haml b/app/components/select_input_component/select_input_component.html.haml deleted file mode 100644 index a46f0ad29..000000000 --- a/app/components/select_input_component/select_input_component.html.haml +++ /dev/null @@ -1,10 +0,0 @@ -%div{:data => { controller: "select-input", 'select-input': {'multiple-value': @multiple.to_s}}} - = select_tag(@name, options_values, { multiple: @multiple, class: "form-control", id: "select_#{@id}", data: { action: "select-input#toggleOtherValue", "select-input-target": "selectedValues" } }) - - %div.d-flex.mt-1{style: "display:#{@open_to_add_values ? 'none !important;' : 'block;'}"} - = text_field_tag("add_#{@id}", nil, :style => "margin-right: 1em;width: 16em;display: none;", :placeholder => "Or provide the value", - data: {action: "keydown.enter->select-input#addValue", "select-input-target": "inputValueField"}, class: 'metadataInput form-control form-control-sm') - - %button.btn.btn-primary.btn-sm.add-value-btn{id: "btnAdd#{@id}", style: "display: none;", - data: { action: "select-input#addValue", "select-input-target": "btnValueField"}} - Add new value \ No newline at end of file diff --git a/app/components/select_input_component/select_input_component_controller.js b/app/components/select_input_component/select_input_component_controller.js index 7fb94e380..5002e90ea 100644 --- a/app/components/select_input_component/select_input_component_controller.js +++ b/app/components/select_input_component/select_input_component_controller.js @@ -1,137 +1,20 @@ -import {Controller} from "@hotwired/stimulus" -import {useChosen} from "../../javascript/mixins/useChosen"; +import { Controller } from "@hotwired/stimulus" +import TomSelect from "tom-select" export default class extends Controller { - static values = { - other: {type: Boolean, default: true}, - multiple: {type: Boolean, default: false} + multiple: Boolean, + openAdd : Boolean } - - static targets = ["btnValueField", "inputValueField", "selectedValues"] - connect() { - this.initMultipleSelect() - this.#displayOtherValueField() - } - - toggleOtherValue() { - if (this.otherValue && !this.multipleValue) { - this.#toggle() - } - } - - addValue(event) { - event.preventDefault() - - if (this.inputValueFieldTarget.value) { - let newOption = this.inputValueFieldTarget.value; - this.#addNewOption(newOption) - this.#selectNewOption(newOption) - if (!this.multipleValue) { - this.#hideOtherValueField() - } - } - } - - - initMultipleSelect() { - this.#addEmptyOption() - useChosen(this.selectedValuesTarget, { - width: '100%', - search_contains: true, - allow_single_deselect: !this.multipleValue, - }, (event) => { - if(this.multipleValue){ - let selected = event.target.selectedOptions - if (selected.length === 0) { - this.#selectEmptyOption() - } else { - this.#unSelectEmptyOption() - } - } - }) - } - - #selectEmptyOption() { - this.emptyOption.selected = true - this.emptyOption.disabled = false - } - - #unSelectEmptyOption() { - this.emptyOption.selected = false - this.emptyOption.disabled = true - } - - #addEmptyOption() { - this.emptyOption = document.createElement("option") - this.emptyOption.innerHTML = '' - this.emptyOption.value = '' - this.selectedValuesTarget.prepend(this.emptyOption) - } - - #selectNewOption(newOption) { - let selectedOptions = this.#selectedOptions(); - - - if (Array.isArray(selectedOptions)) { - selectedOptions.push(newOption); - } else { - selectedOptions = []; - selectedOptions.push(newOption) - } - - this.selectedValuesTarget.value = selectedOptions + let myOptions = {} if (this.multipleValue) { - const options = this.selectedValuesTarget.options - for (const element of options) { - element.selected = selectedOptions.indexOf(element.value) >= 0; - } - jQuery(this.selectedValuesTarget).trigger("chosen:updated") + myOptions['plugins'] = ['remove_button']; } - - } - - #addNewOption(newOption) { - let option = document.createElement("option"); - option.value = newOption; - option.text = newOption; - this.selectedValuesTarget.add(option) - } - - #selectedOptions() { - if (this.multipleValue) { - const selectedOptions = []; - for (let option of this.selectedValuesTarget.options) { - if (option.selected) { - selectedOptions.push(option.value); - } - } - return selectedOptions - } else { - return this.selectedValuesTarget.value + if (this.openAddValue) { + myOptions['create'] = true; } + new TomSelect(this.element, myOptions); } - #toggle() { - if (this.selectedValuesTarget.value === 'other') { - this.#displayOtherValueField() - } else { - this.#hideOtherValueField() - } - } - - #displayOtherValueField() { - this.inputValueFieldTarget.value = "" - this.btnValueFieldTarget.style.display = 'block' - this.inputValueFieldTarget.style.display = 'block' - } - - #hideOtherValueField() { - this.inputValueFieldTarget.value = "" - this.btnValueFieldTarget.style.display = 'none' - this.inputValueFieldTarget.style.display = 'none' - } - - } \ No newline at end of file diff --git a/app/components/summary_section_component.rb b/app/components/summary_section_component.rb new file mode 100644 index 000000000..0ca33932f --- /dev/null +++ b/app/components/summary_section_component.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class SummarySectionComponent < ViewComponent::Base + renders_many :action_links + + def initialize(title: , link: nil, link_title: nil, show_card: true) + super + @title = title + @link = link + @link_title = link_title + @show_card = show_card + end + + def show_card? + @show_card + end +end diff --git a/app/components/summary_section_component/summary_section_component.html.haml b/app/components/summary_section_component/summary_section_component.html.haml new file mode 100644 index 000000000..c43356866 --- /dev/null +++ b/app/components/summary_section_component/summary_section_component.html.haml @@ -0,0 +1,19 @@ +%h2.card_title + %span.mr-2 + = @title + - if @link + %span + = link_to(@link, target: "_blank") do + = render Display::InfoTooltipComponent.new(text: @link_title) + + - if action_links? + %span + = render Layout::HorizontalListComponent.new do |l| + - action_links.each { |link| l.element { raw link }} + +- if show_card? + = render Layout::CardComponent.new do + = content +- else + %div + = content \ No newline at end of file diff --git a/app/components/switch_input_component.rb b/app/components/switch_input_component.rb index e8ba66431..3b7f67781 100644 --- a/app/components/switch_input_component.rb +++ b/app/components/switch_input_component.rb @@ -3,7 +3,7 @@ class SwitchInputComponent < ViewComponent::Base - def initialize(id:, name: , label: nil, value: '', checked: false, boolean_switch: false) + def initialize(id:, name: , label: '', value: '', checked: false, boolean_switch: false) super @id = id @name = name diff --git a/app/components/switch_input_component/switch_input_component.html.haml b/app/components/switch_input_component/switch_input_component.html.haml index 1f74a7c24..4fe4ccbac 100644 --- a/app/components/switch_input_component/switch_input_component.html.haml +++ b/app/components/switch_input_component/switch_input_component.html.haml @@ -1,6 +1,9 @@ -%div.custom-control.custom-switch +%div.switch-filter - if @boolean_switch = hidden_field_tag @name, @value - = check_box_tag check_box_name, @value, @checked, class: 'custom-control-input', id: check_box_id, onChange: "#{boolean_switch_action}" - %label.custom-control-label{for: check_box_id} - = content || @label \ No newline at end of file + - if content || !@label.empty? + %p + = content || @label + %label.switch{for: check_box_id} + = check_box_tag check_box_name, @value, @checked, class: '', id: check_box_id, onChange: "#{boolean_switch_action}" + %span.slider \ No newline at end of file diff --git a/app/components/tab_item_component.rb b/app/components/tab_item_component.rb new file mode 100644 index 000000000..b6612bb5b --- /dev/null +++ b/app/components/tab_item_component.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +class TabItemComponent < ViewComponent::Base + + include ActionView::Helpers::UrlHelper + + def initialize(id: nil, title: nil, path: nil, page_name: '', selected: false) + super + @id = id + @title = title + @path = path + @page_name = page_name + @selected = selected + end + + def selected_item? + @selected + end + + def item_id + id.parameterize.underscore + end + + def target_id + "#{item_id}_content" + end + + + def id + @title || @id + end + + def title + @title&.humanize + end + + def active_class + selected_item? ? 'active show' : '' + end + + def call + if title && !title.empty? + link_to(title, @path, id: "#{item_id}_tab", class: "#{active_class} tab-link") + else + link_to(@path, id: "#{item_id}_tab", class: "#{active_class} tab-link") do + content + end + end + end + +end diff --git a/app/components/table_cell_component.rb b/app/components/table_cell_component.rb new file mode 100644 index 000000000..2e459cb32 --- /dev/null +++ b/app/components/table_cell_component.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class TableCellComponent < ViewComponent::Base + + def initialize(width: nil, colspan: nil,type: 'td') + super + @width = width + @type = type + @colspan = colspan + end + + def call + options = {} + options[:width] = @width if @width + options[:colspan] = @colspan if @colspan + content_tag(@type, content&.html_safe, options) + end +end diff --git a/app/components/table_component.rb b/app/components/table_component.rb new file mode 100644 index 000000000..9670464db --- /dev/null +++ b/app/components/table_component.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class TableComponent < ViewComponent::Base + + renders_one :header, TableRowComponent + renders_many :rows, TableRowComponent + + def initialize(id: '', stripped: true, borderless: false, layout_fixed: false ) + super + @id = id + @stripped = stripped + @borderless = borderless + @layout_fixed = layout_fixed + end + + def stripped_class + @stripped ? 'table-content-stripped' : '' + end + + def borderless_class + @borderless ? 'table-content-borderless' : '' + end + + def layout_fixed_class + @layout_fixed ? 'table-layout-fixed' : '' + end + + def add_row(*array, &block) + self.row.create(*array, &block) + end +end diff --git a/app/components/table_component/table_component.html.haml b/app/components/table_component/table_component.html.haml new file mode 100644 index 000000000..ed479fb66 --- /dev/null +++ b/app/components/table_component/table_component.html.haml @@ -0,0 +1,7 @@ +%table.table-content{id: @id, class: stripped_class + ' ' + borderless_class + ' ' + layout_fixed_class} + %thead + = header + %tbody{id: "#{@id}_table_body"} + - rows.each do |row| + = row + = content \ No newline at end of file diff --git a/app/components/table_row_component.rb b/app/components/table_row_component.rb new file mode 100644 index 000000000..68620a05c --- /dev/null +++ b/app/components/table_row_component.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class TableRowComponent < ViewComponent::Base + + renders_many :cells, TableCellComponent + + def initialize(id: '', class_css: '') + super + @id = id + @class_css = class_css + end + + def create(*array, &block) + array.each do |key_value| + key, value = key_value.to_a.first + self.cell(type: key) { value&.to_s } + end + block.call(self) if block_given? + end + + def th(width: nil, colspan: nil, &block) + self.cell(type: 'th', width: width, colspan: colspan, &block) + end + + def td(width: nil, colspan: nil, &block) + self.cell(type: 'td', width: width, colspan: colspan, &block) + end +end diff --git a/app/components/table_row_component/table_row_component.html.haml b/app/components/table_row_component/table_row_component.html.haml new file mode 100644 index 000000000..c25e45eee --- /dev/null +++ b/app/components/table_row_component/table_row_component.html.haml @@ -0,0 +1,4 @@ +%tr{id: @id, class: @class_css} + - cells.each do |cell| + = cell + = content \ No newline at end of file diff --git a/app/components/tabs_container_component.rb b/app/components/tabs_container_component.rb new file mode 100644 index 000000000..bb9ecaa21 --- /dev/null +++ b/app/components/tabs_container_component.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +class TabsContainerComponent < ViewComponent::Base + + renders_many :items, TabItemComponent + renders_many :item_contents + renders_one :pinned_right + + def initialize(id: '', url_parameter: nil, type: 'primary') + super + @url_parameter = url_parameter + @type = type + @id = id + end + + def container_class + case @type + when 'primary' + 'tabs-container' + when 'outline' + 'tabs-container outline-tabs' + when 'pill' + 'pill-tabs-container' + else + 'tabs-container' + end + end + + def item_target(item) + "##{@id}#{item.target_id}" + end + + def item_content_id(item) + @id + item.target_id + end + + def tabs_container_data(item) + { + toggle: 'tab', + target: item_target(item), + 'tab-id': item.id, + 'tab-title': item.title, + 'url-parameter': @url_parameter, + action: 'click->tabs-container#selectTab' + } + end +end diff --git a/app/components/tabs_container_component/tabs_container_component.html.haml b/app/components/tabs_container_component/tabs_container_component.html.haml new file mode 100644 index 000000000..2ee9f8818 --- /dev/null +++ b/app/components/tabs_container_component/tabs_container_component.html.haml @@ -0,0 +1,16 @@ +%div{data: {controller:'tabs-container'}, class: container_class} + .tab-items.nav + - items.each do |item| + %div{data: tabs_container_data(item), class: item.active_class + ' nav-item'} + = item + - unless @pill + %hr + - if pinned_right? + %div.d-flex.mx-1 + = pinned_right + +.tab-content + - item_contents.each_with_index do |item_content, index| + %div.tab-pane{id: item_content_id(items[index]), class: items[index].active_class} + = item_content + diff --git a/app/components/tabs_container_component/tabs_container_component_controller.js b/app/components/tabs_container_component/tabs_container_component_controller.js new file mode 100644 index 000000000..9991b699f --- /dev/null +++ b/app/components/tabs_container_component/tabs_container_component_controller.js @@ -0,0 +1,43 @@ +import {Controller} from "@hotwired/stimulus"; +import {HistoryService} from "../../javascript/mixins/useHistory"; + +export default class extends Controller { + + connect() { + this.event = null + } + + + selectTab(event) { + this.event = event + if (this.#parameter()) { + this.#updateURL() + } + this.element.dispatchEvent(new CustomEvent("tab-selected", { + bubbles: true, + detail: {data: {selectedTab: this.#pageId()}} + })) + } + + #pageId() { + return this.event.currentTarget.getAttribute("data-tab-id") + } + + #title() { + return this.event.currentTarget.getAttribute("data-tab-title") + } + + #parameter() { + return this.event.currentTarget.getAttribute("data-url-parameter") + } + + + #url() { + return `?${this.#parameter()}=${this.#pageId()}` + } + + #updateURL() { + (new HistoryService()).pushState({[this.#parameter()]: this.#pageId()}, this.#title(), this.#url()); + } + +} diff --git a/app/components/text_area_field_component.rb b/app/components/text_area_field_component.rb new file mode 100644 index 000000000..5da424e33 --- /dev/null +++ b/app/components/text_area_field_component.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class TextAreaFieldComponent < ViewComponent::Base + + def initialize(value: , see_more_text:'See more...' , see_less_text: 'See less...') + super + @value = value + @see_more_text = see_more_text + @see_less_text = see_less_text + end + +end \ No newline at end of file diff --git a/app/components/text_area_field_component/text_area_field_component.html.haml b/app/components/text_area_field_component/text_area_field_component.html.haml new file mode 100644 index 000000000..6a58213be --- /dev/null +++ b/app/components/text_area_field_component/text_area_field_component.html.haml @@ -0,0 +1,5 @@ +%div{data:{controller:"text-truncate", 'text-truncate-more-text-value': @see_more_text , 'text-truncate-less-text-value': @see_less_text}} + %span.text-content{'data-text-truncate-target': 'content'} + = @value + %span.see_more_text{data:{'text-truncate-target': 'button', 'action':"click->text-truncate#toggle"}} + = @see_more_text \ No newline at end of file diff --git a/app/components/turbo_modal_component.rb b/app/components/turbo_modal_component.rb index 24356efef..3cb4af778 100644 --- a/app/components/turbo_modal_component.rb +++ b/app/components/turbo_modal_component.rb @@ -3,11 +3,12 @@ class TurboModalComponent < ViewComponent::Base include Turbo::FramesHelper - def initialize(id: '', title:'', size: 'modal-lg') + def initialize(id: '', title: '', size: 'modal-lg', show: false) super @id = id @title = title @size = size + @show = show end end diff --git a/app/components/turbo_modal_component/turbo_modal_component.html.haml b/app/components/turbo_modal_component/turbo_modal_component.html.haml index 0d4490921..e5ad17503 100644 --- a/app/components/turbo_modal_component/turbo_modal_component.html.haml +++ b/app/components/turbo_modal_component/turbo_modal_component.html.haml @@ -1,11 +1,11 @@ -%div.modal{id: @id, 'data-controller':"turbo-modal"} +%div.modal{id: @id, 'data-controller':"turbo-modal", 'data-turbo-modal-show-value': @show.to_s} %div.modal-dialog{class: @size} %div.modal-content %div.modal-header %h5.modal-title = @title %button.close{type:'button', data: { action: "turbo-modal#hide" }} - %span × + %span.shape.btn.btn-primary.p-1 × %div.modal-body = render TurboFrameComponent.new(id: 'application_modal_content', data: { 'turbo-modal-target': 'content'}) do = content diff --git a/app/components/turbo_modal_component/turbo_modal_component_controller.js b/app/components/turbo_modal_component/turbo_modal_component_controller.js index acc493a83..2942770ed 100644 --- a/app/components/turbo_modal_component/turbo_modal_component_controller.js +++ b/app/components/turbo_modal_component/turbo_modal_component_controller.js @@ -4,6 +4,16 @@ import ShowModalController from "../../javascript/controllers/show_modal_control export default class extends ShowModalController { static targets = ["content"] + static values = { + show: Boolean + } + + connect() { + super.connect(); + if (this.showValue) { + this.show() + } + } show() { this.modal.showModal(this.element) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d9b2eefce..7e1174082 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -64,6 +64,10 @@ class ApplicationController < ActionController::Base before_action :set_global_thread_values, :domain_ontology_set, :authorize_miniprofiler, :clean_empty_strings_from_params_arrays, :init_trial_license + def show_image_modal + url = params[:url] + render turbo_stream: helpers.prepend('application_modal_content') { helpers.image_tag(url, style:'width: 100%') } + end def set_global_thread_values Thread.current[:session] = session diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb index 83051c4e1..b47208ac2 100644 --- a/app/controllers/notes_controller.rb +++ b/app/controllers/notes_controller.rb @@ -103,7 +103,7 @@ def create success_message = 'New comment added successfully' locals = { note: new_note, ontology_acronym: ontology_acronym, parent_type: parent_type } partial = 'notes/note_line' - container_id = "#{parent_type}_notes_table_content" + container_id = "#{parent_type}_notes_table_body" alerts_container_id = nil end diff --git a/app/controllers/ontologies_controller.rb b/app/controllers/ontologies_controller.rb index 7b4a2ef9b..9cf416011 100644 --- a/app/controllers/ontologies_controller.rb +++ b/app/controllers/ontologies_controller.rb @@ -385,8 +385,12 @@ def widgets render partial: 'ontologies/sections/widgets', layout: 'ontology_viewer' end end - - + def ajax_ontologies + + + render json: LinkedData::Client::Models::Ontology.all(include_views: true, + display: 'acronym,name', display_links: false, display_context: false) + end private def ontology_params diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 557f2ef0c..6863fc264 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -7,6 +7,20 @@ module ApplicationHelper + include ModalHelper + + RESOLVE_NAMESPACE = {:omv => "http://omv.ontoware.org/2005/05/ontology#", :skos => "http://www.w3.org/2004/02/skos/core#", :owl => "http://www.w3.org/2002/07/owl#", + :rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", :rdfs => "http://www.w3.org/2000/01/rdf-schema#", :metadata => "http://data.bioontology.org/metadata/", + :metadata_def => "http://data.bioontology.org/metadata/def/", :dc => "http://purl.org/dc/elements/1.1/", :xsd => "http://www.w3.org/2001/XMLSchema#", + :oboinowl_gen => "http://www.geneontology.org/formats/oboInOwl#", :obo_purl => "http://purl.obolibrary.org/obo/", + :umls => "http://bioportal.bioontology.org/ontologies/umls/", :door => "http://kannel.open.ac.uk/ontology#", :dct => "http://purl.org/dc/terms/", + :void => "http://rdfs.org/ns/void#", :foaf => "http://xmlns.com/foaf/0.1/", :vann => "http://purl.org/vocab/vann/", :adms => "http://www.w3.org/ns/adms#", + :voaf => "http://purl.org/vocommons/voaf#", :dcat => "http://www.w3.org/ns/dcat#", :mod => "http://www.isibang.ac.in/ns/mod#", :prov => "http://www.w3.org/ns/prov#", + :cc => "http://creativecommons.org/ns#", :schema => "http://schema.org/", :doap => "http://usefulinc.com/ns/doap#", :bibo => "http://purl.org/ontology/bibo/", + :wdrs => "http://www.w3.org/2007/05/powder-s#", :cito => "http://purl.org/spar/cito/", :pav => "http://purl.org/pav/", :nkos => "http://w3id.org/nkos/nkostype#", + :oboInOwl => "http://www.geneontology.org/formats/oboInOwl#", :idot => "http://identifiers.org/idot/", :sd => "http://www.w3.org/ns/sparql-service-description#", + :cclicense => "http://creativecommons.org/licenses/"} + def get_apikey unless session[:user].nil? return session[:user].apikey @@ -449,14 +463,14 @@ def xmldatetime_to_date(xml_date_time_str) #return DateTime.xmlschema( xml_date_time_str ).to_date.to_s end - def flash_class(level) + def notification_type(flash_key) bootstrap_alert_class = { - 'notice' => 'alert-info', - 'success' => 'alert-success', - 'error' => 'alert-danger', - 'alert' => 'alert-danger' + 'notice' => 'success', + 'success' => 'success', + 'error' => 'error', + 'alert' => 'alert' } - bootstrap_alert_class[level] + bootstrap_alert_class[flash_key] end ###BEGIN ruby equivalent of JS code in bp_ajax_controller. @@ -558,36 +572,7 @@ def ontology_viewer_page_name(ontology_name, concept_name_title , page) ontology_name + " | " +concept_name_title + " - #{page.capitalize}" end - def link_to_modal(name, options = nil, html_options = nil, &block) - new_data = { - controller: 'show-modal', turbo: true, - turbo_frame: 'application_modal_content', - action: 'click->show-modal#show' - } - - html_options[:data].merge!(new_data) do |_, old, new| - "#{old} #{new}" - end - if name.nil? - link_to(options, html_options, &block) - else - link_to(name, options, html_options) - end - end - def submit_to_modal(name, html_options = nil, &block) - new_data = { - controller: 'show-modal', turbo: true, - turbo_frame: 'application_modal_content', - action: 'click->show-modal#show' - } - - html_options[:data].merge!(new_data) do |_, old, new| - "#{old} #{new}" - end - - submit_tag(name || "save", html_options) - end def uri?(url) url =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/ @@ -609,4 +594,50 @@ def skos? submission = @submission || @submission_latest submission&.hasOntologyLanguage === 'SKOS' end + + def current_page?(path) + request.path.eql?(path) + end + + def request_lang + lang = params[:language] || params[:lang] + lang = 'EN' unless lang + lang.upcase + end + + def bp_config_json + # For config settings, see + # config/bioportal_config.rb + # config/initializers/ontologies_api_client.rb + config = { + org: $ORG, + org_url: $ORG_URL, + site: $SITE, + org_site: $ORG_SITE, + ui_url: $UI_URL, + apikey: LinkedData::Client.settings.apikey, + userapikey: get_apikey, + rest_url: LinkedData::Client.settings.rest_url, + proxy_url: $PROXY_URL, + biomixer_url: $BIOMIXER_URL, + annotator_url: $ANNOTATOR_URL, + ncbo_annotator_url: $NCBO_ANNOTATOR_URL, + ncbo_apikey: $NCBO_API_KEY, + interportal_hash: $INTERPORTAL_HASH, + resolve_namespace: RESOLVE_NAMESPACE + } + config[:ncbo_slice] = @subdomain_filter[:acronym] if (@subdomain_filter[:active] && !@subdomain_filter[:acronym].empty?) + config.to_json + end + + + def portal_name + $SITE + end + + def navitems + items = [["/ontologies", "Browse"],["/mappings", "Mappings"],["/recommender", "Recommender"],["/annotator", "Annotator"], ["/landscape", "Landscape"]] + end + + end diff --git a/app/helpers/components_helper.rb b/app/helpers/components_helper.rb new file mode 100644 index 000000000..3b931cb31 --- /dev/null +++ b/app/helpers/components_helper.rb @@ -0,0 +1,80 @@ +module ComponentsHelper + def info_tooltip(text) + render Display::InfoTooltipComponent.new(text: text) + end + + def empty_state_message(message) + content_tag(:p, message.html_safe, class: 'font-italic field-description_text') + end + + def properties_list_component(c, properties, &block) + properties.each do |k, v| + c.row do + content = if block_given? + capture(v, &block) + else + v + end + render FieldContainerComponent.new(label: attr_label(k)) do + content + end + end + end + + end + + + def horizontal_list_container(values, &block) + return if Array(values).empty? + + render Layout::HorizontalListComponent.new do |l| + Array(values).each do |v| + l.element do + capture(v, &block) + end + end + end + end + + def list_container(values, &block) + return if Array(values).empty? + + render Layout::ListComponent.new do |l| + Array(values).each do |v| + l.row do + capture(v, &block) + end + end + end + end + + def properties_card(title, tooltip, properties, &block) + render Layout::CardComponent.new do |d| + d.header(text: title, tooltip: tooltip) + render(Layout::ListComponent.new) do |c| + if properties + properties_list_component(c, properties, &block) + else + capture(c, &block) + end + end + end + end + + def properties_dropdown(id, title, tooltip, properties, &block) + render DropdownContainerComponent.new(title: title, id: id, tooltip: tooltip) do |d| + d.empty_state do + properties_string = properties.keys[0..4].map{|key| "#{attr_label(key)}" }.join(', ')+'... ' if properties + empty_state_message "The fields #{properties_string} are empty" + end + + render Layout::ListComponent.new do |c| + if properties + properties_list_component(c, properties, &block) + else + capture(c, &block) + end + end + end + end +end diff --git a/app/helpers/modal_helper.rb b/app/helpers/modal_helper.rb new file mode 100644 index 000000000..568c0f866 --- /dev/null +++ b/app/helpers/modal_helper.rb @@ -0,0 +1,42 @@ +module ModalHelper + + def link_to_modal(name, options = nil, html_options = nil, &block) + html_options = modal_controller_data(html_options) + if name.nil? + link_to(options, html_options, &block) + else + link_to(PopupLinkTextComponent.new(text: name).call, options, html_options) + end + end + + def submit_to_modal(name, html_options = nil) + html_options = modal_controller_data(html_options) + + submit_tag(name || 'save', html_options) + end + + def modal_frame_container(id = 'application_modal') + render TurboModalComponent.new(id: id) + end + + def render_in_modal(id = 'application_modal', &block) + render TurboFrameComponent.new(id: "#{id}_content") do + block.call.html_safe if block_given? + end + end + + private + + def modal_controller_data(html_options) + new_data = { + controller: 'show-modal', turbo: true, + turbo_frame: 'application_modal_content', + action: 'click->show-modal#show' + } + + html_options[:data].merge!(new_data) do |_, old, new| + "#{old} #{new}" + end + html_options + end +end diff --git a/app/helpers/submissions_helper.rb b/app/helpers/submissions_helper.rb index a9dc3d8b9..bf2a48bb4 100644 --- a/app/helpers/submissions_helper.rb +++ b/app/helpers/submissions_helper.rb @@ -49,11 +49,11 @@ def metadata_section(id, label, collapsed: true, parent_id: nil, &block) def attribute_container(attr, required: false, &block) if show_attribute?(attr, required) - content_tag(:div) do - capture(&block) - end + content_tag(:div) do + capture(&block) end end + end def inline_save? !@inline_save.nil? && @inline_save @@ -355,6 +355,11 @@ def generate_list_field_input(attr, name, values, field_func) c.template do method(field_func).call("#{name}[NEW_RECORD]", '', :id => attr["attribute"].to_s + "_" + @ontology.acronym, class: "metadataInput form-control my-1") end + + c.empty_state do + hidden_field_tag "#{name}[#{values.size}]" + end + values.each_with_index do |metadata_val, i| c.row do method(field_func).call("#{name}[#{i}]", metadata_val, :id => "submission_#{attr["attribute"].to_s}" + "_" + @ontology.acronym, class: "metadataInput my-1 form-control") diff --git a/app/javascript/component_controllers/index.js b/app/javascript/component_controllers/index.js index dc1edde16..482bc6786 100644 --- a/app/javascript/component_controllers/index.js +++ b/app/javascript/component_controllers/index.js @@ -2,7 +2,7 @@ import {application} from "../controllers/application"; import TurboModalController from "../../components/turbo_modal_component/turbo_modal_component_controller" import FileInputLoaderController - from "../../components/file_input_loader_component/file_input_loader_component_controller"; + from "../../components/input/file_input_component/file_input_loader_component_controller"; import Select_input_component_controller from "../../components/select_input_component/select_input_component_controller"; @@ -10,9 +10,20 @@ import Metadata_selector_component_controller from "../../components/metadata_selector_component/metadata_selector_component_controller"; import Ontology_subscribe_button_component_controller from "../../components/ontology_subscribe_button_component/ontology_subscribe_button_component_controller"; +import Search_input_component_controller + from "../../components/search_input_component/search_input_component_controller"; +import CircleProgressBarComponentController from "../../components/circle_progress_bar_component/circle_progress_bar_component_controller" +import Tabs_container_component_controller + from "../../components/tabs_container_component/tabs_container_component_controller"; +import Progress_pages_component_controller + from "../../components/layout/progress_pages_component/progress_pages_component_controller"; application.register("turbo-modal", TurboModalController) application.register("file-input", FileInputLoaderController) application.register("select-input", Select_input_component_controller) application.register("metadata-select", Metadata_selector_component_controller) application.register("subscribe-notes", Ontology_subscribe_button_component_controller) +application.register("search-input", Search_input_component_controller) +application.register("tabs-container", Tabs_container_component_controller) +application.register("circle-progress-bar", CircleProgressBarComponentController) +application.register("progress-pages", Progress_pages_component_controller) diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js index 258ab85b4..185546806 100644 --- a/app/javascript/controllers/application.js +++ b/app/javascript/controllers/application.js @@ -12,7 +12,8 @@ import Flatpickr from "stimulus-flatpickr" application.register("flatpickr", Flatpickr); import NestedForm from 'stimulus-rails-nested-form' application.register('nested-form', NestedForm) - +import ReadMore from 'stimulus-read-more' +application.register('read-more', ReadMore) export { application } diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index 00e656994..9dfec3b78 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -57,9 +57,18 @@ application.register("simple-tree", SimpleTreeController) import SkosCollectionColorsController from "./skos_collection_colors_controller" application.register("skos-collection-colors", SkosCollectionColorsController) +import TextTruncateController from "./text_truncate_controller" +application.register("text-truncate", TextTruncateController) + +import Ontology_viewer_tabs_controller from "./ontology_viewer_tabs_controller" +application.register("ontology-viewer-tabs", Ontology_viewer_tabs_controller) + import TooltipController from "./tooltip_controller" application.register("tooltip", TooltipController) +import TopnavResponsivenessController from "./topnav_responsiveness_controller" +application.register("topnav-responsiveness", TopnavResponsivenessController) + import TurboFrameController from "./turbo_frame_controller" application.register("turbo-frame", TurboFrameController) diff --git a/app/javascript/controllers/language_change_controller.js b/app/javascript/controllers/language_change_controller.js new file mode 100644 index 000000000..e4d891317 --- /dev/null +++ b/app/javascript/controllers/language_change_controller.js @@ -0,0 +1,19 @@ +import { Controller } from "@hotwired/stimulus" + +// Connects to data-controller="language-change" +export default class extends Controller { + + dispatchLangChangeEvent() { + + this.element.dispatchEvent(new CustomEvent('lang_changed', { + bubbles: true, + cancelable: true, + detail: { + data: { + language: [this.element.value] + } + } + })); + + } +} diff --git a/app/javascript/controllers/ontology_viewer_tabs_controller.js b/app/javascript/controllers/ontology_viewer_tabs_controller.js new file mode 100644 index 000000000..6ddf9b71b --- /dev/null +++ b/app/javascript/controllers/ontology_viewer_tabs_controller.js @@ -0,0 +1,46 @@ +import { Controller } from "@hotwired/stimulus" +import {HistoryService} from "../mixins/useHistory"; + + +export default class extends Controller { + + + static targets = ["languageSelector"] + static values = { + languageSections: Array + } + + connect() { + this.changeEvent = this.languageSelectorTarget.addEventListener("change", (e) => { + this.languageSectionsValue.forEach(p => { + let elem = document.getElementById("language_selector_hidden_"+p) + if(elem){ + elem.value = e.target.value + elem.dispatchEvent(new Event('change')) + } + }) + }) + } + + destroy(){ + this.changeEvent.removeEventListener() + } + + updateLanguageSelector(event) { + console.log('language selector update') + let page = event.detail.data.selectedTab + this.#disableLanguageSelector(page) + } + + #disableLanguageSelector(selectedSection){ + if (this.languageSectionsValue.includes(selectedSection)){ + this.languageSelectorTarget.removeAttribute("disabled") + this.languageSelectorTarget.style.visibility = 'visible' + } else{ + this.languageSelectorTarget.setAttribute("disabled", true) + this.languageSelectorTarget.style.visibility = 'hidden' + } + } + + +} diff --git a/app/javascript/controllers/text_truncate_controller.js b/app/javascript/controllers/text_truncate_controller.js new file mode 100644 index 000000000..b3c235e83 --- /dev/null +++ b/app/javascript/controllers/text_truncate_controller.js @@ -0,0 +1,21 @@ +import ReadMore from "stimulus-read-more"; + +// Connects to data-controller="text-truncate" +export default class extends ReadMore { + static targets = ['button'] + + connect() { + super.connect() + if (!this.#isTextClamped()) { + this.#hideButton() + } + } + + #isTextClamped() { + return this.contentTarget.scrollHeight > this.contentTarget.clientHeight + } + + #hideButton() { + this.buttonTarget.style.display = 'none' + } +} diff --git a/app/javascript/controllers/topnav_responsiveness_controller.js b/app/javascript/controllers/topnav_responsiveness_controller.js new file mode 100644 index 000000000..218919ff8 --- /dev/null +++ b/app/javascript/controllers/topnav_responsiveness_controller.js @@ -0,0 +1,22 @@ +import { Controller } from "@hotwired/stimulus" + +// Connects to data-controller="topnav-responsiveness" +export default class extends Controller { + static targets = ['navMenu'] + + connect() { + let checkbox = this.navMenuTarget + let divs = document.querySelectorAll('.top-nav, .top-nav-ul, .nav-items, .nav-ul-li, .nav-input, .nav-a, .nav-language, .supportMenuDropdownLink'); + checkbox.addEventListener('change', function() { + if (this.checked) { + divs.forEach(function(div) { + div.classList.add('show-responsive'); + }); + } else { + divs.forEach(function(div) { + div.classList.remove('show-responsive'); + }); + } + }); + } +} diff --git a/app/views/admin/index.html.haml b/app/views/admin/index.html.haml index a67c02674..d8527a23f 100644 --- a/app/views/admin/index.html.haml +++ b/app/views/admin/index.html.haml @@ -42,33 +42,27 @@ = link_to("Reset UI cache connection", "#", id: "reset_memcache_connection_action", class: "btn btn-outline-secondary btn-sm admin-action-item", role: "button") = link_to("Flush GOO cache", "#", id: "flush_goo_cache_action", class: "btn btn-outline-secondary btn-sm admin-action-item", role: "button") = link_to("Flush HTTP cache", "#", id: "flush_http_cache_action", class: "btn btn-outline-secondary btn-sm", role: "button") - - -# Check for updates + %div#site-admin-update-check.mb-5 %div.site-admin-page-header VERSION MANAGEMENT %dive.site-admin-page-section = link_to("Check for updates", "#", id: "update_check_action", class: "btn btn-outline-secondary btn-sm", role: "button") - -# View appliance ID %div#site-admin-appliance-id.mb-5 %div.site-admin-page-header APPLIANCE ID %dive.site-admin-page-section %div#appliance-id %span - - -# Clear caches + %div#site-admin-clear-caches.my-5 %div.site-admin-page-header MONITORING LINKS %dive.site-admin-page-section = link_to("Newrelic", "https://login.newrelic.com/login", target: '_blank', id: "newrelic_link", class: "btn btn-outline-secondary btn-sm admin-action-item", role: "button") = link_to("StatusCake", "https://app.statuscake.com/Login", target: '_blank', id: "statuscake_link", class: "btn btn-outline-secondary btn-sm admin-action-item", role: "button") - - - -# Ontology Administration tab - %div.tab-pane.fade{id: "ontology-admin", role: "tabpanel", aria: { labelledby: "ontology-admin-tab" }} + - t.item_content do %div.ontologies_list_container.mt-3 %table{:style => "float:left;"} %tr @@ -79,9 +73,8 @@ %span.ui-button-text{:class => "report_date_generated_button"} %p.tab_description{:style => "clear:both;"} %table#adminOntologies.zebra{:cellpadding => "0", :cellspacing => "0", :width => "100%"} + - t.item_content do - -# Licensing tab - %div.tab-pane.fade{id: "licensing", role: "tabpanel", aria: { labelledby: "licensing-admin-tab" }} %div#renew-license-notice %table.table.table-sm.table-bordered.mt-5#license-table @@ -89,22 +82,18 @@ %tr %th{scope: "col"} Licensed to %th{scope: "col"} Appliance ID - %th{scope: "col"} Valid till + %th{scope: "col"} Valid till %th{scope: "col"} Days remaining %tbody %div.mb-5#renew-license-button - = link_to("Renew license", new_admin_license_path(), class: "btn btn-primary", role: "button", remote: "true") + = link_to("Renew license", new_admin_license_path, class: "btn btn-primary", role: "button", remote: "true") %div.mb-5#renew-license-form - - -# Users tab - %div.tab-pane.fade{id: "users", role: "tabpanel", aria: { labelledby: "users-admin-tab" }} + - t.item_content do %div.ontologies_list_container.mt-3 %table#adminUsers.zebra{:cellpadding => "0", :cellspacing => "0", :width => "100%"} - - -# metadata tab - %div.tab-pane.fade{id: "ontologies_metadata_curator", role: "tabpanel", aria: { labelledby: "ontologies_metadata_curator-admin-tab" }} + - t.item_content do = render partial: 'ontologies_metadata_curator/metadata_tab' -# Groups tab diff --git a/app/views/annotator/index.html.haml b/app/views/annotator/index.html.haml index 6c12a1f55..ca9fa67bb 100644 --- a/app/views/annotator/index.html.haml +++ b/app/views/annotator/index.html.haml @@ -3,7 +3,7 @@ %head = javascript_include_tag "bp_annotator" -%div.container-fluid +%div.container-fluid.flex-grow-1 %div.row %div.col %h2.mt-3 Annotator diff --git a/app/views/annotatorplus/index.html.haml b/app/views/annotatorplus/index.html.haml index 0fab2ce09..01cbdbbac 100644 --- a/app/views/annotatorplus/index.html.haml +++ b/app/views/annotatorplus/index.html.haml @@ -3,7 +3,7 @@ %head = javascript_include_tag "bp_annotatorplus" -%div.container-fluid +%div.container-fluid.flex-grow-1 %div.row %div.col %h2.mt-3 Annotator + diff --git a/app/views/collections/_collection.html.haml b/app/views/collections/_collection.html.haml index a3310e726..580c0b74e 100644 --- a/app/views/collections/_collection.html.haml +++ b/app/views/collections/_collection.html.haml @@ -4,24 +4,8 @@ top_keys: %w[created modified comment note], bottom_keys: [], exclude_keys: %w[member]) do |c| - = c.header do - %tr - %td.label - ID - %td - %p - = collection["@id"] - %tr - %td{nowrap: ""} Preferred Name - %td - %p= get_collection_label(collection) - %tr - %td{nowrap: ""} Members count - %td - %p= collection["memberCount"] - %tr - %td.label - Type - %td - %p - = collection["@type"] \ No newline at end of file + - c.header(stripped: true) do |t| + - t.add_row({th: 'ID'}, {td: collection["@id"]}) + - t.add_row({th: 'Preferred Name'}, {td: get_collection_label(collection)}) + - t.add_row({th: 'Members count'}, {td: collection["memberCount"]}) + - t.add_row({th: 'Type'}, {td: collection["@type"]}) \ No newline at end of file diff --git a/app/views/concepts/_details.html.haml b/app/views/concepts/_details.html.haml index 2b225d586..68b48e108 100644 --- a/app/views/concepts/_details.html.haml +++ b/app/views/concepts/_details.html.haml @@ -43,6 +43,7 @@ %div.my-1 - @concept.memberOf.each do |v| = raw get_link_for_collection_ajax(v, @ontology.acronym, '_blank') + - unless @concept.inScheme.nil? || @concept.inScheme.empty? %tr %td{nowrap: ""} In Schemes diff --git a/app/views/errors/internal_server_error.html.erb b/app/views/errors/internal_server_error.html.erb deleted file mode 100644 index f44358e78..000000000 --- a/app/views/errors/internal_server_error.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -<%= content_tag :div, id: "bd", style: "clear: both; text-align: center; margin-top: 100px; margin-bottom: 100px;" do -%> -

We're sorry but something has gone wrong. We have been notified of this error.

-<% end -%> \ No newline at end of file diff --git a/app/views/errors/internal_server_error.html.haml b/app/views/errors/internal_server_error.html.haml new file mode 100644 index 000000000..3a9b4c7df --- /dev/null +++ b/app/views/errors/internal_server_error.html.haml @@ -0,0 +1,15 @@ +.d-flex.align-items-center.flex-column.position-relative + = inline_svg("errors/agroportal.svg") + .position-absolute.text-center{style: "top: 425px; font-size: 30px; font-weight: 800; color: #263238;"} + %div + We're sorry but something has gone wrong. + %div + We have been notified of this error. + .buttons.d-flex.justify-content-center.mt-3 + %div{style: "width: 216px;"} + = render Buttons::RegularButtonComponent.new(id:'Home-button', value: "Go home", variant: "secondary", href: "/") + %div{style: "width: 216px; margin-left: 22px"} + = render Buttons::RegularButtonComponent.new(id:"feedback-button" ,value: "Send a feedback", variant: "primary", href: "/feedback") + + + diff --git a/app/views/errors/not_found.html.erb b/app/views/errors/not_found.html.erb deleted file mode 100644 index 2a0701060..000000000 --- a/app/views/errors/not_found.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -<%= content_tag :div, id: "bd", style: "clear: both; text-align: center; margin-top: 100px; margin-bottom: 100px;" do -%> -

- <%= @error_message || "The page you are looking for wasn't found. Please try again." %> -

-<% end -%> \ No newline at end of file diff --git a/app/views/errors/not_found.html.haml b/app/views/errors/not_found.html.haml new file mode 100644 index 000000000..5aaf6ea2c --- /dev/null +++ b/app/views/errors/not_found.html.haml @@ -0,0 +1,12 @@ +.d-flex.align-items-center.flex-column.position-relative + = inline_svg("errors/agroportal.svg") + .position-absolute{style: "top: 442px; font-size: 30px; font-weight: 800; color: #263238;"} + = @error_message || "Page not found" + .buttons.d-flex.justify-content-center.mt-3 + %div{style: "width: 216px;"} + = render Buttons::RegularButtonComponent.new(id:'Home-button', value: "Go home", variant: "secondary", href: "/") + %div{style: "width: 216px; margin-left: 22px"} + = render Buttons::RegularButtonComponent.new(id:"feedback-button" ,value: "Send a feedback", variant: "primary", href: "/feedback") + + + diff --git a/app/views/fair_score/_details.html.haml b/app/views/fair_score/_details.html.haml index 7d3181b59..b75d6fef2 100644 --- a/app/views/fair_score/_details.html.haml +++ b/app/views/fair_score/_details.html.haml @@ -1,4 +1,4 @@ -= turbo_frame_tag 'application_modal_content' do += render_in_modal do :javascript var scrollY = window.getScrollTop() $(document).ready(function(){ diff --git a/app/views/label_xl/show.html.haml b/app/views/label_xl/show.html.haml index 7b94c4971..f038b63cc 100644 --- a/app/views/label_xl/show.html.haml +++ b/app/views/label_xl/show.html.haml @@ -1,22 +1,11 @@ -= turbo_frame_tag 'application_modal_content' do += render_in_modal do - if @label_xl && !@label_xl.empty? = render ConceptDetailsComponent.new(id:'skos-xl-label', acronym: @ontology_acronym, properties: @label_xl.properties, top_keys: %w[description comment], bottom_keys: %w[disjoint subclass is_a has_part], exclude_keys: []) do |c| - - c.header do - %tr - %td.label - ID - %td - %p - = @label_xl["@id"] - %tr - %td{nowrap: ""} Preferred Name - %td - %p= get_label_xl_label(@label_xl) - %tr - %td{nowrap: ""} Type - %td - %p= @label_xl["@type"] + - c.header(stripped: true) do |t| + - t.add_row({th: 'ID'}, {td: @label_xl["@id"]}) + - t.add_row({th: 'Preferred Name'}, {td: get_label_xl_label(@label_xl)}) + - t.add_row({th: 'Type'}, {td: @label_xl["@type"]}) diff --git a/app/views/layouts/_footer.html.haml b/app/views/layouts/_footer.html.haml index a88f4166f..2cdd9b7c0 100644 --- a/app/views/layouts/_footer.html.haml +++ b/app/views/layouts/_footer.html.haml @@ -1,33 +1,32 @@ -%footer.footer.pt-4.mt-5 - %div.container - %div.row - - $FOOTER_LINKS.to_h[:top].to_a.each do |footer_links_block| - %div.col-6.col-md - %h6= footer_links_block[:column_header] - %ul.list-unstyled - - footer_links_block[:links].each do |footer_links_row| - %li - - footer_links_row.each do |footer_link| - = render_footer_link footer_link - %div.row.legal-text - %div.col - = t('.grant_html', site: $SITE) - %div.row.pt-2 - - $FOOTER_LINKS.to_h[:bottom].to_a.each do |footer_links_block| - %div.col-6.col-md - - if footer_links_block[:column_header].present? - %h6= footer_links_block[:column_header] - %ul.list-inline - - footer_links_block[:links].each do |footer_links_row| - - footer_links_row.each_with_index do |footer_link, i| - %li.list-inline-item - = render_footer_link footer_link - - unless i >= footer_links_row.size - 1 - %li.list-inline-item - = raw(footer_links_block[:separator]) +%br +%br/ +.footer-container + %footer + .footer-header + .footer-logo + %img{:src => "#{asset_path("logos/ontoportal.svg")}"} + - logo = $UI_THEME.to_s.capitalize + - logo.sub! 'portal' , 'Portal' + %p + = logo + .footer-social-media-links + - $FOOTER_LINKS[:social].each do |link| + %a{:href => link[:link], :target => "_blank"} + %img{:src => "#{asset_path(link[:logo])}"}/ + .footer-nav-links + - $FOOTER_LINKS[:sections].each do |key, section_links| + %div + %h2 + = t("layout.footer."+key.to_s) + %div + - section_links.each do |section , link| + %a{:href => link, :target => "_blank"} + = t("layout.footer."+section.to_s) + + = javascript_include_tag "application" diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb index 730a85af5..0530d3209 100644 --- a/app/views/layouts/_header.html.erb +++ b/app/views/layouts/_header.html.erb @@ -43,5 +43,5 @@ <%=render partial: 'layouts/topnav'%> -
+
<%=render partial: 'layouts/notices'%> \ No newline at end of file diff --git a/app/views/layouts/_notices.html.haml b/app/views/layouts/_notices.html.haml index 9119dc815..35fe7cf79 100644 --- a/app/views/layouts/_notices.html.haml +++ b/app/views/layouts/_notices.html.haml @@ -2,10 +2,7 @@ = license_notification(current_license()) - flash.each do |key, message| - %div{class: "flash alert #{flash_class(key)} alert-dismissible fade show", role: "alert"} - = message - %button{type: 'button', class: 'close', 'data-dismiss': 'alert', 'aria-label': 'Close'} - %span{'aria-hidden': 'true'} × + = render NotificationComponent.new(title: message , type: notification_type(key)) - do_not_display_subdomain_info_here = Set.new(["homeall_resources"]) - if at_slice? && !do_not_display_subdomain_info_here.include?("#{controller.controller_name}#{controller.action_name}") diff --git a/app/views/layouts/_ontology_viewer.html.haml b/app/views/layouts/_ontology_viewer.html.haml index 709267865..e713da605 100644 --- a/app/views/layouts/_ontology_viewer.html.haml +++ b/app/views/layouts/_ontology_viewer.html.haml @@ -51,7 +51,7 @@ - = render TurboModalComponent.new(id: 'application_modal') + = modal_frame_container -# Modal dialog for getting a permanent link to a class (must reside in a top-level position in the document to display properly). %div#classPermalinkModal{class: "modal fade", tabindex: "-1", role: "dialog", aria: {labelledby: "classPermalinkLabel", hidden: "true"}} diff --git a/app/views/layouts/_topnav.html.haml b/app/views/layouts/_topnav.html.haml index 8c3e73e76..3ab3c4d6b 100644 --- a/app/views/layouts/_topnav.html.haml +++ b/app/views/layouts/_topnav.html.haml @@ -1,56 +1,55 @@ -%nav.navbar.navbar-expand-lg.navbar-dark.navbar-custom - = link_to(image_tag("logos/ontoportal-logo.png") + content_tag(:span, $SITE, class: 'site-name'), root_path(), class: "navbar-brand") - = button_tag(type: "button", class: "navbar-toggler", data: {toggle: "collapse", target: "#topNavigationToggler"}, aria: {controls: "topNavigationToggler", expanded: "false", label: "Toggle navigation"}) do - %span.navbar-toggler-icon - - %div#topNavigationToggler.navbar-collapse.collapse.justify-content-between - %ul.navbar-nav - %li.nav-item - = link_to("Browse", ontologies_path(), class: "nav-link") - %li.nav-item - = link_to("Search", "/search", class: "nav-link") - %li.nav-item - = link_to("Mappings", mappings_path(), class: "nav-link") - %li.nav-item - = link_to("Recommender", recommender_index_path, class: "nav-link") - %li.nav-item - = link_to("Annotator", annotator_index_path(), class: "nav-link") - - if $NCBO_ANNOTATORPLUS_ENABLED == true - %li.nav-item - = link_to("NCBO Annotator+", '/ncbo_annotatorplus', class: "nav-link") - %li.nav-item - = link_to("Projects", projects_path(), class: "nav-link") - %li.nav-item - = link_to("Landscape", '/landscape', class: "nav-link") - -if (!session[:user].nil? && session[:user].admin?) - %li.nav-item - = link_to("Admin", admin_index_path, class: "nav-link") - %ul.navbar-nav - - if session[:user].nil? - %li.nav-item - = link_to("Login", login_index_path(redirect: request.original_url), class: "btn btn-bp-login mr-md-2") +.nav-container{data: {controller:"topnav-responsiveness"}} + %nav.top-nav + .nav-responsiveness-container + %a.nav-logo{href: "/"} + %img{:src => asset_path("logo-white.svg")}/ + %p + = portal_name + %input#nav-menu{:type => "checkbox", 'data-topnav-responsiveness-target': 'navMenu'} + %label.menu-btn{:for => "nav-menu"} + %i.fas.fa-bars + .nav-items + %ul.top-nav-ul + - navitems.each do |navItem| + %li.nav-ul-li + %a{href: navItem[0], class: ("active" if current_page?(navItem[0]))} #{navItem[1]} + - if current_page?('/') + .nav-search-container{style:'visibility: hidden'} + %input - else - -# Account menu - %li.nav-item.dropdown - = link_to("#", id: "accountMenuDropdownLink", class: "nav-link dropdown-toggle", role: "button", data: {toggle: "dropdown"}, aria: {haspopup: "true", expanded: "false"}) do - = session[:user].username - %div.dropdown-menu.dropdown-menu-right{aria: {labelledby: "accountMenuDropdownLink"}} - = link_to("Account Settings", "/account", class: "dropdown-item") - - unless session[:ontologies].nil? - %div.dropdown-divider - %h6.dropdown-header Recently Viewed - - for ont in session[:ontologies] - = link_to(ont.ontology_name, "/ontologies/#{ont.ontology_acronym}/?p=classes&conceptid=#{CGI.escape(ont.concept)}", class: "dropdown-item") - %div.dropdown-divider - = link_to("Logout", logout_path, class: "dropdown-item") - -# Support menu - %li.nav-item.dropdown - = link_to("#", id: "supportMenuDropdownLink", class: "nav-link dropdown-toggle", role: "button", data: {toggle: "dropdown"}, aria: {haspopup: "true", expanded: "false"}) do - Support - %div.dropdown-menu.dropdown-menu-right{aria: {labelledby: "supportMenuDropdownLink"}} - = link_to("Submit Feedback", feedback_path(location: encode_param(request.url)), id: "submitFeedbackMenuItem", class: "dropdown-item pop_window") - %div.dropdown-divider - %h6.dropdown-header Documentation - = link_to("Help", "#{$WIKI_HELP_PAGE}", target: "_blank", class: "dropdown-item") - = link_to("Release Notes", "#{$RELEASE_NOTES}", target: "_blank", class: "dropdown-item") - = link_to("Publications", $PUBLICATIONS_URL, target: "_blank", class: "dropdown-item") + .nav-search-container{'data-controller': "home-search"} + %input.nav-input{:placeholder => "Search in "+portal_name+" ...", :type => "text", :name => "search", 'data-home-search-target': 'input', 'data-action': 'input->home-search#search blur->home-search#blur'} + #home-search-drop-down.nav-search-drop-down{'data-home-search-target': 'dropDown', 'data-action': 'mousedown->home-search#prevent'} + %a.home-search-ontology-content#home-search-ontology-content{href: "#", 'data-home-search-target': 'searchOntologyContent'} + %p#seached-ontology{'data-home-search-target': 'ontology'} + %div + %img{src: asset_path("loop.svg")}/ + %p Search ontology content + %a.home-search-ontology-content#home-search-ontologies{href: "#", 'data-home-search-target': 'homeSearchOntologies'} + %p#seached-ontologies{'data-home-search-target': 'searchedOntologies'} + %div + %img{src: asset_path("loop.svg")}/ + %p See all ontologies + %a.nav-a{:href => "/login"} Login + + = select_tag('language', options_for_select([['EN','en'],['FR','fr']]), id: 'language-select', class: 'nav-language', + data: { controller: "platform-language", action: "change->platform-language#handleLangChanged" }) + + = render DropdownButtonComponent.new(css_class:'text-white') do |d| + - d.header do + = link_to("#", id: "supportMenuDropdownLink", class: "nav-link supportMenuDropdownLink", role: "button") do + Support + - d.with_section(divide: false) do |s| + - s.item do + = link_to(t(:submit_feedback), feedback_path(location: encode_param(request.url)), id: "submitFeedbackMenuItem", class: "pop_window") + - d.with_section do |s| + - s.header do + Documentation + - s.item do + = link_to(t(:_help), "#{$WIKI_HELP_PAGE}", target: "_blank") + - s.item do + = link_to(t(:_release_notes), "#{$RELEASE_NOTES}", target: "_blank") + - s.item do + = link_to(t(:_publications), $PUBLICATIONS_URL, target: "_blank") + + diff --git a/app/views/layouts/appliance.html.haml b/app/views/layouts/appliance.html.haml index aae2cc1d6..5794e4865 100644 --- a/app/views/layouts/appliance.html.haml +++ b/app/views/layouts/appliance.html.haml @@ -28,9 +28,10 @@ %body{:class => "#{controller_name} #{action_name}"} = render partial: "layouts/topnav" - %div.container-fluid + %div.container-fluid.flex-grow-1 = render partial: "layouts/notices" - = render TurboModalComponent.new(id: 'application_modal') + = modal_frame_container + = yield = render partial: "layouts/footer" diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 5ff643c32..8b025f31a 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -8,7 +8,7 @@ <%= javascript_include_tag "application"%> -<%= render TurboModalComponent.new(id: 'application_modal') %> +<%= modal_frame_container %> <%= yield %> diff --git a/app/views/layouts/component_preview.html.erb b/app/views/layouts/component_preview.html.erb new file mode 100644 index 000000000..5369cd053 --- /dev/null +++ b/app/views/layouts/component_preview.html.erb @@ -0,0 +1,59 @@ + + + Component Preview + + <%= stylesheet_link_tag "application" %> + <%= javascript_include_tag "vendor" %> + + + + <%= modal_frame_container %> +
+ <%= yield %> + <%= javascript_include_tag "application" %> +
+ + + \ No newline at end of file diff --git a/app/views/layouts/component_preview_not_centred.html.erb b/app/views/layouts/component_preview_not_centred.html.erb new file mode 100644 index 000000000..81b1c2964 --- /dev/null +++ b/app/views/layouts/component_preview_not_centred.html.erb @@ -0,0 +1,56 @@ + + + Component Preview + + <%= stylesheet_link_tag "application" %> + <%= javascript_include_tag "vendor" %> + + + + <%= modal_frame_container %> + <%= yield %> + <%= javascript_include_tag "application" %> + + \ No newline at end of file diff --git a/app/views/layouts/ontology.html.erb b/app/views/layouts/ontology.html.erb index 78c31664c..b3d793d23 100644 --- a/app/views/layouts/ontology.html.erb +++ b/app/views/layouts/ontology.html.erb @@ -1,6 +1,6 @@ <%=render partial: 'layouts/header'%>
- <%= render TurboModalComponent.new(id: 'application_modal')%> + <%= modal_frame_container%> <%=yield%>
<%=render partial: 'layouts/footer'%> diff --git a/app/views/layouts/ontology_viewer/_header.html.haml b/app/views/layouts/ontology_viewer/_header.html.haml new file mode 100644 index 000000000..a77aa452b --- /dev/null +++ b/app/views/layouts/ontology_viewer/_header.html.haml @@ -0,0 +1,34 @@ +- sub = @submission_latest +- details_available = true +- if sub.nil? || (sub.respond_to?(:status) && sub.status == 404) + - details_available = false +-# A header of sorts to display ontology name and subset of details. +%div.ont-info-bar.rounded + %div + %h4 + = link_to(@ontology.name, ontology_path(@ontology.acronym)) + %div + - if (details_available && !sub.released.nil?) + %span.text-muted + = t('ontology_details.header.last_uploaded') + = l(Date.parse(sub.creationDate), format: :monthfull_day_year) + %div.ont-info-links + - unless (@ontology.summaryOnly || @ont_restricted || @submission_latest.nil?) + = link_to(@submission_latest.id + "/download?apikey=#{get_apikey}", "aria-label": "Download latest version", title: "Download latest version") do + %i.fas.fa-lg.fa-download{"aria-hidden": true} + - if details_available + - if $PURL_ENABLED + = link_to(@ontology.purl, "aria-label": "BioPortal PURL", title: "BioPortal PURL", target: "_blank") do + %i.fas.fa-lg.fa-link{"aria-hidden": true} + = link_to(sub.homepage, "aria-label": "Ontology home page", title: "Ontology home page", target: "_blank") do + %i.fas.fa-lg.fa-home{"aria-hidden": true} + - unless sub.documentation.nil? + = link_to(sub.documentation, "aria-label": "Ontology documentation", title: "Ontology documentation", target: "_blank") do + %i.fas.fa-lg.fa-book-reader{"aria-hidden": true} + - unless sub.publication.nil? + - Array(sub.publication).each do |pub| + = link_to(pub, "aria-label": "Ontology publications", title: "Ontology publications", target: "_blank") do + %i.fas.fa-lg.fa-book{"aria-hidden": true} + - if @ontology.admin?(session[:user]) + = link_to(edit_ontology_path(@ontology.acronym), "aria-label": "Edit ontology details", title: "Edit ontology details") do + %i.fas.fa-lg.fa-user-edit \ No newline at end of file diff --git a/app/views/login/index.html.haml b/app/views/login/index.html.haml index 16d6b495a..ae71c1c1f 100644 --- a/app/views/login/index.html.haml +++ b/app/views/login/index.html.haml @@ -14,7 +14,8 @@ = password_field 'user','password', :autocomplete => "off", class: "login-input password-input", placeholder: "Enter your password" %a.login-forgot-password{:href => "/lost_pass"} %p Forgot password? - %input.login-button{"data-disable-with" => "Login", :name => "commit", :type => "submit", :value => "Login"}/ + .login-button-container + = render Buttons::RegularButtonComponent.new(value: "Login", name: "commit", type: "submit") %p.dont-have-account Don't have an account? %a.text-decoration-none{:href => new_user_path} Register diff --git a/app/views/mappings/_count.html.haml b/app/views/mappings/_count.html.haml index 149d59d7a..a0a244cec 100644 --- a/app/views/mappings/_count.html.haml +++ b/app/views/mappings/_count.html.haml @@ -1,19 +1,19 @@ -%table#mapping_count_table.zebra{cellpadding: "0", cellspacing: "0"} - %thead - %tr - %th Ontology - %th Mappings - %tbody - - if @mapping_counts.blank? - %tr - %td There are no mappings to or from this ontology - %td   - - else - - for mapping_count in @mapping_counts - %tr - %td - %a.facebox{href: "/mappings/show_mappings?id=#{@ontology_acronym}&target=#{mapping_count[:target_ontology].id}&height=600&width=800"}= mapping_count[:target_ontology].name - %td= number_with_delimiter(mapping_count[:count], delimiter: ',') += render TableComponent.new(id: 'mapping_count_table') do |t| + - t.header do |h| + - h.th {'Ontology'} + - h.th {'Mappings'} + + - if @mapping_counts.blank? + - t.row do |r| + - r.td {'There are no mappings to or from this ontology'} + - r.td {' '} + - else + - @mapping_counts.each do |mapping_count| + - t.row do |r| + - r.td do + %a.facebox{href: "/mappings/show_mappings?id=#{@ontology_acronym}&target=#{mapping_count[:target_ontology].id}&height=600&width=800"}= mapping_count[:target_ontology].name + - r.td do + = number_with_delimiter(mapping_count[:count], delimiter: ',') :javascript $(document).ready(() => { diff --git a/app/views/mappings/bulk_loader/_loader.html.haml b/app/views/mappings/bulk_loader/_loader.html.haml index 14a556b23..242a50b71 100644 --- a/app/views/mappings/bulk_loader/_loader.html.haml +++ b/app/views/mappings/bulk_loader/_loader.html.haml @@ -1,4 +1,4 @@ -= turbo_frame_tag 'application_modal_content' do += render_in_modal do %div.d-flex.flex-column{:style => "overflow: auto; max-height: 600px;"} = render TurboFrameComponent.new(id: 'file_loader_result') do %div.my-2 @@ -14,6 +14,6 @@ = JSON.pretty_generate @example_code = form_with url: '/mappings/loader', method: :post, multipart: true, data: { turbo: true} do %div - = render FileInputLoaderComponent.new(name: :file) + = render Input::FileInputComponent.new(name: :file) %button.btn.btn-secondary.btn-block.mt-2{type:'submit'} Save diff --git a/app/views/mappings/edit.html.haml b/app/views/mappings/edit.html.haml index 21bdd3f7c..4e37b31fc 100644 --- a/app/views/mappings/edit.html.haml +++ b/app/views/mappings/edit.html.haml @@ -1,2 +1,2 @@ -= turbo_frame_tag 'application_modal_content' do += render_in_modal do = render partial: 'form', locals: {form_url: mapping_path} diff --git a/app/views/mappings/index.html.haml b/app/views/mappings/index.html.haml index 438f3658f..94807c194 100644 --- a/app/views/mappings/index.html.haml +++ b/app/views/mappings/index.html.haml @@ -1,5 +1,5 @@ - @title = "Mappings" -%div#mappings_container.container-fluid.py-4 +%div#mappings_container.container-fluid.py-4.flex-grow-1 %h1.my-1 Mappings %div#mappings_uploader.my-2 diff --git a/app/views/mappings/new.html.haml b/app/views/mappings/new.html.haml index 05cf6fb89..48e195b10 100644 --- a/app/views/mappings/new.html.haml +++ b/app/views/mappings/new.html.haml @@ -1,2 +1,2 @@ -= turbo_frame_tag 'application_modal_content' do += render_in_modal do = render partial: 'form', locals: {form_url: mappings_path} diff --git a/app/views/ncbo_annotatorplus/index.html.haml b/app/views/ncbo_annotatorplus/index.html.haml index ba1315f02..9d9cffc47 100644 --- a/app/views/ncbo_annotatorplus/index.html.haml +++ b/app/views/ncbo_annotatorplus/index.html.haml @@ -3,7 +3,7 @@ %head = javascript_include_tag "bp_annotator" -%div.container-fluid.annotator +%div.container-fluid.annotator.flex-grow-1 %div.row %div.col %h2.mt-3 NCBO Annotator + diff --git a/app/views/notes/_new_comment.html.haml b/app/views/notes/_new_comment.html.haml index 885115ebe..95b8b0804 100644 --- a/app/views/notes/_new_comment.html.haml +++ b/app/views/notes/_new_comment.html.haml @@ -1,4 +1,4 @@ -= turbo_frame_tag "application_modal_content" do += render_in_modal do = render_alerts_container = form_with url: notes_path, method: 'post', data:{turbo: true, 'turbo-frame': '_top'} do = hidden_field_tag 'parent', parent_id diff --git a/app/views/notes/_new_proposal.html.haml b/app/views/notes/_new_proposal.html.haml index 9a3abbd8c..64e0976a0 100644 --- a/app/views/notes/_new_proposal.html.haml +++ b/app/views/notes/_new_proposal.html.haml @@ -1,4 +1,4 @@ -= render TurboFrameComponent.new(id: 'application_modal_content') do += render_in_modal do :javascript function updateProposalForm(event){ let frame = document.getElementById('application_modal_content') diff --git a/app/views/notes/_note_line.html.haml b/app/views/notes/_note_line.html.haml index 77823dd57..ce50b99ba 100644 --- a/app/views/notes/_note_line.html.haml +++ b/app/views/notes/_note_line.html.haml @@ -1,29 +1,26 @@ -%tr{id: "#{note.id}_tr_#{parent_type}"} - %td += render TableRowComponent.new(id: "#{note.id}_tr_#{parent_type}") do |row| + - row.td do - if current_user_admin? - alert_text = "Are you sure you want to delete the note ''" + (note.subject || '') + "'' created by " + note.creator.split('/')[-1] + "?
This action CAN NOT be undone!!!" = button_to "Delete", notes_path(noteid: note.id, parent_type: parent_type), method: :delete, class:'btn btn-sm btn-link', form: {data: { turbo: true, turbo_confirm: alert_text, turbo_frame: '_top'}} - %td + - row.td do - note_link = "/ontologies/#{ontology_acronym}/notes/" - note_link = "#{note_link}?noteid=#{CGI.escape(note.id)}" = link_to_modal note.subject || note_link , note_link, id:"row_#{note.id}", - class: "ont_notes_list_link notes_list_link", - data: { show_modal_title_value: ""} + class: "ont_notes_list_link notes_list_link", + data: { show_modal_title_value: ""}     %span{:id => "#{note.id}_row_archived", :style => "font-size: x-small; color: grey;"} - if note.archived archived - %td.d-none - = note.subject - %td.d-none - = note.archived || "false" - %td + - row.td do = note.creator.split('/')[-1] - %td + + - row.td do = note.proposal ? get_note_type_text(note.proposal.type) : "Comment" - if parent_type.eql?('ontology') - %td + - row.td do - if note.relatedClass && note.relatedClass.length > 0 - %a{href: "/ontologies/#{ontology_acronym}?p=classes&conceptid=#{CGI.escape(note.relatedClass.first)}"}= note.relatedClass.first - %td + %a{href: "/ontologies/#{ontology_acronym}?p=classes&conceptid=#{CGI.escape(note.relatedClass.first)}", 'data-turbo': 'false'}= note.relatedClass.first + - row.td do = DateTime.parse(note.created).strftime("%Y-%m-%d") \ No newline at end of file diff --git a/app/views/notes/_notes.html.haml b/app/views/notes/_notes.html.haml index d7a13e4a6..57b77791a 100644 --- a/app/views/notes/_notes.html.haml +++ b/app/views/notes/_notes.html.haml @@ -17,35 +17,21 @@ = render_alerts_container("notes_#{parent_type}_list_table_alerts") .ont_notes_table_container - %table.zebra.notes_ont_list_table{:id => "#{notes_table_id}", :style => "width: 100%;", :width => "100%"} - %thead - %tr - %th - Delete - %th - Subject - %th.d-none - Subject Sort - %th.d-none - Archive Sort - %th - Author - %th - Type - - if parent_type.eql?('ontology') - %th - Class - %th - Created - %tbody{id: "#{parent_type}_notes_table_content"} - - if @notes.nil? || @notes.empty? - %tr#ont_no_notes - %td{colspan: colspan} No notes to display - - (colspan-1).times.each do - %td - - else - - @notes.each do |note| - = render partial: 'notes/note_line', locals: {note: note, ontology_acronym: @ontology.acronym, parent_type: parent_type} + - cols = ['Action', 'Subject', 'Author', 'Type', (parent_type.eql?('ontology') ? 'Class' : nil),'Created'].compact + = render TableComponent.new(id:"#{parent_type}_notes") do |t| + - t.header do |row| + - row.create(*cols.map{|col| {th: col}}) + + - if @notes.nil? || @notes.empty? + - t.row do |row| + - row.td(colspan: colspan) do + %div.text-center + No notes to display + + - else + - @notes.each do |note| + = render partial: 'notes/note_line', locals: {note: note, ontology_acronym: @ontology.acronym, parent_type: parent_type} + :javascript jQuery(".ontologies.show").ready(function(){ jQuery("#hide_archived_ont").click(function(){ diff --git a/app/views/notes/show.html.haml b/app/views/notes/show.html.haml index 30214eaac..2bec34432 100644 --- a/app/views/notes/show.html.haml +++ b/app/views/notes/show.html.haml @@ -1,4 +1,4 @@ -= turbo_frame_tag 'application_modal_content' do += render_in_modal do - ontology_name = @ontology ? " on #{@ontology.name}" : "" - @title = "Note#{ontology_name} | #{@note.subject}" #note_container{:style => "padding: 1em;"} diff --git a/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml b/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml index 1c4c5128c..6531ba17c 100644 --- a/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml +++ b/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml @@ -1,5 +1,8 @@ -%nav - .nav.nav-tabs.text-center{:role => "tablist", style:"background-color: rgba(0, 0, 0, 0.03);"} +%div#concept_browser + = render TabsContainerComponent.new(type:'outline') do |c| + - c.item(id: 'tree-tab', selected: default_sub_menu?) do + %span{title: 'Hierarchy view', 'data-controller': "tooltip"} + = inline_svg('icons/list-tree.svg', style:'width: 18px; height: 18px') %a#concepts-tree-tab.nav-item.nav-link.flex-grow-1.border-radius-0{"data-toggle" => "tab", :href => "#concepts-tree-container", title: 'Hierarchy view', 'data-controller': "tooltip", class: default_sub_menu_class} %img{src: asset_path('list-tree.svg') , style:'width: 25px; height: 25px'} diff --git a/app/views/ontologies/sections/visualize.html.haml b/app/views/ontologies/sections/visualize.html.haml index 14dee3422..83b470c2e 100644 --- a/app/views/ontologies/sections/visualize.html.haml +++ b/app/views/ontologies/sections/visualize.html.haml @@ -5,7 +5,7 @@ - @enable_ontolobridge = !$NEW_TERM_REQUEST_ONTOLOGIES.nil? && $NEW_TERM_REQUEST_ONTOLOGIES.include?(@ontology.acronym) %div.tooltip %div#bd_content.bd_content.explore{data:{controller: 'container-splitter'}} - %div.sidebar.d-flex.flex-column.mr-2.card{data:{'container-splitter-target': 'container'}} + %div.sidebar.d-flex.flex-column.p-1.mr-1{data:{'container-splitter-target': 'container'}} = render partial: 'ontologies/concepts_browsers/concepts_browser' %div#concept_content.d-flex.flex-column.card.p-1.ml-2{data:{'container-splitter-target': 'container'}} = render partial: 'concepts/show' diff --git a/app/views/ontologies_metadata_curator/_form_edit.html.haml b/app/views/ontologies_metadata_curator/_form_edit.html.haml index 24ed94da2..533cbde3b 100644 --- a/app/views/ontologies_metadata_curator/_form_edit.html.haml +++ b/app/views/ontologies_metadata_curator/_form_edit.html.haml @@ -1,4 +1,4 @@ -= turbo_frame_tag 'application_modal_content' do += render_in_modal do :javascript function saveSelectedTab(value){ const input = document.getElementById("active_ontology") diff --git a/app/views/schemes/_scheme.html.haml b/app/views/schemes/_scheme.html.haml index 91607bf91..2fcf310c9 100644 --- a/app/views/schemes/_scheme.html.haml +++ b/app/views/schemes/_scheme.html.haml @@ -5,19 +5,8 @@ top_keys: %w[description comment], bottom_keys: %w[disjoint subclass is_a has_part], exclude_keys: []) do |c| - = c.header do - %tr - %td.label - ID - %td - %p= scheme["@id"] - %tr - %td{nowrap: ""} Preferred Name - %td - %p= get_scheme_label(scheme) - %tr - %td.label - Type - %td - %p= scheme["@type"] + - c.header(stripped: true) do |t| + - t.add_row({th: 'ID'} , {td: scheme["@id"]}) + - t.add_row({th: 'Preferred Name'} , {td: get_scheme_label(scheme)}) + - t.add_row({th: 'Type'} , {td: scheme["@type"]}) diff --git a/app/views/submissions/_form_content.html.haml b/app/views/submissions/_form_content.html.haml index 5b55e4ec9..85896b8dc 100644 --- a/app/views/submissions/_form_content.html.haml +++ b/app/views/submissions/_form_content.html.haml @@ -46,19 +46,16 @@ = text_area c.name, c.method_name, rows: 5, value: @submission.description, required: true, class: "form-control" -# Home page - = attribute_text_field_container('homepage') do |c| - - c.help do - Enter a URL for the main page of your ontology. + = form_group_attribute('homepage') do + Enter a URL for the main page of your ontology. -# Documentation page - = attribute_text_field_container('documentation') do |c| - - c.help do - Enter a URL for a page that provides ontology documentation. + = form_group_attribute('documentation') do + Enter a URL for a page that provides ontology documentation. -# Publications page - = attribute_text_field_container('publication') do |c| - - c.help do - Enter a URL for a page that lists publications about your ontology. + = form_group_attribute('publication') do + Enter a URL for a page that lists publications about your ontology. -# Used ontology engineering tool = form_group_attribute("usedOntologyEngineeringTool") @@ -105,6 +102,9 @@ = render NestedFormInputsComponent.new do |c| - c.template do = render partial: "submissions/submission_contact_form", locals: {contact: nil, index: 'NEW_RECORD'} + - c.empty_state do + = hidden_field_tag object_name+"[contact][#{@submission.contact.size}][email]" + = hidden_field_tag object_name+"[contact][#{@submission.contact.size}][name]" - @submission.contact.each_with_index do |contact, i| - c.row do = render partial: "submissions/submission_contact_form", locals: {contact: contact, index: i} diff --git a/app/views/users/_form.html.haml b/app/views/users/_form.html.haml index 4697bc2d8..e70512e62 100644 --- a/app/views/users/_form.html.haml +++ b/app/views/users/_form.html.haml @@ -50,4 +50,5 @@ .d-flex %input#user_register_mail_list{:checked => "checked", :name => "user[register_mail_list]", :type => "checkbox", :value => "1"}/ %p#register-check-text Register for the AgroPortal's mailing list - %input.register-button{:type => "submit", :value => "Register"}/ + .register-button-container + = render Buttons::PrimaryButtonComponent.new(type: "submit", value: "Register") diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index ecd788660..bf3657498 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -111,8 +111,8 @@ %h4.account-page-card-title Submitted ontologies .account-page-small-cards-container - @admin_ontologies.each do |ont| - .account-page-submitted-ontology - %a{href: "/ontologies/#{ont.acronym}"}= ont.name + .account-page-submitted-ontology{data: {controller: 'tooltip'}, title: ont.name} + %a{href: "/ontologies/#{ont.acronym}"}= ont.acronym - unless @user_projects.nil? || @user_projects.empty? - no_ontologies = false .account-page-card diff --git a/config/application.rb b/config/application.rb index f13cb361a..ea51961b9 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,5 +27,8 @@ class Application < Rails::Application config.change_request = config_for :change_request config.generators.template_engine = :haml + + # Set the default layout to app/views/layouts/component_preview.html.erb + config.view_component.default_preview_layout = "component_preview" end end diff --git a/config/environments/appliance.rb b/config/environments/appliance.rb index db8739398..ec5f5e79f 100644 --- a/config/environments/appliance.rb +++ b/config/environments/appliance.rb @@ -87,7 +87,7 @@ # Add custom data attributes to sanitize allowed list config.action_view.sanitized_allowed_attributes = ['id', 'class', 'style', 'data-cls', 'data-ont'] - + config.view_component.show_previews = true # TODO: Fix this? # enable json logging format. Useful for logstash # require 'rackstash' diff --git a/config/locales/en.yml b/config/locales/en.yml index b37ebbb55..29050980a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,66 +1,9 @@ en: - - about: > -
-

Abstract

-

- Many vocabularies and ontologies are produced to represent and annotate agronomic data. Therefore, there is a need of - a common platform to identify, host and use them in agro-informatics application. The AgroPortal project aims to offer - a reference ontology repository for agronomy, reusing the NCBO BioPortal technology. The scientific outcomes and the - experience of the biomedical domain are thus exploited and transposed in the agronomy domain, including plants, food, - environment and possibly animal sciences. We offer an ontology portal which features ontology hosting, search, versioning, - visualization, comment, recommendation, enables semantic annotation, as well as storing and exploiting ontology alignments. - All of these within a fully semantic web compliant infrastructure. The AgroPortal specifically pays attention to respect the - requirements of the agronomic community in terms of ontology formats (e.g., SKOS, trait dictionaries) or supported features. - AgroPortal project is based on five driving agronomic use cases which participate in the design and orientation of the platform. - AgroPortal already offers a robust and stable reference repository highly valuable for the agronomic domain. -

-

Use cases

- -
-

New features

-

- See the release notes -

-
-

Partners

-

The National Center For Biomedical Ontology (NCBO), Institut de Recherche pour le Développement (IRD), Research Data Alliance (RDA), - Bioversity International, Food & Agriculture Organization (FAO), Global Open Data for Agriculture & Nutrition (Godan Action), Institut National de la Recherche Agronomique (INRA)

-

Acknowledgments

-

The AgroPortal is partly achieved within the Semantic Indexing of French biomedical Resources (SIFR) project - that received funding from the EU H2020 research and innovation programme under the Marie Sklodowska-Curie (grant 701771) - and the French National Research Agency (grant ANR-12-JS02-01001), the NUMEV Labex (grant ANR-10-LABX-20), - the Computational Biology Institute of Montpellier (grant ANR-11-BINF-0002) as well as by University of Montpellier and the CNRS. - We also thank the National Center for Biomedical Ontologies for help and time spent with us in deploying the AgroPortal.

-

Team

- To contact us: firstname.lastname@lirmm.fr -
    -
  • Clément Jonquet, researcher at LIRMM (Univ. of Montpellier, France), main investigator of the AgroPortal project
  • -
  • Anne Toulet, researcher at LIRMM (Univ. of Montpellier, France)
  • -
  • Vincent Emonet, engineer at LIRMM (Univ. of Montpellier, France)
  • -
-
- - activerecord: - errors: - models: - license: - attributes: - encrypted_key: - invalid_license_key: is an invalid license key - no_appliance_id_for_comparison: couldn't be validated. Unable to retrieve virtual appliance ID. - appliance_id_mismatch: is an appliance ID mismatch - - admin: - licenses: - create: - success: License successfully renewed! + nbco_annotatosplus: + score_help: "Score annotations following previous NCBO 2009 measure (old) or Score annotations following C-Value measure (cvalue) or Score annotations following C-Value measure with hierarchy expansion (cvalueh)" + start_typing_to_select: "Start typing to select %{type} or leave blank to use all" + include_ancestors_up_to_level: "Include ancestors up to level" + include_score: "Include score" date: formats: @@ -116,7 +59,48 @@ en: tooltip: "Enable FastContext to detect : if a concept has been negated (affirmed, negated), who experienced the found concept (patient, other), when the annotated concept occurred (recent, historical, hypothetical), and/or if the annotated concept is uncertain (certain, uncertain)." sample_text: Melanoma is a malignant tumor of melanocytes which are found predominantly in skin but also in the bowel and the eye. - nbco_annotatosplus: + select: "Select %{name}" + + fast_context: + title: "FastContext" + help: "Activate FastContext to detect: if a concept has been negated (affirmed, negated), who experienced the concept found (patient, other), when the annotated concept occurred (recent, historical, hypothetical), and/or if the annotated concept is uncertain (certain, uncertain)." + + annotations: "Annotations" + + filters: + by: + filter: "Filter" + title: "Results are filtered by" + class: "Class" + ontology: "Ontology" + match_type: "Type" + match_context: "Context" + matched_class: "Associated Class" + matched_ontology: "Associated Ontology" + umls_sem_type: "UMLS Semantic Type" + score: "Score" + negation: "Negation" + experiencer: "Experiencer" + temporality: "Temporality" + certainty: "Certainty" + + additional_parameters_explained_at: "Additional parameters are explained on the page:" + format_results_as: "Format results as:" + reproduce_results_using: "Reproduce these results using the" + match_longest_only: "Match longest only" + match_partial_words: "Recognize partial words" + include_mappings: "Include mappings" + exclude_numbers: "Exclude numbers" + exclude_synonyms: "Exclude synonyms" + max_hierarchy_level: "Include ancestors up to level" + score: "Include score" + score_help: "Score annotations according to the previous NCBO 2009 measure (old) or score annotations using the C-Value measure (cvalue) or score annotations using the C-Value measure with hierarchy expansion (cvalueh)" + score_threshold: "Filter by score threshold" + score_threshold_help: "Specify the minimum score value for annotations" + confidence_threshold: "Filter confidence threshold" + confidence_threshold_help: "Specify the minimum position in the scores distribution (between 1 and 100)" + entity_recognizer: "entity recognition tool" + index: intro: > The NCBO Annotator+ is a proxy calling the NCBO Annotator Web service on the NCBO BioPortal. @@ -144,28 +128,425 @@ en: index: intro: Browse a selection of projects that use %{site} resources + landscape: + title: "%{site} Landscape" + intro: Visualize data retrieved from ontologies stored in the portal + groups_and_categories: Groups and Categories + ontologies_by: "Ontologies by %{type}" + ontologies_count_by_catalog: Number of ontologies in each data catalog + properties_use: Property Usage + properties_usage_proportion: The proportion of properties usage among stored ontologies + ontologies_languages: Natural languages of ontologies + ontologies_licenses: Licenses used by ontologies + ontology_tools: Most used tools to build ontologies + more_properties_charts: More properties charts + ontology_properties_pie_charts: Pie charts for the properties used in ontologies + owl_ontology_preflabel_uris: URIs for prefLabel properties used for OWL ontologies + owl_ontology_synonym_uris: URIs for synonym properties used for OWL ontologies + owl_ontology_definition_uris: URIs for definition properties used for OWL ontologies + owl_ontology_author_uris: URIs for author properties used for OWL ontologies + ontology_types: Ontology types + ontology_formality_levels: Formality levels of ontologies + ontologies_formats: Format used + ontologies_contributors: Contributors to ontology development + most_active_people: Most active people + most_mentioned_people: Most mentioned people as contact, creator, contributor or curator + most_active_organizations: Most active organizations + funding_endorsing_organizations: Organizations funding and endorsing the most ontologies + ontologies_activity_on: "Ontology Activity on %{site}" + most_active_people_as_reviewer: "Most active people as reviewers" + most_mentioned_people_as_reviewer: People who published notes, reviews, and projects + most_active_ontologies: "Most active ontologies" + ontologies_with_notes_reviews_projects: "Ontologies with notes, reviews, and projects" + ontology_relations_network: "Ontology Relations Network" + relations_between_stored_ontologies: "Relations between stored ontologies in the portal" + filter_network: "Filter network" + ontology_fairness_evaluator: "Ontology FAIRness Evaluator (O’FAIRe)" + average_metrics: "Average metrics" + group: Group + category: Category + size: Size + + home: + find_ontology: "Find an ontology" + search_class: "Search Class" + browse_by_group: "Browse by Group" + browse_ontologies: "Browse ontologies" + comprehensive_repository: "the most comprehensive repository of biomedical ontologies in the world" + advanced_search: "Advanced Search" + ontology_visits: "Ontology visits" + fair_scores: "FAIR Scores" + clear_selection: "Clear Selection" + latest_notes: "Latest Notes" + ontologies: "Ontologies" + classes: "Classes" + individuals: "People" + projects: "Projects" + users: "Users" + no_recent_notes: "No recent notes were submitted" + index: + find_ontology_placeholder: Start typing the ontology name, then choose from + query_placeholder: Enter a class, eg Melanoma + tagline: The home of vocabularies and ontologies in agronomy and related fields. + title: Welcome to the %{organization} + welcome: Welcome to %{site}, + help: + welcome: Welcome to the %{site} of the National Center for Biomedical Ontology. %{site} is a web application for accessing and sharing biomedical ontologies. + getting_started: > + %{site} allows users to browse, upload, download, search, comment, and create mappings for ontologies. + browse: > + Users can browse and explore individual ontologies by navigating either in a tree structure or in an animated graphical view. Users can also view mappings and + ontology metadata and ontology download. Additionally, logged in users can submit a new ontology to the library. + rest_examples_html: View documentation and examples for the %{site} REST API. + announce_list_html: > + To receive notices of new releases or site outages, please subscribe to + bioontology support list. + + recommend: + intro: Get recommendations for the most relevant ontologies from an excerpt of a biomedical text or a list of keywords + title: "recommender" + ontology_recommender: "Ontology Recommender" + ontology_recommendation_input: "Please paste a paragraph of text or some keywords to compute ontology recommendations." + weight_sum_greater_than_zero: "The sum of weights must be greater than zero" + weights_greater_than_zero: "All weights must be greater than or equal to zero" + valid_numeric_weights: "All weights must be valid numeric values" + valid_integer_max_ontologies_per_set: "Max ontologies per set must be a valid integer value" + valid_max_ontologies_per_set_range: "Max ontologies per set must be a number between 2 and 4" + recommendation_error: "Problem retrieving recommendations, please try again" + no_recommendations: "No recommendations found" + no_sets_recommended: "There are no recommended ontology sets for the provided input. Please try the 'Ontologies' output." + text_length_limit: "Please use less than 500 words. If you need to annotate longer pieces of text, you can use the recommendation web service." + + mappings: + title: "Correspondences" + upload_mappings: "Upload mappings" + mappings_bulk_load: "Mapping Bulk Load" + intro: "Browse mappings between classes of different ontologies" + no_mappings_available: "No mappings available" + loading_mappings: "Loading mappings..." + find_mappings: "Find mappings of a class/concept" + view_mappings_help: "View mappings help" + select_class: "Start typing to select a class" + select_ontologies: "Start typing to select ontologies or leave blank to use all ontologies" + select_semantic_types: "Select UMLS semantic types" + select_semantic_types_help: "Start typing to select UMLS semantic types or leave blank to use all types" + select_semantic_groups: "Select UMLS semantic groups" + select_semantic_groups_help: "Start typing to select UMLS semantic groups or leave blank to use all groups" + include_ancestors_up_to_level: "Include ancestors up to level" + include_score: "Include score" + + annotator: + title: "Annotator" + get_annotator: "Get annotations" + filters: + match_longest_only: "Match longest only" + match_partial_words: "Recognize partial words" + include_mappings: "Include Mappings" + exclude_numbers: "Exclude Numbers" + exclude_synonyms: "Exclude synonyms" + max_hierarchy_level: "Include ancestors up to level" + score: "Include score" + score_help: "Score annotations following previous NCBO 2009 measure (old) or Score annotations following C-Value measure (cvalue) or Score annotations following C-Value measure with hierarchy expansion (cvalueh)" + score_threshold: "Filter by score threshold" + score_threshold_help: "Specify minimum score value for annotations" + confidence_threshold: "Filter Confidence Threshold" + confidence_threshold_help: "Specify the minimum position in the score distribution (between 1 and 100)" + recognizer recognizer: "entity recognition tool" + start_typing_to_select: "Start typing to select %{type} or leave blank to use all" + select: "Select %{name}" + enter_or_paste_text: "Enter or paste text to annotate" + fast_context: "FastContext" + lemmatize: "Lemmatize" + annotations_result: "Annotations" + results_filtered_by: "Results are filtered by" + + umls: + semantic_types: "UMLS Semantic Types" + semantic_groups: "UMLS Semantic Groups" + index: + intro: Get annotations for biomedical text with ontology classes + annotatorplus_html: Check out the beta version of AnnotatorPlus; a new version of the Annotator with added support for negation, and more! + fast_context: + tooltip: "Enable FastContext to detect: if a concept was denied (affirmed, denied), who experienced the found concept (patient, other), when the annotated concept occurred (recent, historical, hypothetical), and/ or if the annotated concept is uncertain (certain, uncertain)." + lemmatize: + tooltip: "Enable Lemmatize to lemmatize submitted text and use a lemmatized dictionary for annotations" + sample_text: Melanoma is a malignant tumor of melanocytes found mainly in the skin but also in the intestine and the eye. + + ontology_details: + metadata: + details: "Details" + acronym: "Acronym" + visibility: "Visibility" + viewing_restriction: "Viewing Restriction" + view_of_ontology: "View of ontology" + description: "Description" + status: "Status" + format: "Format" + contact: "Contact" + categories: "Categories" + groups: "Groups" + pull_url: "Pull URL" + submissions: "Submissions" + links: "Links" + add_submission: "Add Submission" + views_of: "Views of" + create_new_view: "Create a new view" + no_views_of: "No views of %{name} available" + go_to_rest_api_json_entry: "Go to REST API JSON Entry" + get_my_metadata_back: "Get my metadata back" + n_triple: "N-Triple" + json_ld: "JSON-LD" + rdf_xml: "RDF/XML" + view_individual_metrics_definitions: "View individual metrics definitions" + metrics: "Metrics" + metrics_not_calculated_yet: "We have not yet calculated metrics for" + classes: "Classes" + individuals: "Individuals" + properties: "Properties" + max_depth: "Maximum depth" + max_children: "Maximum number of children" + avg_children: "Average number of children" + single_child_classes: "Classes with a single child" + many_children_classes: "Classes with more than 25 children" + no_definition_classes: "Classes without definition" + visits: "Visits" + download_as_csv: "Download as CSV" + projects_using: "Projects Using" + no_projects_using: "No projects are using" + create_new_project: "Create a new project" + additional_metadata: "Additional Metadata" + + layout: + header: + browse: "Browse" + search: "Search" + mappings: "Mappings" + recommend: "Recommend" + annotator: "Annotator" + ncbo_annotator_plus: "NCBO Annotator+" + projects: "Projects" + landscape: "Landscape" + login: "Login" + account_setting: "Account Settings" + submit_feedback: "Send Feedback" + help: "Help" + release_notes: "Release Notes" + publications: "Publications" + footer: + products: Products + ontoportal: OntoPortal + release_notes: Release Notes + api: API + sparql: SPARQL + support: Support + contact_us: Contact Us + wiki: Wiki + documentation: Documentation + agreements: Agreements + terms: Terms + privacy_policy: Privacy Policy + cite_us: Cite Us + acknowledgments: Acknowledgments + about: About + about_us: About Us + projects: Projects + team: Team + copyright_html: Copyright © 2005-2022, Leland Stanford Junior University Board of Trustees. All rights reserved. + grant_html: > + %{site} is currently being developed as part of the ANR D2KAB project (ANR-18-CE23-0017). It receives or has also received support from the ANR SIFR project (ANR-12-JS02-0010), European Union Project H2020-MSCA SIFRm (N° 701771), the Labex NUMEV (ANR-10-LABX-20), the Montpellier IBC project (ANR-11 -BINF0002) , the Agro Labex (ANR-10-LABX-0001) as well than the University of Montpellier and the CNRS. + notes: + license_contact: > + For more information, email support@ontoportal.org or + visit https://ontoportal.org/licensing. + license_obtain: > + If you are the owner of this OntoPortal installation, you can visit + https://license.ontoportal.org to obtain a license. + license_expired: > + We're sorry, but the license for this OntoPortal installation has expired. If you are the owner of this OntoPortal installation, + please visit https://license.ontoportal.org to renew your license. + license_trial: + one: This OntoPortal appliance installation is a trial license, which will expire in 1 day. + other: This OntoPortal appliance installation is a trial license, which will expire in %{count} days. + # Other + + about: > +
+

Summary

+

+ Many vocabularies and ontologies are produced to represent and annotate agronomic data. It is therefore necessary to have a common platform to identify them, host them and use them in agro-informatics applications. The AgroPortal project aims to provide a repository of reference ontologies for agronomy, by reusing the NCBO BioPortal technology. The scientific results and the experience of the biomedical field are thus exploited and transposed in the field of agronomy, including plants, food, the environment and possibly animal sciences. We propose an ontology portal that offers ontology hosting, search, versioning, visualization, commenting, recommendation, allows semantic annotation, as well as storing and exploiting alignments of ontologies. All this in an infrastructure fully compliant with the Semantic Web. The AgroPortal project pays particular attention to meeting the requirements of the agronomic community in terms of ontology formats (e.g. SKOS, trait dictionaries) or supported functionalities. The AgroPortal project is based on five agronomic use cases that participate in the design and orientation of the platform. AgroPortal already offers a robust and stable reference repository, of great value for the field of agronomy. +

+

Use cases

+ +
+

New Features

+

+ See the release-notes +

+
+

Partners

+

The National Center for Biomedical Ontology (NCBO), the Research Institute for Development (IRD), Research Data Alliance (RDA), + Bioversity International, Food & Agriculture Organization (FAO), Global Open Data for Agriculture & Nutrition (Godan Action), National Institute for Agronomic Research (INRA)

+

thanks

+

The AgroPortail is partly produced as part of the Semantic Indexing of French Biomedical Resources project (SIFR) + who have received funding from the EU H2020 research and innovation program under Marie Sklodowska-Curie (grant 701771) + and the National Research Agency (ANR-12-JS02-01001 grant), Labex NUMEV (ANR-10-LABX-20 grant), + the Institute of Computational Biology of Montpellier (grant ANR-11-BINF-0002) as well as by the University of Montpellier and the CNRS. + We also thank the National Center of Biomedical Ontologies for their help and the time spent with us in the deployment of the AgroPortail.

+

Team

+ To contact us: firstname.lastname@lirmm.fr +
    +
  • Clément Jonquet, researcher at LIRMM (Univ. of Montpellier, France), principal investigator of the AgroPortal project
  • +
  • Anne Toulet, researcher at LIRMM (Univ. of Montpellier, France)
  • +
  • Vincent Emonet, engineer at LIRMM (Univ. of Montpellier, France)
  • +
+
+ + activaterecord: + errors: + models: + license: + attributes: + encrypted_key: + invalid_license_key: is an invalid license key + no_appliance_id_for_comparison: Could not be validated. Unable to retrieve virtual appliance ID. + appliance_id_mismatch: is an appliance id mismatch + + admin: + licenses: + create: + success: License renewed successfully! + + date: + formats: + year_month_day_concise: "%Y-%m-%d" # 2017-03-01 + month_day_year: "%b %-d, %Y" # Mar 1, 2017 + monthfull_day_year: "%B %-d, %Y" # March 1, 2017 + ontologies: - intro: Browse the library of ontologies + self: "Ontologies" + loading: Loading ontologies + intro: Browse the Ontology Library + please_wait: Please wait.. + browse: Explore + welcome_admin: Welcome admin + admin_help: This color indicates features reserved for administrators + debug_info: Debug Info + submit_new_ontology: Submit a new ontology + entry_type: Entry Type + uploaded_in_the_last: Uploaded in the last concepts: request_term: new_term_instructions: > -

This ontology integrates with OntoloBridge, allowing community users to suggest additions to the public ontology. Complete the template below to submit a term request directly to the ontology maintainer.

-
-

Term Label (required)
Suggested term name. If a term can be described with multiple synonyms, only list the preferred name here.

-
-
-

Term description (required)
A brief definition, description, or usage of your suggested term. Additional term synonyms may be listed in this section.

-
-
-

Superclass (required)
The parent term of the suggested term. The parent term should be an existing entry of the current ontology. The superclass can be selected directly from Bioportal's Classes tree viewer.

-
-
-

References (optional)
Provide evidence for the existence of the requested term such as Pubmed IDs of papers or links to other resources that describe the term.

-
-
-

Justification (optional)
Provide any additional information about the requested term here.

-
- mappings: - intro: Browse mappings between classes in different ontologies +

This ontology integrates with OntoloBridge, allowing community users to suggest additions to the public ontology. Complete the template below to submit a term request directly to the Ontology Manager.

+
+

Term label (required)
Suggested term name. If a term can be described with more than one synonym, enter only the preferred name here.

+
+
+

Term Description (required)
A brief definition, description, or usage of the suggested term. Synonyms of additional terms may be listed in this section.

+
+
+

Superclass (required)
The parent term of the suggested term. The parent term must be an existing entry in the current ontology. The superclass can be selected directly from the Bioportal class tree.

+
+
+

References (optional)
Provide evidence that the requested term exists, such as Pubmed IDs of articles or links to other resources describing the term.

+
+
+

Justification (optional)
Provide here any additional information about the requested term.

+
+ + # General + + showing: Display + of: of + sort: Sort + popular: Popular + name: Name + classes_count: Number of classes + instances_concepts_count: Number of instances/concepts + Notes: Notes + upload_date: Upload date + release_date: Release date + fair_score: FAIR score + search_rank: Search Rank + no_matches: No matches! + uploaded: Uploaded + view_of: View of + view: View + summary_only: Summary only + groups: Groups + categories: Categories + admins: Administrators + status: Status + no_submissions_available: No submissions available + classes: classes + category: Category + group: Group + size: size + ontology_content: Ontology content + natural_language: Natural language + formality_levels: Formality levels + is_of_type: Is of type + missing_status: Missing Status + types: Types + artifacts: Artifacts + formats: formats + selected_ontologies: Selected ontologies + all: "All" + none: "none" + keywords: "Keywords" + keywords_separated_by_commas: "Keywords separated by commas" + see_details: "See details" + view_fair_scores_definitions: "View fair scores definitions" + get_json_version: "Get the json version" + select_ontologies: "Start typing to select ontologies or leave blank to use them all" + clear_selection: "Clear Selection" + select_from_list: "Select from list" + more: "More" + statistics: "Statistics" + average: "Average" + min: "Min" + max: "Max" + median: "Median" + slices: "Slices" + help: "Help" + or: "Or" + show_advanced_options: "Show advanced options" + insert_sample_text: "Insert sample text" + class: "Class" + filter: "Filter" + ontology: "Ontology" + type: "Type" + context: "Context" + umls_sem_type: "UMLS Sem Type" + matched_ontology: "matched ontology" + matched_class: "Matched class" + score: "Score" + negation: "negation" + experience: "Experience" + temporality: "Temporality" + certainty: "Certainty" + format_results: "Format results as " + reproduce_results: "Reproduce these results using the " + additional_parameters: "Additional Parameters Explained at " + input: "Input" + text: "Text" + output: "Output" + ontology_sets: "Ontology sets" + insert_sample_input: "Insert sample input" + weights_configuration: "Weights Configuration" + coverage: "Coverage" + accept: "Accept" + knowledge_detail: "Knowledge Detail" + specialization: "Specialization" + max_ontologies_per_set: "Maximum number of ontologies per set" + paste_input_text: "Paste a paragraph of text or keywords to use in calculating ontology recommendations" + get_recommendations: "Get recommendations" + select_ontologies_list: "Select ontologies" diff --git a/config/routes.rb b/config/routes.rb index 096db77a1..56d1d4f52 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -150,6 +150,7 @@ get '/ajax/fair_score/json' => 'fair_score#details_json' get '/ajax/:ontology/instances' => 'instances#index_by_ontology' get '/ajax/:ontology/classes/:conceptid/instances' => 'instances#index_by_class', :constraints => { conceptid: /[^\/?]+/ } + get '/ajax/ontologies' , to:"ontologies#ajax_ontologies" # User get '/logout' => 'login#destroy', :as => :logout @@ -210,5 +211,7 @@ get '/visualize' => 'ontologies#visualize', :as => :visualize_concept, :constraints => { ontology: /[^\/?]+/, id: /[^\/?]+/, ontologyid: /[^\/?]+/, conceptid: /[^\/?]+/ } get '/exhibit/:ontology/:id' => 'concepts#exhibit' - + + mount Lookbook::Engine, at: "/lookbook" + end diff --git a/lib/tasks/generate_component_previews.rake b/lib/tasks/generate_component_previews.rake new file mode 100644 index 000000000..2bc61c28b --- /dev/null +++ b/lib/tasks/generate_component_previews.rake @@ -0,0 +1,34 @@ +# lib/tasks/generate_component_previews.rake + +namespace :component_previews do + desc "Generate previews for all components" + task generate: :environment do + components_path = Rails.root.join("app/components") + components = Dir.glob("#{components_path}/**/*_component.rb") + + components.each do |component_path| + component_name = File.basename(component_path, "_component.rb") + preview_path = Rails.root.join("test/components/previews/#{component_name}_preview.rb") + + # Skip if the preview already exists + next if File.exist?(preview_path) + + File.open(preview_path, "w") do |file| + file.puts("class #{component_name.camelize}Preview < ViewComponent::Preview") + file.puts(" def default") + file.puts(" # Initialize the component with any necessary data") + file.puts(" component = #{component_name.camelize}Component.new") + + file.puts(" # Add any necessary data or context to the component") + file.puts(" # component.some_data = some_value") + + file.puts(" # Render the component") + file.puts(" render(component)") + file.puts(" end") + file.puts("end") + end + + puts "Generated preview for #{component_name}" + end + end +end diff --git a/package.json b/package.json index d112843e7..94282d913 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "flatpickr": "^4.6.13", "split.js": "^1.6.5", "stimulus-flatpickr": "^3.0.0-0", - "stimulus-rails-nested-form": "^4.0.0" + "stimulus-rails-nested-form": "^4.0.0", + "stimulus-read-more": "^4.1.0", + "tom-select": "^2.2.2" }, "scripts": { "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds" diff --git a/spec/components/file_input_loader_component_spec.rb b/spec/components/file_input_loader_component_spec.rb deleted file mode 100644 index 9e5190e86..000000000 --- a/spec/components/file_input_loader_component_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require "rails_helper" - -RSpec.describe FileInputLoaderComponent, type: :component do - pending "add some examples to (or delete) #{__FILE__}" - - # it "renders something useful" do - # expect( - # render_inline(described_class.new(attr: "value")) { "Hello, components!" }.css("p").to_html - # ).to include( - # "Hello, components!" - # ) - # end -end diff --git a/test/components/previews/buttons/ontology_subscribe_button_component_preview.rb b/test/components/previews/buttons/ontology_subscribe_button_component_preview.rb new file mode 100644 index 000000000..4d9c2b56d --- /dev/null +++ b/test/components/previews/buttons/ontology_subscribe_button_component_preview.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class Buttons::OntologySubscribeButtonComponentPreview < ViewComponent::Preview + def default + render OntologySubscribeButtonComponent.new(ontology_id: '', subscribed: true, user_id: '') + end +end diff --git a/test/components/previews/buttons/pill_button_component_preview.rb b/test/components/previews/buttons/pill_button_component_preview.rb new file mode 100644 index 000000000..f4cc6a9ac --- /dev/null +++ b/test/components/previews/buttons/pill_button_component_preview.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class Buttons::PillButtonComponentPreview < ViewComponent::Preview + # @param text text + def default(text: 'hello') + render PillButtonComponent.new(text: text) + end +end diff --git a/test/components/previews/buttons/regular_button_component_preview.rb b/test/components/previews/buttons/regular_button_component_preview.rb new file mode 100644 index 000000000..85894c64a --- /dev/null +++ b/test/components/previews/buttons/regular_button_component_preview.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true +class Buttons::RegularButtonComponentPreview < ViewComponent::Preview + include InlineSvg::ActionView::Helpers + layout 'component_preview_not_centred' + + def primary + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "primary") + + end + + def link + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Link", variant: "primary", href: "#") + end + + + def secondary + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "secondary") + end + + def slim + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "primary", size: "slim") + end + + def danger + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "primary", color: "danger") + end + + def warning + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "primary", color: "warning") + end + + def disabled + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "primary", state: "disabled") + end + + def no_animation + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "primary", state: "regular") + end + + def icon_left + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "primary") do |btn| + btn.icon_left do + inline_svg_tag "check.svg" + end + end + end + + def icon_right + + render Buttons::RegularButtonComponent.new(id:'regular-button', value: "Login", variant: "primary") do |btn| + btn.icon_right do + inline_svg_tag "check.svg" + end + end + end + +end \ No newline at end of file diff --git a/test/components/previews/buttons/rounded_button_component_preview.rb b/test/components/previews/buttons/rounded_button_component_preview.rb new file mode 100644 index 000000000..685badf8a --- /dev/null +++ b/test/components/previews/buttons/rounded_button_component_preview.rb @@ -0,0 +1,14 @@ +class Buttons::RoundedButtonComponentPreview < ViewComponent::Preview + + # @param icon text + # @param link text + # @param size select [small, medium, big] + + def default(icon: "json.svg", link: "text", size: "small") + render(RoundedButtonComponent.new(icon: icon, link: link, size: size)) + end + + + + +end \ No newline at end of file diff --git a/test/components/previews/concept_details_component_preview.rb b/test/components/previews/concept_details_component_preview.rb new file mode 100644 index 000000000..3d486535a --- /dev/null +++ b/test/components/previews/concept_details_component_preview.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +class ConceptDetailsComponentPreview < ViewComponent::Preview + def default + properties = { links: nil, + context: nil, + "http://www.w3.org/2004/02/skos/core#narrower": ["http://opendata.inrae.fr/thesaurusINRAE/d_0101", + "http://opendata.inrae.fr/thesaurusINRAE/d_0103", + "http://opendata.inrae.fr/thesaurusINRAE/d_0102", + "http://opendata.inrae.fr/thesaurusINRAE/d_0104", + "http://opendata.inrae.fr/thesaurusINRAE/d_0105"], + "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": ["http://www.w3.org/2004/02/skos/core#Concept", + "http://www.w3.org/2002/07/owl#NamedIndividual"], + "http://www.w3.org/2004/02/skos/core#topConceptOf": ["http://opendata.inrae.fr/thesaurusINRAE/thesaurusINRAE"], + "http://www.w3.org/2004/02/skos/core#prefLabel": ["01. ENVIRONMENT [domain]"], + "http://www.w3.org/2004/02/skos/core#inScheme": ["http://opendata.inrae.fr/thesaurusINRAE/thesaurusINRAE"], + "http://purl.org/dc/terms/modified": ["2021-02-24T15:25:56"] + } + schemes_keys = %w[hasTopConcept topConceptOf] + label_xl_set = %w[skos-xl#prefLabel skos-xl#altLabel skos-xl#hiddenLabel] + render ConceptDetailsComponent.new(id: 'concept-details', acronym: "Ontology", + properties: OpenStruct.new(properties), + top_keys: %w[description comment], + bottom_keys: %w[disjoint subclass is_a has_part], + exclude_keys: schemes_keys + label_xl_set + ['inScheme']) do |c| + c.header(stripped: true) do |table| + table.add_row({ th: 'ID' }, { td: "http://opendata.inrae.fr/thesaurusINRAE/d_1" }) + table.add_row({ th: 'Preferred Name' }, { td: "01. ENVIRONMENT [domain]" }) + table.add_row({ th: 'Type' }, { td: "http://www.w3.org/2004/02/skos/core#Concept" }) + end + end + end +end diff --git a/test/components/previews/display/circle_progress_bar_component_preview.rb b/test/components/previews/display/circle_progress_bar_component_preview.rb new file mode 100644 index 000000000..f22677437 --- /dev/null +++ b/test/components/previews/display/circle_progress_bar_component_preview.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class Display::CircleProgressBarComponentPreview < ViewComponent::Preview + + # @param count number + # @param max number + def default(count: 63, max: 100) + render CircleProgressBarComponent.new(count: count, max: max) + end +end diff --git a/test/components/previews/display/date_time_field_component_preview.rb b/test/components/previews/display/date_time_field_component_preview.rb new file mode 100644 index 000000000..04071bc8c --- /dev/null +++ b/test/components/previews/display/date_time_field_component_preview.rb @@ -0,0 +1,9 @@ +class Display::DateTimeFieldComponentPreview < ViewComponent::Preview + + # @param text text + # @param format select [year_month_day_concise, month_day_year, monthfull_day_year] + def default(text: "2022-10-01", format: 'monthfull_day_year') + render DateTimeFieldComponent.new(value: text, format: format.to_sym) + end + +end \ No newline at end of file diff --git a/test/components/previews/display/field_container_component_preview.rb b/test/components/previews/display/field_container_component_preview.rb new file mode 100644 index 000000000..0f04e8222 --- /dev/null +++ b/test/components/previews/display/field_container_component_preview.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Display::FieldContainerComponentPreview < ViewComponent::Preview + + # @param label text + # @param value text + # + def default(label: 'label' , value: 'value') + render FieldContainerComponent.new(label: label , value: value) + end +end diff --git a/test/components/previews/display/header_component_preview.rb b/test/components/previews/display/header_component_preview.rb new file mode 100644 index 000000000..491190896 --- /dev/null +++ b/test/components/previews/display/header_component_preview.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class Display::HeaderComponentPreview < ViewComponent::Preview + + # @param text text + # @param tooltip text + def default(text: 'header text' , tooltip: 'text tooltip') + render Display::HeaderComponent.new(text: text, tooltip: tooltip) + end +end diff --git a/test/components/previews/display/image_component_preview.rb b/test/components/previews/display/image_component_preview.rb new file mode 100644 index 000000000..d6caa1f9a --- /dev/null +++ b/test/components/previews/display/image_component_preview.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class Display::ImageComponentPreview < ViewComponent::Preview + def default + render Display::ImageComponent.new(src: "empty-box.svg", title: 'Image popup') + end +end diff --git a/test/components/previews/display/info_tooltip_component_preview.rb b/test/components/previews/display/info_tooltip_component_preview.rb new file mode 100644 index 000000000..44f844972 --- /dev/null +++ b/test/components/previews/display/info_tooltip_component_preview.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Display::InfoTooltipComponentPreview < ViewComponent::Preview + + # @param text text + def default(text: 'tooltip text') + render Display::InfoTooltipComponent.new(text: text) + end +end diff --git a/test/components/previews/display/language_field_component_preview.rb b/test/components/previews/display/language_field_component_preview.rb new file mode 100644 index 000000000..29cd56d3a --- /dev/null +++ b/test/components/previews/display/language_field_component_preview.rb @@ -0,0 +1,8 @@ +class Display::LanguageFieldComponentPreview < ViewComponent::Preview + + # @param value text + def default(value: 'fr') + render LanguageFieldComponent.new(value: value) + end + +end \ No newline at end of file diff --git a/test/components/previews/display/license_field_component_preview.rb b/test/components/previews/display/license_field_component_preview.rb new file mode 100644 index 000000000..203318a0b --- /dev/null +++ b/test/components/previews/display/license_field_component_preview.rb @@ -0,0 +1,8 @@ +class Display::LicenseFieldComponentPreview < ViewComponent::Preview + + # @param value select [ CC-BY IGO 3.0, https://creativecommons.org/licenses/by/4.0/, http://www.gnu.org/licenses/gpl-3.0, https://opensource.org/licenses/MIT, http://www.apache.org/licenses/LICENSE-2.0 ] + def default(value: "https://creativecommons.org/licenses/by/4.0/") + render LicenseFieldComponent.new(value: value) + end + +end \ No newline at end of file diff --git a/test/components/previews/display/link_field_component_preview.rb b/test/components/previews/display/link_field_component_preview.rb new file mode 100644 index 000000000..3b6d3a85a --- /dev/null +++ b/test/components/previews/display/link_field_component_preview.rb @@ -0,0 +1,8 @@ +class Display::LinkFieldComponentPreview < ViewComponent::Preview + + # @param text text + def default(text: "https://agroportal.lirmm.fr/") + render LinkFieldComponent.new(value: text) + end + +end \ No newline at end of file diff --git a/test/components/previews/display/link_text_component_preview.rb b/test/components/previews/display/link_text_component_preview.rb new file mode 100644 index 000000000..d041c5c95 --- /dev/null +++ b/test/components/previews/display/link_text_component_preview.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class Display::LinkTextComponentPreview < ViewComponent::Preview + + # @param text text + # @param icon text + def default(text: 'link text', icon: '') + render ChipButtonComponent.new(text: LinkTextComponent.new(text: text, icon: icon).call, type: 'clickable') + end + + # @param text text + def internal(text: 'redirect inside the site') + render ChipButtonComponent.new(text: InternalLinkTextComponent.new(text: text).call, type: 'clickable') + end + + # @param text text + def external(text: 'go out of the site') + render ChipButtonComponent.new(text: ExternalLinkTextComponent.new(text: text).call, type: 'clickable') + end + + # @param text text + def popup(text: 'open popup') + render ChipButtonComponent.new(text: PopupLinkTextComponent.new(text: text).call, type: 'clickable') + end +end diff --git a/test/components/previews/display/text_area_field_component_preview.rb b/test/components/previews/display/text_area_field_component_preview.rb new file mode 100644 index 000000000..efa508ab2 --- /dev/null +++ b/test/components/previews/display/text_area_field_component_preview.rb @@ -0,0 +1,13 @@ +class Display::TextAreaFieldComponentPreview < ViewComponent::Preview + + + # @param value textarea + def default(value: '') + render TextAreaFieldComponent.new(value: value.empty? ? (long_text + long_text) : value ) + end + + private + def long_text + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + end +end \ No newline at end of file diff --git a/test/components/previews/input/chips_component_preview.rb b/test/components/previews/input/chips_component_preview.rb new file mode 100644 index 000000000..146410a12 --- /dev/null +++ b/test/components/previews/input/chips_component_preview.rb @@ -0,0 +1,10 @@ +class Input::ChipsComponentPreview < ViewComponent::Preview + + # @param name text + # @param value text + + def default(name: "name", value: "value") + render(ChipsComponent.new(name: name, value: value)) + end + + end \ No newline at end of file diff --git a/test/components/previews/input/input_field_component_preview.rb b/test/components/previews/input/input_field_component_preview.rb new file mode 100644 index 000000000..49849e984 --- /dev/null +++ b/test/components/previews/input/input_field_component_preview.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +class Input::InputFieldComponentPreview < ViewComponent::Preview + + # This is a date input field: + # - To use it without a label: don't give a value to the param label or leave it empty. + # - To put it in error state: define the param error_message with the error message you want to be displayed. + # - To give it a helper text (a text displayed under the input field): define the param helper_text with the helper text you want to be displayed. + # @param label text + # @param error_message text + # @param helper_text text + + def date(label: "Label", placeholder: "", error_message: "", helper_text: "") + render Input::DateComponent.new(label: label, name: "name", placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + + # This is a url input field: + # - To use it without a label: don't give a value to the param label or leave it empty. + # - To put it in error state: define the param error_message with the error message you want to be displayed. + # - To give it a helper text (a text displayed under the input field): define the param helper_text with the helper text you want to be displayed. + # @param label text + # @param error_message text + # @param helper_text text + + def email(label: "Label", placeholder: "", error_message: "", helper_text: "") + render Input::EmailComponent.new(label: label, name: "name", placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + + def file + render Input::FileInputComponent.new(name: "file") + end + + + # This is a url input field: + # - To use it without a label: don't give a value to the param label or leave it empty. + # - To put it in error state: define the param error_message with the error message you want to be displayed. + # - To give it a helper text (a text displayed under the input field): define the param helper_text with the helper text you want to be displayed. + # @param label text + # @param error_message text + # @param helper_text text + + def password(label: "Label", placeholder: "", error_message: "", helper_text: "") + render Input::PasswordComponent.new(label: label, name: "name", placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + + # This is a url input field: + # - To use it without a label: don't give a value to the param label or leave it empty. + # - To put it in error state: define the param error_message with the error message you want to be displayed. + # - To give it a helper text (a text displayed under the input field): define the param helper_text with the helper text you want to be displayed. + # @param label text + # @param error_message text + # @param helper_text text + + def url(label: "Label", placeholder: "", error_message: "", helper_text: "") + render Input::UrlComponent.new(label: label, name: "name", placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + # This is a text input field: + # - To use it without a label: don't give a value to the param label or leave it empty. + # - To give it a hint (placeholder): define the param hint with the hind you want to be displayed. + # - To put it in error state: define the param error_message with the error message you want to be displayed. + # - To give it a helper text (a text displayed under the input field): define the param helper_text with the helper text you want to be displayed. + # @param label text + # @param placeholder text + # @param error_message text + # @param helper_text text + + def text(label: "Label", placeholder: "", error_message: "", helper_text: "") + render Input::TextInputComponent.new(label: label, name: "name", placeholder: placeholder, error_message: error_message, helper_text: helper_text) + end + + # This is a textarea field: + # - To use it without a label: don't give a value to the param label or leave it empty. + # - To give it a hint (placeholder): define the param hint with the hind you want to be displayed. + # - To put it in error state: define the param error_message with the error message you want to be displayed. + # - To give it a helper text (a text displayed under the input field): define the param helper_text with the helper text you want to be displayed. + + # @param label text + # @param placeholder text + # @param error_message text + # @param helper_text text + # @param rows number + + def text_area(label: "Label", placeholder: "", error_message: "", helper_text: "", rows: 5) + render Input::TextAreaComponent.new(label: label, name: "name",value: '', placeholder: placeholder, error_message: error_message, helper_text: helper_text, rows: rows) + end +end diff --git a/test/components/previews/input/nested_form_input_component_preview.rb b/test/components/previews/input/nested_form_input_component_preview.rb new file mode 100644 index 000000000..ec9329466 --- /dev/null +++ b/test/components/previews/input/nested_form_input_component_preview.rb @@ -0,0 +1,18 @@ +class Input::NestedFormInputComponentPreview < ViewComponent::Preview + + include ActionView::Helpers::TagHelper + include ActionView::Helpers::FormTagHelper + + # @param object_name text + def default(object_name: 'contact') + render NestedFormInputsComponent.new(object_name: object_name) do |c| + c.header do + content_tag(:div, 'Contact name', class: 'w-50 mx-1') + content_tag(:div, 'Contact email', class: 'w-50 mx-1') + end + + c.template do + raw "
".html_safe + end + end + end +end \ No newline at end of file diff --git a/test/components/previews/input/select_component_preview.rb b/test/components/previews/input/select_component_preview.rb new file mode 100644 index 000000000..61599fb78 --- /dev/null +++ b/test/components/previews/input/select_component_preview.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class Input::SelectComponentPreview < ViewComponent::Preview + layout 'component_preview_not_centred' + + def default(id: "", name: "", values: ["choices 1", "choices 2", "choices 3"], selected: "choices 2", multiple: false, open_to_add_values: false) + render Input::SelectComponent.new(id: id, name: name, value: values, selected: selected, multiple: multiple, open_to_add_values: open_to_add_values) + end + + def multiple(id: "", name: "", values: ["choices 1", "choices 2", "choices 3"], selected: "choices 2", multiple: true, open_to_add_values: false) + render Input::SelectComponent.new(id: id, name: name, value: values, selected: selected, multiple: multiple, open_to_add_values: open_to_add_values) + end + + def open_to_add(id: "", name: "", values: ["choices 1", "choices 2", "choices 3"], selected: "choices 2", multiple: true , open_to_add_values: true) + render Input::SelectComponent.new(id: id, name: name, value: values, selected: selected, multiple: multiple, open_to_add_values: open_to_add_values) + end +end diff --git a/test/components/previews/input/switch_input_component_preview.rb b/test/components/previews/input/switch_input_component_preview.rb new file mode 100644 index 000000000..fd40bd6ae --- /dev/null +++ b/test/components/previews/input/switch_input_component_preview.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Input::SwitchInputComponentPreview < ViewComponent::Preview + + # @param label text + def default(label: 'Label') + render SwitchInputComponent.new(id: 'id', name: 'selected_metadata[]', value: '', label: label) + end +end diff --git a/test/components/previews/layout/card_component_preview.rb b/test/components/previews/layout/card_component_preview.rb new file mode 100644 index 000000000..23f07a2d8 --- /dev/null +++ b/test/components/previews/layout/card_component_preview.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class Layout::CardComponentPreview < ViewComponent::Preview + # @param text textarea + def default(text: 'text here') + render Layout::CardComponent.new do + text.html_safe + end + end +end diff --git a/test/components/previews/layout/dropdown_container_component_preview.rb b/test/components/previews/layout/dropdown_container_component_preview.rb new file mode 100644 index 000000000..7d66eb5df --- /dev/null +++ b/test/components/previews/layout/dropdown_container_component_preview.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class Layout::DropdownContainerComponentPreview < ViewComponent::Preview + layout 'component_preview_not_centred' + + # @param title text + # @param content textarea + + def default(title: 'title', content: 'content') + render DropdownContainerComponent.new(id: 'id' , title: title) do + content.html_safe + end + end + +end diff --git a/test/components/previews/layout/list_component_preview.rb b/test/components/previews/layout/list_component_preview.rb new file mode 100644 index 000000000..ea57e5836 --- /dev/null +++ b/test/components/previews/layout/list_component_preview.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class Layout::ListComponentPreview < ViewComponent::Preview + def vertical + render Layout::ListComponent.new do |l| + 4.times.each do |i| + l.row {content_tag(:div , "element #{i}", class: 'p-1 border')} + end + end + end + + def horizontal + render Layout::HorizontalListComponent.new do |l| + 4.times.each do |i| + l.element {content_tag(:div , "element #{i}", class: 'p-1 border')} + end + end + end +end diff --git a/test/components/previews/layout/progress_pages_component_preview.rb b/test/components/previews/layout/progress_pages_component_preview.rb new file mode 100644 index 000000000..afb6596de --- /dev/null +++ b/test/components/previews/layout/progress_pages_component_preview.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Layout::ProgressPagesComponentPreview < ViewComponent::Preview + + # @param pages_count number + def default(pages_count: 5) + render Layout::ProgressPagesComponent.new(pages_title: (pages_count || 0).times.map { |x| "page #{x}" }) do |c| + 5.times.each { |i| c.page { content_tag(:div, "page #{i}", class: "p-5 mx-5 text-center", style: 'width: 500px') } } + end + end +end diff --git a/test/components/previews/layout/summary_section_component_preview.rb b/test/components/previews/layout/summary_section_component_preview.rb new file mode 100644 index 000000000..626770b14 --- /dev/null +++ b/test/components/previews/layout/summary_section_component_preview.rb @@ -0,0 +1,14 @@ +class Layout::SummarySectionComponentPreview < ViewComponent::Preview + layout 'component_preview_not_centred' + # @param title text + # @param content textarea + # @param link url + # @param link_title text + # @param show_card toggle + def default(title: 'title' , link: nil, link_title: nil, show_card: true, content: 'here is the content') + render SummarySectionComponent.new(title: title , link: link, link_title: link_title, show_card: show_card) do + content.html_safe + end + end + +end \ No newline at end of file diff --git a/test/components/previews/layout/table_component_preview.rb b/test/components/previews/layout/table_component_preview.rb new file mode 100644 index 000000000..b38a7cd0f --- /dev/null +++ b/test/components/previews/layout/table_component_preview.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class Layout::TableComponentPreview < ViewComponent::Preview + + include ActionView::Helpers::UrlHelper + + def default + render TableComponent.new do |t| + table_content(t) + end + end + + def stripped + render TableComponent.new(stripped: true) do |t| + table_content(t) + end + end + + private + + def table_content(t) + headers = 5.times.map { |i| "header #{i}" } + rows = 6.times.map { |row| 5.times.map { |i| "line #{row} :#{i} " } } + + t.header do |h| + headers.each do |header| + h.th { header } + end + h.th { 'Action' } + end + + rows.each do |row| + t.row do |r| + row.each do |col| + r.td { col } + end + + r.td do + link_to('Edit', '', class: 'mr-3') + link_to('Delete', '') + end + end + end + + end +end diff --git a/test/components/previews/layout/tabs_container_component_preview.rb b/test/components/previews/layout/tabs_container_component_preview.rb new file mode 100644 index 000000000..b82e09f32 --- /dev/null +++ b/test/components/previews/layout/tabs_container_component_preview.rb @@ -0,0 +1,78 @@ +class Layout::TabsContainerComponentPreview < ViewComponent::Preview + + + def default + render TabsContainerComponent.new do |c| + sections = ['section 1', 'section 2', 'section 3', 'section 4'] + + sections.each do |section_title| + c.item(title: section_title, + path: "#{section_title}path", + selected: section_title.eql?('section 2'), + page_name: "#{section_title}path") + + c.item_content do + section_title + end + end + + end + end + + def pill + render TabsContainerComponent.new(type: 'pill') do |c| + sections = ['section 1', 'section 2', 'section 3', 'section 4'] + + sections.each do |section_title| + c.item(title: section_title, + path: "#{section_title}path", + selected: section_title.eql?('section 2'), + page_name: "#{section_title}path") + + c.item_content do + section_title + end + end + + end + end + + def outline + render TabsContainerComponent.new(type: 'outline') do |c| + sections = ['section 1', 'section 2', 'section 3', 'section 4'] + + sections.each do |section_title| + c.item(title: section_title, + path: "#{section_title}path", + selected: section_title.eql?('section 2'), + page_name: "#{section_title}path") + + c.item_content do + section_title + end + end + + end + end + + def with_action_links + render TabsContainerComponent.new do |c| + sections = ['section 1', 'section 2', 'section 3', 'section 4'] + + sections.each do |section_title| + c.item(title: section_title, + path: "#{section_title}path", + selected: section_title.eql?('section 2'), + page_name: "#{section_title}path") + + c.item_content do + section_title + end + end + c.pinned_right do + RoundedButtonComponent.new(icon: 'check.svg').render_in(c) + ''.html_safe + RoundedButtonComponent.new.render_in(c) + end + end + end + +end \ No newline at end of file diff --git a/test/components/previews/layout/turbo_modal_component_preview.rb b/test/components/previews/layout/turbo_modal_component_preview.rb new file mode 100644 index 000000000..bf976326d --- /dev/null +++ b/test/components/previews/layout/turbo_modal_component_preview.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Layout::TurboModalComponentPreview < ViewComponent::Preview + layout 'component_preview_not_centred' + + include ActionView::Helpers::TagHelper + include ActionView::Context + + # @param title text + # @param message text + def default(message: 'hello you !', title: 'title') + render TurboModalComponent.new(title: title, show: true) do + content_tag(:div, message, class: 'p-5') + end + end +end diff --git a/test/components/previews/loader_component_preview.rb b/test/components/previews/loader_component_preview.rb new file mode 100644 index 000000000..78e55ca33 --- /dev/null +++ b/test/components/previews/loader_component_preview.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class LoaderComponentPreview < ViewComponent::Preview + def default + render LoaderComponent.new + end + + def small + render LoaderComponent.new(small: true) + end + +end diff --git a/test/components/previews/notification_component_preview.rb b/test/components/previews/notification_component_preview.rb new file mode 100644 index 000000000..407c0d947 --- /dev/null +++ b/test/components/previews/notification_component_preview.rb @@ -0,0 +1,12 @@ +class NotificationComponentPreview < ViewComponent::Preview + + # @param title text + # @param message text + # @param type select [success, alert, error] + # @param auto_remove toggle + + def default(title: "Notification message", message: "Here we can type a success or failure message to the user", type: 'success', auto_remove: false) + render NotificationComponent.new(title: title, comment: message, type: type, auto_remove: auto_remove) + end + +end \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index c90a58e5c..a16ad8d21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,6 +25,18 @@ resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-7.3.0.tgz#2226000fff1aabda9fd9587474565c9929dbf15d" integrity sha512-Dcu+NaSvHLT7EjrDrkEmH4qET2ZJZ5IcCWmNXxNQTBwlnE5tBZfN6WxZ842n5cHV52DH/AKNirbPBtcEXDLW4g== +"@orchidjs/sifter@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@orchidjs/sifter/-/sifter-1.0.3.tgz#43f42519472282eb632d0a1589184f044d64129b" + integrity sha512-zCZbwKegHytfsPm8Amcfh7v/4vHqTAaOu6xFswBYcn8nznBOuseu6COB2ON7ez0tFV0mKL0nRNnCiZZA+lU9/g== + dependencies: + "@orchidjs/unicode-variants" "^1.0.4" + +"@orchidjs/unicode-variants@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@orchidjs/unicode-variants/-/unicode-variants-1.0.4.tgz#6d2f812e3b19545bba2d81caffff1204de9a6a58" + integrity sha512-NvVBRnZNE+dugiXERFsET1JlKZfM5lJDEpSMilKW4bToYJ7pxf0Zne78xyXB2ny2c2aHfJ6WLnz1AaTNHAmQeQ== + "@rails/actioncable@^7.0": version "7.0.4" resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.0.4.tgz#70a3ca56809f7aaabb80af2f9c01ae51e1a8ed41" @@ -178,3 +190,16 @@ stimulus-rails-nested-form@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/stimulus-rails-nested-form/-/stimulus-rails-nested-form-4.1.0.tgz#bfce185cff908170a4eb9973875b72517c3bc83a" integrity sha512-ORqcTsg3sa4PGFEyUkbvcPG56F4K2fx1qJCUQIgngO1GaW5taKcvDkT0HvdTqtQAFe/1lN4CpJAqoSCt+nYF/Q== + +stimulus-read-more@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/stimulus-read-more/-/stimulus-read-more-4.1.0.tgz#f34efb2dcb33fd091936d84c569937bc100506c8" + integrity sha512-SJyCJqZrhDSKpfrepnhStBaxtyv6Jnvr+b84GDg3l+/BzL5HaFLYmc6QkSNCeR6y0x+Zw7lwKuzv+XzyAm1KzQ== + +tom-select@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tom-select/-/tom-select-2.2.2.tgz#8e5f9296e6d80254feccb57f0986bd6c44d126e2" + integrity sha512-igGah1yY6yhrnN2h/Ky8I5muw/nE/YQxIsEZoYu5qaA4bsRibvKto3s8QZZosKpOd0uO8fNYhRfAwgHB4IAYew== + dependencies: + "@orchidjs/sifter" "^1.0.3" + "@orchidjs/unicode-variants" "^1.0.4"