diff --git a/app/assets/images/icons/calendar.svg b/app/assets/images/icons/calendar.svg new file mode 100644 index 0000000000..7ad6a2f7ac --- /dev/null +++ b/app/assets/images/icons/calendar.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 0000000000..eac310be4a --- /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 0000000000..4c1b3ded20 --- /dev/null +++ b/app/assets/images/icons/list.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/images/list-tree.svg b/app/assets/images/list-tree.svg deleted file mode 100644 index 4180dac32a..0000000000 --- a/app/assets/images/list-tree.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/stylesheets/components/index.scss b/app/assets/stylesheets/components/index.scss index 35a9b13920..09c2d57732 100644 --- a/app/assets/stylesheets/components/index.scss +++ b/app/assets/stylesheets/components/index.scss @@ -12,6 +12,9 @@ @import 'input_field'; @import 'file_input_loader'; @import 'text_area_field'; +@import 'tabs_container'; +@import 'pill_tabs_container'; +@import 'outline_tabs_container'; @import 'pill_button'; @import "switch"; @import "table"; 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 0000000000..76c390d92a --- /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_tabs_container.scss b/app/assets/stylesheets/components/pill_tabs_container.scss new file mode 100644 index 0000000000..e03697544c --- /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/tabs_container.scss b/app/assets/stylesheets/components/tabs_container.scss new file mode 100644 index 0000000000..87ef9291ce --- /dev/null +++ b/app/assets/stylesheets/components/tabs_container.scss @@ -0,0 +1,56 @@ +.tabs-container { + border-bottom: 1px solid #DFDFDF; + display: flex; + justify-content: space-between; + & > div { + display: flex; + justify-content: space-between; + } +} + +.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/concepts.scss b/app/assets/stylesheets/concepts.scss index 87627bd5ce..783cf2097f 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; } } @@ -55,7 +55,7 @@ div.synonym-change-request button { justify-content: space-between; align-items: center; } -.concepts-tabs{ +.concepts-tabs{ display: flex; justify-content: space-between; width: 589px; @@ -105,7 +105,7 @@ div.synonym-change-request button { margin-top: 20px; border-radius: 5px; border: 1px solid #DFDFDF; - + } .concepts-raw-title{ display: flex; @@ -119,6 +119,34 @@ div.synonym-change-request button { .concepts-raw-title div{ padding: 10px 0px; } + #details_content{ - margin-top: 15px; + border: none !important; +} + +#details_content .card{ + border-top: none !important; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +#concept_browser{ + .outline-tabs .tab-items{ + width: 100%; + } + .outline-tabs .tab-items .nav-item { + flex: 1; + } + .outline-tabs .tab-items .nav-item a { + display: flex; + justify-content: center; + svg path { + fill: #5e5e5e !important; + } + } + .outline-tabs .tab-items .nav-item.active a { + svg path { + fill: var(--primary-color) !important; + } + } } \ No newline at end of file diff --git a/app/assets/stylesheets/ontologies.scss b/app/assets/stylesheets/ontologies.scss index 4de56daa7a..ffd00d9aaf 100644 --- a/app/assets/stylesheets/ontologies.scss +++ b/app/assets/stylesheets/ontologies.scss @@ -11,7 +11,6 @@ $ont-show-bg-color: #e9ecef; } .ontologies.show .gutter { - background-color: rgba(0, 0, 0, 0.03); background-repeat: no-repeat; background-position: center; @@ -271,4 +270,3 @@ $ont-show-bg-color: #e9ecef; flex-direction: row; } - diff --git a/app/components/rounded_button_component.rb b/app/components/rounded_button_component.rb index 65a11dd0ae..47983fce1b 100644 --- a/app/components/rounded_button_component.rb +++ b/app/components/rounded_button_component.rb @@ -1,19 +1,20 @@ class RoundedButtonComponent < ViewComponent::Base - def initialize(icon: "json.svg", link: "#", size: "small") - @icon = icon - @link = link - @size = size - end + 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 + 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 index 7eb803affe..4baa20df96 100644 --- a/app/components/rounded_button_component/rounded_button_component.html.haml +++ b/app/components/rounded_button_component/rounded_button_component.html.haml @@ -1,2 +1,2 @@ -%a.rounded-button{:href => @link, style: "height:"+size[0]+"; width:"+size[0]+"; border-radius:"+size[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/tab_item_component.rb b/app/components/tab_item_component.rb new file mode 100644 index 0000000000..b6612bb5be --- /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/tabs_container_component.rb b/app/components/tabs_container_component.rb new file mode 100644 index 0000000000..bb9ecaa21c --- /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 0000000000..2ee9f88186 --- /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 0000000000..9991b699f0 --- /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/helpers/ontologies_helper.rb b/app/helpers/ontologies_helper.rb index b2706d9eb9..dfbcf251aa 100644 --- a/app/helpers/ontologies_helper.rb +++ b/app/helpers/ontologies_helper.rb @@ -457,7 +457,7 @@ def language_selector_tag(name) end end else - select_tag name, languages_options, class: 'custom-select', disabled: !ontology_data_section?, style: "visibility: #{ontology_data_section? ? 'visible' : 'hidden'}; margin-bottom: -10px;", data: {'ontology-viewer-tabs-target': 'languageSelector'} + select_tag name, languages_options, class: '', disabled: !ontology_data_section?, style: "visibility: #{ontology_data_section? ? 'visible' : 'hidden'}; border: none; outline: none;", data: {'ontology-viewer-tabs-target': 'languageSelector'} end end diff --git a/app/javascript/component_controllers/index.js b/app/javascript/component_controllers/index.js index b9968423b4..cb96f8b3e1 100644 --- a/app/javascript/component_controllers/index.js +++ b/app/javascript/component_controllers/index.js @@ -13,9 +13,13 @@ import Ontology_subscribe_button_component_controller import Search_input_component_controller from "../../components/search_input_component/search_input_component_controller"; +import Tabs_container_component_controller + from "../../components/tabs_container_component/tabs_container_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) diff --git a/app/javascript/controllers/ontology_viewer_tabs_controller.js b/app/javascript/controllers/ontology_viewer_tabs_controller.js index f8cb2a3106..6ddf9b71bd 100644 --- a/app/javascript/controllers/ontology_viewer_tabs_controller.js +++ b/app/javascript/controllers/ontology_viewer_tabs_controller.js @@ -26,16 +26,9 @@ export default class extends Controller { this.changeEvent.removeEventListener() } - selectTab(event) { - this.#updateURL(event) - } - - #updateURL(event){ - const page = event.target.getAttribute("data-bp-ont-page"); - const page_name = event.target.getAttribute("data-bp-ont-page-name"); - - (new HistoryService()).pushState({p: page}, page_name + " | " + jQuery(document).data().bp.ont_viewer.org_site, "?p=" + page); - + updateLanguageSelector(event) { + console.log('language selector update') + let page = event.detail.data.selectedTab this.#disableLanguageSelector(page) } diff --git a/app/views/admin/index.html.haml b/app/views/admin/index.html.haml index a67c026743..91b174eb52 100644 --- a/app/views/admin/index.html.haml +++ b/app/views/admin/index.html.haml @@ -13,27 +13,14 @@ %div.row %div.col - %ul.nav.nav-tabs{id: "admin-tabs", role: "tablist"} - %li.nav-item - =link_to("Site Administration", "#site-admin", id: "site-admin-tab", class: "nav-link active", role: "tab", data: { toggle: "tab" }, aria: { controls: "site-admin", selected: "true" }) - %li.nav-item - =link_to("Ontology Administration", "#ontology-admin", id: "ontology-admin-tab", class: "nav-link", role: "tab", data: { toggle: "tab" }, aria: { controls: "ontology-admin", selected: "false" }) - %li.nav-item - =link_to("Licensing", "#licensing", id: "licensing-admin-tab", class: "nav-link", role: "tab", data: { toggle: "tab", href: admin_licenses_path() }, aria: { controls: "licensing", selected: "false" }) - %li.nav-item - =link_to("Users", "#users", id: "users-admin-tab", class: "nav-link", role: "tab", data: { toggle: "tab", href: users_path() }, aria: { controls: "users", selected: "false" }) - %li.nav-item - =link_to("Metadata Administration", "#ontologies_metadata_curator", id: "ontologies_metadata_curator-admin-tab", class: "nav-link", role: "tab", data: { toggle: "tab"}, aria: { controls: "ontologies_metadata_curator", selected: "false" }) - %li.nav-item - =link_to("Groups", "#groups", id: "groups-admin-tab", class: "nav-link", role: "tab", data: { toggle: "tab", href: "groups" }, aria: { controls: "groups", selected: "false" }) - %li.nav-item - =link_to("Categories", "#categories", id: "categories-admin-tab", class: "nav-link", role: "tab", data: { toggle: "tab", href: "categories" }, aria: { controls: "categories", selected: "false" }) - %div#adminTabContent.tab-content - - -# Site Administration tab - %div.tab-pane.active.show.fade{id: "site-admin", role: "tabpanel", aria: { labelledby: "site-admin-tab" }} - - -# Clear caches + - sections = ['Site Administration','Ontology Administration', 'Licensing', 'Users', 'Metadata Administration', 'Groups', 'Categories'] + = render TabsContainerComponent.new do |t| + - sections.each do |section_title| + - t.item(title: section_title, + path: '', + selected: section_title.eql?(sections.first), + page_name: '') + - t.item_content do %div#site-admin-clear-caches.my-5 %div.site-admin-page-header CACHE MANAGEMENT @@ -42,33 +29,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 +60,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,35 +69,26 @@ %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 - %div.tab-pane.fade{id: "groups", role: "tabpanel", aria: { labelledby: "groups-admin-tab" }} + - t.item_content do %div.ontologies_list_container.mt-3 %table#adminGroups.zebra{:cellpadding => "0", :cellspacing => "0", :width => "100%"} - - -# Categories tab - %div.tab-pane.fade{id: "categories", role: "tabpanel", aria: { labelledby: "categories-admin-tab" }} + - t.item_content do %div.ontologies_list_container.mt-3 %table#adminCategories.zebra{:cellpadding => "0", :cellspacing => "0", :width => "100%"} - \ No newline at end of file diff --git a/app/views/concepts/_show.html.haml b/app/views/concepts/_show.html.haml index af69f8f2ef..1988ec9000 100644 --- a/app/views/concepts/_show.html.haml +++ b/app/views/concepts/_show.html.haml @@ -3,58 +3,62 @@ %div{:style => "padding: 100px 0; font-size: larger; font-weight: bold; text-align: center;"} Use the "Jump To" to find a class and display details, visualization, notes, and mappings - else + = render TabsContainerComponent.new(type:'outline') do |c| + + - c.pinned_right do + - if $PURL_ENABLED + %div.mx-1 + = link_to("#classPermalinkModal", class: "class-permalink nav-link", title: "Get a permanent link to this class", aria: {label: "Get a permanent link to this class"}, data: {toggle: "modal", current_purl: "#{@current_purl}"}) do + %i{class: "fas fa-link", aria: {hidden: "true"}} + %div + = render RoundedButtonComponent.new(link: "#{@ontology.id}/classes/#{escape(@concept.id)}?display=all&apikey=#{get_apikey}", target:'_blank') + + - c.item(title: 'Details', path: '#details', selected: true) - %ul.nav.tabs - %li#details_top.nav-item - %a.nav-link.active.py-1{:href => "#details" , data:{toggle: 'tab', target: '#details_content'}} Details - unless skos? - %li#instances_top.nav-item - %a.nav-link.py-1{:href => "#instances" , data:{toggle: 'tab', target: '#instances_content'}} - Instances - ( - %span#instances_count - ) - %li#visualization_top.nav-item - %a.nav-link.py-1{:href => "#visualization", data:{toggle: 'tab', target: '#visualization_content'}} Visualization - %li#notes_top.nav-item - %a.nav-link.py-1{:href => "#notes", data:{toggle: 'tab', target: '#notes_content'}} - Notes - %span#note_count_wrapper - ( - %span#note_count= @notes.length - ) - %li#mappings_top.nav-item - %a.nav-link.py-1{:href => "#mappings", data:{toggle: 'tab', target: '#mappings_content'}} - #{concept_label_to_show(submission: @submission)} Mappings ( - %span#mapping_count= 'loading' + - c.item(id: 'instances', path: '#instances') do + Instances + ( + %span#instances_count + ) + + - c.item(title: 'Visualization', path: '#visualization') + + - c.item(id: 'notes', path: '#notes') do + Notes + %span#note_count_wrapper + ( + %span#note_count= @notes.length ) - %a.concepts-json{:href => "#{@ontology.id}/classes/#{escape(@concept.id)}?display=all&apikey=#{get_apikey}", target: '_blank'} - = inline_svg_tag "json.svg" + - c.item(id: 'mappings', path: '#mappings') do + #{concept_label_to_show(submission: @submission)} Mappings ( + %span#mapping_count= 'loading' + ) - if @enable_ontolobridge - %li#request_term_top.nav-item - %a.nav-link.py-1{:href => "#request_term", data:{toggle: 'tab', target: '#request_term'}} - New Term Requests - - if $PURL_ENABLED - = link_to("#classPermalinkModal", class: "class-permalink nav-link", title: "Get a permanent link to this class", aria: {label: "Get a permanent link to this class"}, data: {toggle: "modal", current_purl: "#{@current_purl}"}) do - %i{class: "fas fa-link", aria: {hidden: "true"}} - #contents.tab-content - #details_content.tab-pane.active.show + - c.item(title: ' New Term Requests', path: '#request_term') + + - c.item_content do = render :partial =>'/concepts/details' + - unless skos? - #instances_content.tab-pane + - c.item_content do = render :partial =>'instances/instances' , locals: {id: "class-instances-data-table"} - #visualization_content.tab-pane + - c.item_content do = render :partial =>'/concepts/biomixer' - #notes_content.tab-pane + + - c.item_content do = render :partial =>'/notes/list' - #mappings_content.tab-pane + + - c.item_content do = render TurboFrameComponent.new(id:'concept_mappings', src:"/ajax/mappings/get_concept_table?ontologyid=#{@ontology.acronym}&conceptid=#{CGI.escape(@concept.id)}") + - if @enable_ontolobridge - #request_term_content.tab-pane + - c.item_content do = render :partial =>'/concepts/request_term' + :javascript jQuery(document).ready(function(){ diff --git a/app/views/layouts/_ontology_viewer.html.haml b/app/views/layouts/_ontology_viewer.html.haml index 7b7094dd67..5b826f3117 100644 --- a/app/views/layouts/_ontology_viewer.html.haml +++ b/app/views/layouts/_ontology_viewer.html.haml @@ -41,28 +41,26 @@ = render partial: 'kgcl_dialogs' - %div.row.pt-md-3.pb-md-2 - %div.col + %div.pt-md-3.pb-md-2.p-2 + %div = render partial: 'layouts/ontology_viewer/header' - %div.row.pb-4{data: {controller: 'ontology-viewer-tabs', 'ontology-viewer-tabs-language-sections-value': ontology_data_sections }} - %div.col + %div.pb-4.p-2.bg-white{data: {controller: 'ontology-viewer-tabs', 'ontology-viewer-tabs-language-sections-value': ontology_data_sections }} + %div - sections = sections_to_show - %div.card - %div.card-header - %div{style: "display: flex; justify-content: space-between;"} - %ul.nav.nav-tabs.card-header-tabs{id: "navbar-ontology", role: "tablist"} - - sections.each do |section| - %li.nav-item - = link_to_section(section) - %div + %div.ontologies-tabs-container{data:{action: 'tab-selected->ontology-viewer-tabs#updateLanguageSelector'}} + = render TabsContainerComponent.new(id: 'ontology_viewer', url_parameter: 'p') do |t| + - sections.each do |section_title| + - t.item(title: section_title, + path: ontology_path(@ontology.acronym, p: section_title), + selected: selected_section?(section_title), + page_name: ontology_viewer_page_name(@ontology.name, @concept&.prefLabel || '', section_title)) + - t.pinned_right do = language_selector_tag(:language_selector) - %div.card-body - %div.tab-content - - sections.each do |section| - %div.tab-pane{id: "ont_#{section}_content", class: selected_section?(section) ? 'active show' : '', data: section_data(section)} - = language_selector_hidden_tag(section) if ontology_data_section?(section) - = lazy_load_section(section) { yield } + - t.item_content do + %div.p-1{data: section_data(section_title)} + = language_selector_hidden_tag(section_title) if ontology_data_section?(section_title) + = lazy_load_section(section_title) { yield } = render partial: "layouts/footer" diff --git a/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml b/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml index 1c4c5128c2..8f74659d2d 100644 --- a/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml +++ b/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml @@ -1,18 +1,25 @@ -%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'} - if skos? - %a#concepts-list-tab.nav-item.nav-link.flex-grow-1.border-radius-0{"data-toggle" => "tab", :href => "#concepts-list-container", title: 'Collection view', 'data-controller': "tooltip", class: sub_menu_active_class('list')} - %i.fas.fa-list.text-dark{style:'font-size: 25px'} - %a#concepts-date-sort-tab.nav-item.nav-link.flex-grow-1.border-radius-0{"data-toggle" => "tab", :href => "#concepts-date-sort-container", title: 'Date view', 'data-controller': "tooltip", class: sub_menu_active_class('date')} - %i.far.fa-calendar-alt.text-dark{style:'font-size: 25px'} -.tab-content.px-1.py-2 - #concepts-tree-container.tab-pane.fade{class: default_sub_menu_class} - = render partial: 'ontologies/concepts_browsers/concepts_tree' - - if skos? - #concepts-list-container.tab-pane.fade{class: sub_menu_active_class('list')} - = render partial: 'ontologies/concepts_browsers/concepts_list' - #concepts-date-sort-container.tab-pane.fade{class: sub_menu_active_class('date')} - = render partial: 'ontologies/concepts_browsers/concepts_date_sort' \ No newline at end of file + - c.item(id: 'list-tab', selected: sub_menu_active?('list')) do + %span{title: 'Collection view', 'data-controller': "tooltip"} + = inline_svg('icons/list.svg', style:'width: 18px; height: 18px') + + - c.item(id: 'date-tab', selected: sub_menu_active?('date')) do + %span{title: 'Date view', 'data-controller': "tooltip"} + = inline_svg('icons/calendar.svg', style:'width: 18px; height: 18px') + + - c.item_content do + %div.p-1 + = render partial: 'ontologies/concepts_browsers/concepts_tree' + - if skos? + - c.item_content do + %div.p-1 + = render partial: 'ontologies/concepts_browsers/concepts_list' + - c.item_content do + %div.p-1 + = render partial: 'ontologies/concepts_browsers/concepts_date_sort' diff --git a/app/views/ontologies/sections/visualize.html.haml b/app/views/ontologies/sections/visualize.html.haml index fcaa805f2a..3851db29de 100644 --- a/app/views/ontologies/sections/visualize.html.haml +++ b/app/views/ontologies/sections/visualize.html.haml @@ -5,9 +5,9 @@ - @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.p-1.ml-2{data:{'container-splitter-target': 'container'}} + %div#concept_content.d-flex.flex-column.p-1.ml-1{data:{'container-splitter-target': 'container'}} = render partial: 'concepts/show' - form_for(:search, :url => {:controller =>'search',:action=>'fetch_results'},:html=>{:id=>'search_form'}) do |f| 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 0000000000..b82e09f32a --- /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