From 7787bb666ebe3efee5be1324581af20060885f2e Mon Sep 17 00:00:00 2001 From: B_Rass Date: Wed, 25 Feb 2026 18:21:51 +0100 Subject: [PATCH] WIP --- app/assets/stylesheets/application.scss | 11 ++- .../stylesheets/bootstrap-variables.scss | 1 + .../components/table_component.scss | 90 +++++++++++++++++++ app/components/list/data_table_component.rb | 36 ++++---- app/components/list/table_component.rb | 13 +-- app/decorators/room_decorator.rb | 6 ++ app/views/rooms/index.html.erb | 31 ++++--- app/views/rooms/show.html.erb | 2 +- app/views/sites/index.html.erb | 4 +- config/locales/activerecord.fr.yml | 3 +- 10 files changed, 157 insertions(+), 40 deletions(-) create mode 100644 app/assets/stylesheets/components/table_component.scss diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index fb6686147..b9d26a68a 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -782,7 +782,7 @@ body { } } - table { + /* table { a:not(.btn):not(.dropdown-item) { text-decoration: none; @@ -790,7 +790,7 @@ body { text-decoration: underline; } } - } + } */ dl.show-page_dl { grid-template-columns: auto 1fr; @@ -958,6 +958,11 @@ body { .border-dashed { --bs-border-style: dashed; + border-style: dashed; + } + + .all-small-caps { + font-variant: all-small-caps; } /* Bootstrap clean */ @@ -990,7 +995,7 @@ body { } .ts-dropdown { - z-index: 9999; + z-index: 8888; } /* Tom-Select fix for bootstrap floating label */ diff --git a/app/assets/stylesheets/bootstrap-variables.scss b/app/assets/stylesheets/bootstrap-variables.scss index 46685496b..c36ecf417 100644 --- a/app/assets/stylesheets/bootstrap-variables.scss +++ b/app/assets/stylesheets/bootstrap-variables.scss @@ -1,6 +1,7 @@ $breadcrumb-divider: quote(">"); $enable-negative-margins: true; $min-contrast-ratio: 3; +$table-striped-order: even; :root { --navbar-height: 66px; diff --git a/app/assets/stylesheets/components/table_component.scss b/app/assets/stylesheets/components/table_component.scss new file mode 100644 index 000000000..bf9e89775 --- /dev/null +++ b/app/assets/stylesheets/components/table_component.scss @@ -0,0 +1,90 @@ +.table-component { + table { + --bs-table-hover-bg: rgba(var(--bs-primary-rgb), 0.09); + /* --bs-table-hover-color: var(--bs-link-color); */ + + --bs-table-striped-bg: rgb(var(--bs-tertiary-bg-rgb)); + + th { + a { + font-size: .9rem; + color: var(--bs-tertiary-color); + visibility: hidden; + + &:hover { + color: rgb(var(--bs-primary-rgb)); + + span.bi-arrow-down-short::before { + content: "\f128"; + } + + span.bi-arrow-up-short::before { + content: "\f148"; + } + } + + span.bi-arrow-down-short.link-primary::before { + content: "\f128"; + } + + span.bi-arrow-up-short.link-primary::before { + content: "\f148"; + } + } + + &:hover { + a { + visibility: visible; + } + } + + a:has(span.bi.link-primary) { + visibility: visible; + } + + &:has(a) { + text-decoration: underline dotted; + text-underline-offset: .2em; + text-decoration-color: rgba(var(--bs-body-color-rgb), 0.25); + } + } + + tr { + td { + padding: 1rem .5rem; + + a:not(.btn):not(.dropdown-item) { + color: inherit; + text-decoration: underline dashed; + text-decoration-color: rgba(var(--bs-body-color-rgb), 0.5); + text-underline-offset: 0.4em; + + &:hover { + color: var(--bs-link-color); + text-decoration: underline; + } + } + + /* &:nth-child(even) { + td { + background-color: var(--bs-table-color-state); + } + } */ + + &:hover { + a:not(.btn):not(.dropdown-item) { + &:hover { + text-decoration-color: rgba(var(--bs-link-color-rgb), 0.5); + } + } + } + } + + &:last-child { + td { + border: none !important; + } + } + } + } +} diff --git a/app/components/list/data_table_component.rb b/app/components/list/data_table_component.rb index 368256e7a..1299377ac 100644 --- a/app/components/list/data_table_component.rb +++ b/app/components/list/data_table_component.rb @@ -74,10 +74,10 @@ def render_bulk_head_checkbox def render_head_cell(col) render(List::TableComponent::TableHeadCell.new(data: { name: col.name })) do + concat col.title + if (sort_by = col.sort_by) - link_to_sort col.title, sort_by - else - col.title + links_to_sort sort_by end end end @@ -102,28 +102,32 @@ def render_col(col, row) col.call(row) end - def link_to_sort(label, attribute) + def links_to_sort(attribute) current_attribute = params[:sort_by]&.to_sym - current_direction = current_attribute == attribute ? params[:sort].to_sym : nil + is_current_attribute = current_attribute == attribute + current_direction = is_current_attribute ? params[:sort].to_sym : nil + + concat(link_to_sort(attribute, is_current_attribute, :asc, current_direction)) + concat(link_to_sort(attribute, is_current_attribute, :desc, current_direction)) + end - parameters = case current_direction - when nil then { sort_by: attribute, sort: :asc } - when :asc then { sort_by: attribute, sort: :desc } - else { sort_by: nil, sort: nil } - end + def link_to_sort(attribute, is_current_attribute, direction, current_direction) + caret = direction == :asc ? "arrow-up-short" : "arrow-down-short" + is_current_direction = current_direction == direction + parameters = is_current_direction ? { sort_by: nil, sort: nil } : { sort_by: attribute, sort: direction } url = url_for(controller.request.query_parameters.merge(parameters)) link_to(url) do - concat label - concat " #{sort_caret(current_direction)}" if current_attribute == attribute + # TODO: user tooltip ? + concat tag.span class: class_names("bi bi-#{caret}", + "ms-2": direction == :asc, + "link-primary": is_current_direction && is_current_attribute), + title: direction, + data: { controller: "tooltip" } end end - def sort_caret(direction) - sanitize(direction == :desc ? "↓" : "↑") - end - def displayed_columns @displayed_columns ||= if @columns_to_display.nil? columns diff --git a/app/components/list/table_component.rb b/app/components/list/table_component.rb index be977443b..8660d3926 100644 --- a/app/components/list/table_component.rb +++ b/app/components/list/table_component.rb @@ -3,7 +3,7 @@ module List class TableComponent < ApplicationComponent erb_template <<~ERB -
+
<%= tag.table(**@html_attributes) do %> <% heads.each do |thead| %> <%= thead %> @@ -28,7 +28,7 @@ def initialize(**html_attributes) css_classes = html_attributes.delete(:class) @html_attributes = html_attributes.merge( - class: class_names("table table-striped table-bordered table-hover mb-0", css_classes), + class: class_names("table table-striped mb-0 table-hover p-4", css_classes), ) end @@ -53,7 +53,7 @@ def call class TableHead < TableTag TAG_NAME = :thead - CSS_CLASSES = "" + CSS_CLASSES = "text-nowrap text-uppercase" end class TableBody < TableTag @@ -67,7 +67,7 @@ class TableFoot < TableTag class TableRow < TableTag TAG_NAME = :tr - CSS_CLASSES = "" # FIXME: should be applied only on body + CSS_CLASSES = "" end class TableCell < TableTag @@ -85,6 +85,7 @@ class TableCell < TableTag center: "text-center", right: "text-end", }.freeze + CSS_CLASSES = "border-dashed" def initialize(text = nil, **html_attributes) super(**html_attributes) @@ -96,9 +97,11 @@ def initialize(text = nil, **html_attributes) css_text_align = TEXT_ALIGN_TYPES[html_attributes.delete(:text_align)&.to_sym || :left] @html_attributes = html_attributes.merge( + scope: "col", class: class_names( css_vertical_align, css_text_align, + self.class::CSS_CLASSES, css_classes, ), ) @@ -113,7 +116,7 @@ def content class TableHeadCell < TableCell TAG_NAME = :th - CSS_CLASSES = "" + CSS_CLASSES = "fw-light text-secondary-emphasis all-small-caps bg-body-tertiary border-bottom" end end end diff --git a/app/decorators/room_decorator.rb b/app/decorators/room_decorator.rb index 4e2c26b31..953d8044b 100644 --- a/app/decorators/room_decorator.rb +++ b/app/decorators/room_decorator.rb @@ -40,6 +40,12 @@ def status_to_badge_component BadgeComponent.new(text, color:, variant: :pill) end + def display_on_room_to_badge_component + color = display_on_home_page ? :success : :danger + + BadgeComponent.new(I18n.t("boolean.#{display_on_home_page}"), color:, variant: :pill) + end + def access_control_to_human return I18n.t("access_control.blank") unless (a_c = access_control.presence) diff --git a/app/views/rooms/index.html.erb b/app/views/rooms/index.html.erb index 2c1194b55..eac787679 100644 --- a/app/views/rooms/index.html.erb +++ b/app/views/rooms/index.html.erb @@ -15,7 +15,10 @@
<%= render FilterComponent.new(@filter) do |c| %> <% c.with_form do |f| %> -
+
+ + +
<%= f.text_field :q, class: "form-control", placeholder: t("filters.placeholder.search") %> <%= f.label :q %> @@ -47,7 +50,7 @@ <% end %> <% table.with_column(Room.human_attribute_name(:name), sort_by: :name) do |room| %> - <%= link_to room, room_path(room), data: { turbo_frame: :_top } %> + <%= link_to room, room_path(room), class: "fw-semibold", data: { turbo_frame: :_top } %> <% end %> <% unless (turbo_frame_request? && @filter.filled?(:site_ids)) %> @@ -56,26 +59,30 @@ <% end %> <% end %> - <% table.with_column(Room.human_attribute_name(:position), sort_by: :position) do |room| %> + <% table.with_column(Room.human_attribute_name(:position), sort_by: :position, text_align: :right) do |room| %> <%= room.position %> <% end %> - <% table.with_column(Islet.model_name.human.pluralize, sort_by: :islets_count) do |room| %> + <% table.with_column(Islet.model_name.human.pluralize, sort_by: :islets_count, text_align: :right) do |room| %> + <%# table.with_column(Islet.model_name.human.pluralize, sort_by: :islets_count) do |room| # %> <%= link_to islets_path(room_ids: room.id), data: { turbo_frame: :_top } do %> - <%= Room.human_attribute_name(:islets_count, count: room.islets_count) %> + <%#= Room.human_attribute_name(:islets_count, count: room.islets_count) %> + <%= room.islets_count %> <% end %> <% end %> - <% table.with_column(Frame.model_name.human.pluralize) do |room| %> + <% table.with_column(Frame.model_name.human.pluralize, text_align: :right) do |room| %> + <%# table.with_column(Frame.model_name.human.pluralize) do |room| %> <%= link_to frames_path(room_ids: room.id), data: { turbo_frame: :_top } do %> - <%= Room.human_attribute_name(:frames_count, count: authorized_scope(room.frames).count) %> + <%#= Room.human_attribute_name(:frames_count, count: authorized_scope(room.frames).count) %> + <%= authorized_scope(room.frames).count %> <% end %> <% end %> - <% table.with_column(Room.human_attribute_name(:display_on_home_page), + <% table.with_column(Room.human_attribute_name(:display_on_home_page_short), sort_by: :display_on_home_page, text_align: :center) do |room| %> - disabled> + <%= render room.decorated.display_on_room_to_badge_component %> <% end %> <% table.with_column(Room.human_attribute_name(:status), sort_by: :status) do |room| %> @@ -87,21 +94,21 @@ <%= render partial: "visualization/rooms/export_button", locals: { room: decorate(room) } %> <% if allowed_to?(:show?, room, with: Visualization::RoomPolicy) %> - <%= link_to visualization_room_path(room), class: "btn btn-primary", data: { turbo_frame: :_top } do %> + <%= link_to visualization_room_path(room), class: "btn btn-outline-primary", data: { turbo_frame: :_top } do %> <%= t("visualization.title") %> <% end %> <% end %> <% if allowed_to?(:update?, room) %> - <%= link_to edit_room_path(room), class: "btn btn-info", data: { turbo_frame: :_top } do %> + <%= link_to edit_room_path(room), class: "btn btn-outline-info", data: { turbo_frame: :_top } do %> <%= t("action.edit") %> <% end %> <% end %> <% if allowed_to?(:destroy?, room) %> - <%= link_to room, method: :delete, data: { turbo_frame: :_top }, class: "btn btn-danger" do %> + <%= link_to room, method: :delete, data: { turbo_frame: :_top }, class: "btn btn-outline-danger" do %> <%= t("action.delete") %> <% end %> diff --git a/app/views/rooms/show.html.erb b/app/views/rooms/show.html.erb index 4a537cb7b..6198cb3f9 100644 --- a/app/views/rooms/show.html.erb +++ b/app/views/rooms/show.html.erb @@ -79,7 +79,7 @@
<%= Room.human_attribute_name(:display_on_home_page) %>
- <%= t("boolean.#{@room.display_on_home_page}") %> + <%= render @room.decorated.display_on_room_to_badge_component %>
<%= Room.human_attribute_name(:status) %>
diff --git a/app/views/sites/index.html.erb b/app/views/sites/index.html.erb index a347991ed..8baaaedd6 100644 --- a/app/views/sites/index.html.erb +++ b/app/views/sites/index.html.erb @@ -44,14 +44,14 @@ <% table.with_column(style: "min-width: 70px; width: 70px") do |site| %>
<% if allowed_to?(:update?, site) %> - <%= link_to edit_site_path(site), class: "btn btn-info" do %> + <%= link_to edit_site_path(site), class: "btn btn-outline-info" do %> <%= t("action.edit") %> <% end %> <% end %> <% if allowed_to?(:destroy?, site) %> - <%= link_to site, method: :delete, class: "btn btn-danger" do %> + <%= link_to site, method: :delete, class: "btn btn-outline-danger" do %> <%= t("action.delete") %> <% end %> diff --git a/config/locales/activerecord.fr.yml b/config/locales/activerecord.fr.yml index 99d355b1e..a83d2060e 100644 --- a/config/locales/activerecord.fr.yml +++ b/config/locales/activerecord.fr.yml @@ -61,7 +61,8 @@ fr: name: Nom position: Position content: Contenu - display_on_home_page: Afficher sur la page d'accueil + display_on_home_page: Afficher sur l'accueil + display_on_home_page_short: Sur l'accueil ? site_id: Site status: Statut surface_area: Superficie