diff --git a/Gemfile.lock b/Gemfile.lock index 91da8a5b6..16dca130d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -359,7 +359,7 @@ GEM logger (~> 1.6) letter_opener (1.10.0) launchy (>= 2.2, < 4) - lexxy (0.1.9.beta) + lexxy (0.1.10.beta) rails (>= 8.0.2) lint_roller (1.1.0) logger (1.7.0) diff --git a/app/assets/stylesheets/card-columns.css b/app/assets/stylesheets/card-columns.css index b6753394e..f4ff6ac05 100644 --- a/app/assets/stylesheets/card-columns.css +++ b/app/assets/stylesheets/card-columns.css @@ -73,7 +73,7 @@ z-index: 3; } - &:not(.cards--considering, .is-collapsed) { + &:not(.cards--considering, .is-collapsed, .cards--grid) { overflow: clip; } diff --git a/app/assets/stylesheets/lexxy.css b/app/assets/stylesheets/lexxy.css index f2dd41d2e..63f5f1f14 100644 --- a/app/assets/stylesheets/lexxy.css +++ b/app/assets/stylesheets/lexxy.css @@ -31,12 +31,6 @@ position: absolute; white-space: pre-line; } - - /* Disable the submit button when Lexical is empty */ - + .comment__submit { - opacity: 0.5; - pointer-events: none; - } } } @@ -178,11 +172,12 @@ border: 1px solid var(--color-ink-lighter); border-radius: 0.3em; color: var(--color-ink); - font-family: var(--font-mono); + font-family: var(--font-base); font-size: var(--text-x-small); font-weight: 500; + inset-inline-end: 0; line-height: inherit; - margin: 0.3em 0.3em 0 -0.3em; + margin: 0.3em 0.3em 0 0; padding: 0.5em 1.8em 0.5em 1.2em; text-align: start; diff --git a/app/assets/stylesheets/rich-text-content.css b/app/assets/stylesheets/rich-text-content.css index f73affd41..18641da1a 100644 --- a/app/assets/stylesheets/rich-text-content.css +++ b/app/assets/stylesheets/rich-text-content.css @@ -178,7 +178,7 @@ } .attachment__caption { - color: var(--color-ink-dark); + color: color-mix(in oklch, var(--color-ink) 66%, transparent); font-size: var(--text-small); .input { diff --git a/app/assets/stylesheets/trays.css b/app/assets/stylesheets/trays.css index 179ac73d4..b024a0412 100644 --- a/app/assets/stylesheets/trays.css +++ b/app/assets/stylesheets/trays.css @@ -345,7 +345,30 @@ } } - &:nth-child(1n + 11) { display: none; } + /* Show 6 max items on smallest devices */ + @media (max-height: 578px) { + &:nth-child(1n + 7) { display: none; } + } + + /* 7 max */ + @media (min-height: 578px) and (max-height: 656px) { + &:nth-child(1n + 8) { display: none; } + } + + /* 8 max */ + @media (min-height: 656px) and (max-height: 734px) { + &:nth-child(1n + 9) { display: none; } + } + + /* 9 max */ + @media (min-height: 734px) and (max-height: 812px) { + &:nth-child(1n + 10) { display: none; } + } + + /* 10 max on larger screens */ + @media (min-height: 812px) { + &:nth-child(1n + 11) { display: none; } + } &:not([aria-selected]) .card__link:focus-visible, .tray__dialog:not([open]) & .card__link:focus-visible { diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index 809428f91..526806879 100644 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -27,7 +27,9 @@ class CardsController < ApplicationController end def update - @card.update! card_params + suppressing_broadcasts_unless_published(@card) do + @card.update! card_params + end if @card.published? render_card_replacement @@ -50,6 +52,14 @@ class CardsController < ApplicationController @card = Current.user.accessible_cards.find params[:id] end + def suppressing_broadcasts_unless_published(card, &block) + if card.published? + yield + else + Collection.suppressing_turbo_broadcasts(&block) + end + end + def card_params params.expect(card: [ :status, :title, :description, :image, tag_ids: [] ]) end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d066632bd..11b793b17 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -24,7 +24,7 @@ class UsersController < ApplicationController def show @filter = Current.user.filters.new(creator_ids: [ @user.id ]) - @day_timeline = Current.user.timeline_for(Time.current, filter: @filter) + @day_timeline = Current.user.timeline_for(day_param, filter: @filter) end def update @@ -50,6 +50,14 @@ class UsersController < ApplicationController head :forbidden unless Current.user.can_change?(@user) end + def day_param + if params[:day].present? + Time.zone.parse(params[:day]) + else + Time.current + end + end + def user_params params.expect(user: [ :name, :email_address, :password, :avatar ]) end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 0eecdb25f..9200f84b7 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -52,17 +52,6 @@ module EventsHelper tag.div class: "events__time-block", style: "grid-area: #{row}/#{col}", & end - def event_next_page_link(next_day) - if next_day - tag.div id: "next_page", - data: { controller: "fetch-on-visible", - fetch_on_visible_url_value: events_days_path( - day: next_day.strftime("%Y-%m-%d"), - **@filter.as_params - ) } - end - end - def event_action_sentence(event) if event.action.comment_created? comment_event_action_sentence(event) diff --git a/app/helpers/pagination_helper.rb b/app/helpers/pagination_helper.rb index 8f2fc7988..ee665e98a 100644 --- a/app/helpers/pagination_helper.rb +++ b/app/helpers/pagination_helper.rb @@ -35,6 +35,30 @@ module PaginationHelper end end + def with_automatic_pagination(name, page, **properties) + pagination_list name, paginate_on_scroll: true, **properties do + concat(pagination_frame_tag(name, page) do + yield + concat link_to_next_page(name, page, activate_when_observed: true) + end) + end + end + + def day_timeline_pagination_frame_tag(day_timeline, &) + turbo_frame_tag day_timeline_pagination_frame_id_for(day_timeline.day), data: { timeline_target: "frame" }, role: "presentation", refresh: :morph, & + end + + def day_timeline_pagination_frame_id_for(day) + "day-timeline-pagination-contents-#{day.strftime("%Y-%m-%d")}" + end + + def day_timeline_pagination_link(day_timeline, filter) + if day_timeline.next_day + link_to "Load more...", events_days_path(day: day_timeline.next_day.strftime("%Y-%m-%d"), **filter.as_params), + data: { frame: day_timeline_pagination_frame_id_for(day_timeline.next_day), pagination_target: "paginationLink" } + end + end + private def pagination_list(name, tag_element: :div, paginate_on_scroll: false, **properties, &block) classes = properties.delete(:class) diff --git a/app/javascript/controllers/collapsible_columns_controller.js b/app/javascript/controllers/collapsible_columns_controller.js index 84ef0d315..5002c46e2 100644 --- a/app/javascript/controllers/collapsible_columns_controller.js +++ b/app/javascript/controllers/collapsible_columns_controller.js @@ -14,7 +14,7 @@ export default class extends Controller { } preventToggle(event) { - if (event.detail.attributeName === "class") { + if (event.target.hasAttribute("data-collapsible-columns-target") && event.detail.attributeName === "class") { event.preventDefault() } } diff --git a/app/javascript/controllers/form_controller.js b/app/javascript/controllers/form_controller.js index 4e59f6055..2b30c99b9 100644 --- a/app/javascript/controllers/form_controller.js +++ b/app/javascript/controllers/form_controller.js @@ -1,8 +1,8 @@ import { Controller } from "@hotwired/stimulus" -import { debounce } from "helpers/timing_helpers"; +import { debounce, nextFrame } from "helpers/timing_helpers"; export default class extends Controller { - static targets = [ "cancel" ] + static targets = [ "cancel", "submit" ] static values = { debounceTimeout: { type: Number, default: 300 } @@ -37,6 +37,16 @@ export default class extends Controller { event.preventDefault() } + async disableSubmitWhenInvalid(event) { + await nextFrame() + + if (this.element.checkValidity()) { + this.submitTarget.removeAttribute("disabled") + } else { + this.submitTarget.toggleAttribute("disabled", true) + } + } + select(event) { event.target.select() } diff --git a/app/views/cards/comments/_new.html.erb b/app/views/cards/comments/_new.html.erb index 7931cd244..015c93a83 100644 --- a/app/views/cards/comments/_new.html.erb +++ b/app/views/cards/comments/_new.html.erb @@ -10,10 +10,10 @@ local_save_key_value: "comment-#{card.id}", action: "turbo:submit-end->local-save#submit keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop" } do |form| %> <%= form.rich_textarea :body, required: true, placeholder: new_comment_placeholder(card), - data: { local_save_target: "input", action: "lexxy:change->local-save#save turbo:morph-element->local-save#restoreContent" } do %> + data: { local_save_target: "input", action: "lexxy:change->form#disableSubmitWhenInvalid lexxy:change->local-save#save turbo:morph-element->local-save#restoreContent" } do %> <%= general_prompts(@card.collection) %> <% end %> - <%= form.button class: "comment__submit btn btn--reversed flex-item-justify-start" do %> + <%= form.button class: "comment__submit btn btn--reversed flex-item-justify-start", data: { form_target: "submit" }, disabled: true do %> Post this comment <% end %> diff --git a/app/views/cards/index.html.erb b/app/views/cards/index.html.erb index 1e457c452..47d15dcb8 100644 --- a/app/views/cards/index.html.erb +++ b/app/views/cards/index.html.erb @@ -27,6 +27,8 @@ <%= turbo_frame_tag :cards_container do %>
- <%= render partial: "cards/display/preview", collection: @page.records, as: :card, locals: { draggable: true }, cached: ->(card) { cacheable_preview_parts_for(card) } %> + <%= with_automatic_pagination :cards_paginated_container, @page do %> + <%= render partial: "cards/display/preview", collection: @page.records, as: :card, locals: { draggable: true }, cached: ->(card) { cacheable_preview_parts_for(card) } %> + <% end %>
<% end %> diff --git a/app/views/collections/edit.html.erb b/app/views/collections/edit.html.erb index b6b0efe6c..f565cc972 100644 --- a/app/views/collections/edit.html.erb +++ b/app/views/collections/edit.html.erb @@ -3,7 +3,7 @@ <% content_for :header do %> <%= render "filters/menu", user_filtering: @user_filtering %>
- <%= link_to cards_path(collection_ids: [ @collection ]), class: "btn borderless txt-medium", data: { controller: "hotkey", action: "keydown.esc@document->hotkey#click" } do %> + <%= link_to @collection, class: "btn borderless txt-medium", data: { controller: "hotkey", action: "keydown.esc@document->hotkey#click" } do %> <%= @collection.name %> @@ -38,7 +38,6 @@
- <%# render "collections/edit/workflows", collection: @collection %> <%= render "collections/edit/auto_close", collection: @collection %> <%= render "collections/edit/publication", collection: @collection %> <%= render "collections/edit/delete", collection: @collection %> diff --git a/app/views/collections/show.html.erb b/app/views/collections/show.html.erb index ac7343885..96392f1d2 100644 --- a/app/views/collections/show.html.erb +++ b/app/views/collections/show.html.erb @@ -1,6 +1,8 @@ <% @page_title = @collection.name %> <% turbo_exempts_page_from_cache %> +<%= turbo_stream_from @collection %> + <% content_for :head do %> <%= tag.meta property: "og:title", content: @page_title %> <%= tag.meta property: "og:description", content: Account.sole.name %> diff --git a/app/views/collections/show/menu/_column.html.erb b/app/views/collections/show/menu/_column.html.erb index 22d249126..fd0894fc8 100644 --- a/app/views/collections/show/menu/_column.html.erb +++ b/app/views/collections/show/menu/_column.html.erb @@ -1,4 +1,4 @@ -
+
diff --git a/app/views/events/days/index.html.erb b/app/views/events/days/index.html.erb new file mode 100644 index 000000000..9529e8018 --- /dev/null +++ b/app/views/events/days/index.html.erb @@ -0,0 +1,4 @@ +<%= day_timeline_pagination_frame_tag @day_timeline do %> + <%= render "events/day", day_timeline: @day_timeline %> + <%= day_timeline_pagination_link(@day_timeline, @filter) %> +<% end %> diff --git a/app/views/events/days/index.turbo_stream.erb b/app/views/events/days/index.turbo_stream.erb deleted file mode 100644 index cceb2d352..000000000 --- a/app/views/events/days/index.turbo_stream.erb +++ /dev/null @@ -1,7 +0,0 @@ -<%= turbo_stream.append :activity do %> - <%= render "events/day", day_timeline: @day_timeline %> -<% end %> - -<%= turbo_stream.replace :next_page do %> - <%= event_next_page_link(@day_timeline.next_day) %> -<% end %> diff --git a/app/views/events/index.html.erb b/app/views/events/index.html.erb index 8dbd02eac..8acc92214 100644 --- a/app/views/events/index.html.erb +++ b/app/views/events/index.html.erb @@ -1,7 +1,7 @@ <% @page_title = "Home" %> <% @header_class = "header--events" %> -<%= turbo_stream_from :activity_summaries %> +<%= render "filters/broadcasts", filter: @filter %> <% content_for :header do %> <%= render "filters/menu", user_filtering: @user_filtering %> @@ -13,9 +13,10 @@ <% end %> -
- <%= turbo_frame_tag :events_container do %> +<%= tag.div id: "activity", class: "events", data: { controller: "pagination", pagination_paginate_on_intersection_value: true } do %> + <%= day_timeline_pagination_frame_tag @day_timeline do %> <%= render "events/day", day_timeline: @day_timeline %> + + <%= day_timeline_pagination_link(@day_timeline, @filter) %> <% end %> -
-<%= event_next_page_link(@day_timeline.next_day) %> +<% end %> diff --git a/app/views/filters/_menu.html.erb b/app/views/filters/_menu.html.erb index 7b84cdd60..a117bdfa7 100644 --- a/app/views/filters/_menu.html.erb +++ b/app/views/filters/_menu.html.erb @@ -1,4 +1,4 @@ -