Merge branch 'main' into collections-filter
* main: (24 commits) Move load-balancer to fizzy-lb-101 Add otel_collector accessory for load balancer Fix: this was getting idiomorph confused as it was being invoked on many subtree elements Keep column popups during page refreshes Don't render next link unless there is more activity Live updates for the collection perma Keep filter panel during page refreshes Add pagination to the list of filtered cards Use frame based pagination for the users timeline too Use frame-based pagination for the activity timeline Don't broadcast updates of cards unless published Live updates for the timeline Make permanent to avoid losing menu on page refreshes Use the new required attribute that now Lexxy supports Use controller to disable empty comment submit Dynamic height for pins based on viewport height Position lexxy language picker Replace old link with proper collection path No longer needed Prevent card bubbles getting clipped in grid layout ...
This commit is contained in:
+1
-1
@@ -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)
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
&:not(.cards--considering, .is-collapsed) {
|
||||
&:not(.cards--considering, .is-collapsed, .cards--grid) {
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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 %>
|
||||
<span>Post this comment</span>
|
||||
<% end %>
|
||||
<span data-form-target="cancel" hidden></span>
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
<%= turbo_frame_tag :cards_container do %>
|
||||
<section class="cards cards--grid">
|
||||
<%= 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 %>
|
||||
</section>
|
||||
<% end %>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<% content_for :header do %>
|
||||
<%= render "filters/menu", user_filtering: @user_filtering %>
|
||||
<div class="header__actions header__actions--start">
|
||||
<%= 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 %>
|
||||
<span class="overflow-ellipsis">
|
||||
←
|
||||
<strong><%= @collection.name %></strong>
|
||||
@@ -38,7 +38,6 @@
|
||||
</div>
|
||||
|
||||
<div class="settings__panel panel shadow center">
|
||||
<%# 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 %>
|
||||
|
||||
@@ -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 %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="cards__expander-menu" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
||||
<div class="cards__expander-menu" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside" data-turbo-permanent>
|
||||
<button class="btn btn--circle txt-x-small borderless" data-action="click->dialog#open">
|
||||
<%= icon_tag "menu-dots-horizontal", class: "translucent" %>
|
||||
<span class="for-screen-reader">Column options</span>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
||||
<div class="position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside" data-turbo-permanent>
|
||||
<button class="btn btn--circle txt-x-small borderless" data-action="click->dialog#open:stop" aria-label="Add a new column, etc.">
|
||||
<%= icon_tag "add", class: "translucent", "aria-hidden": true %>
|
||||
</button>
|
||||
|
||||
@@ -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 %>
|
||||
@@ -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 %>
|
||||
@@ -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 @@
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
<div class="events" id="activity">
|
||||
<%= 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 %>
|
||||
</div>
|
||||
<%= event_next_page_link(@day_timeline.next_day) %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<nav data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
||||
<nav data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside" data-turbo-permanent>
|
||||
<%= render "filters/menu/button" %>
|
||||
|
||||
<%= tag.dialog class: "fizzy-menu filter popup popup--animated panel margin-block-start-half",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% cache user_filtering do %>
|
||||
<%= tag.aside id: "filter-settings",
|
||||
<%= tag.aside \
|
||||
class: class_names("filters flex align-center gap-half justify-center center margin-block-end", { "filters--expanded": user_filtering.expanded? }),
|
||||
data: {
|
||||
controller: "toggle-class filter-settings",
|
||||
@@ -7,7 +7,8 @@
|
||||
filter_settings_filters_set_class: "filters--has-filters-set",
|
||||
filter_settings_no_filtering_url_value: no_filtering_url,
|
||||
filter_settings_refresh_url_value: settings_refresh_path,
|
||||
filter_settings_cards_url_value: cards_path } do %>
|
||||
filter_settings_cards_url_value: cards_path,
|
||||
turbo_permanent: true do %>
|
||||
<%= form_with url: filter_url, method: :get, class: "", data: {
|
||||
controller: "form",
|
||||
turbo_frame: "cards_container",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<%= tag.button class:"fizzy-menu-trigger input input--select center flex-inline align-center txt-normal",
|
||||
data: {
|
||||
action: "click->dialog#open:stop keydown.meta+j@document->hotkey#click keydown.ctrl+j@document->hotkey#click",
|
||||
action: "click->dialog#open:stop keydown.j@document->hotkey#click keydown.meta+j@document->hotkey#click keydown.ctrl+j@document->hotkey#click",
|
||||
controller: "hotkey" } do %>
|
||||
<svg fill="none" height="282" viewBox="0 0 178 282" width="178" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<path d="m14.1582 85.2218s66.3075-9.7823 75.9322-9.7823c9.6242 0 73.9516 9.7823 73.9516 9.7823-6.535 65.4602-17.171 132.0422-21.661 160.5982 0 0-16.941 11.257-51.3278 11.257s-55.9319-12.654-55.9319-12.654c-4.4901-28.557-14.4184-93.741-20.9631-159.2012z" fill="#d2edf8"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% if platform.desktop? %>
|
||||
<footer class="popup__footer">
|
||||
Press <kbd class="kbd"><%= hotkey_label(["ctrl", "J"]) -%></kbd> anytime to open this, <kbd class="kbd">esc</kbd> to close, <span class="txt-nowrap"><kbd class="kbd">↑</kbd><kbd class="kbd">↓</kbd> to move,</span> <kbd class="kbd">enter</kbd> to navigate.
|
||||
Press <kbd class="kbd">J</kbd> anytime to open this, <kbd class="kbd">esc</kbd> to close, <kbd class="kbd">↑</kbd><kbd class="kbd">↓</kbd> to move, <kbd class="kbd">enter</kbd> to navigate.
|
||||
</footer>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<div class="events margin-block-double" id="activity" data-controller="pagination" data-pagination-paginate-on-intersection-value="true">
|
||||
<%= day_timeline_pagination_frame_tag day_timeline do %>
|
||||
<%= render "events/day", day_timeline: day_timeline %>
|
||||
|
||||
<% if day_timeline.next_day %>
|
||||
<%= link_to "Load more...", user_path(user, 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 %>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,4 @@
|
||||
|
||||
<h1 class="font-weight-black txt-large margin-block-double"><%= "What #{ Current.user == @user ? "have you" : "has #{ @user.first_name }" } been up to?" %></h1>
|
||||
|
||||
<div class="events margin-block-double" id="activity">
|
||||
<%= render "events/day", day_timeline: @day_timeline %>
|
||||
</div>
|
||||
<%= event_next_page_link(@day_timeline.next_day) %>
|
||||
<%= render "users/activity_timeline", user: @user, day_timeline: @day_timeline, filter: @filter %>
|
||||
|
||||
+12
-2
@@ -39,11 +39,21 @@ accessories:
|
||||
|
||||
load-balancer:
|
||||
image: basecamp/kamal-proxy:lb
|
||||
roles:
|
||||
- web
|
||||
host: fizzy-beta-lb-01
|
||||
options:
|
||||
publish:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- load-balancer:/home/kamal-proxy/.config/kamal-proxy
|
||||
|
||||
otel_collector-load-balancer:
|
||||
image: otel/opentelemetry-collector-contrib:0.126.0
|
||||
port: 9394
|
||||
files:
|
||||
- config/otel_collector.yml:/etc/otelcol-contrib/config.yaml
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
options:
|
||||
user: 0
|
||||
host: fizzy-beta-lb-01
|
||||
|
||||
@@ -39,11 +39,21 @@ accessories:
|
||||
|
||||
load-balancer:
|
||||
image: basecamp/kamal-proxy:lb
|
||||
roles:
|
||||
- web
|
||||
host: fizzy-lb-101
|
||||
options:
|
||||
publish:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- load-balancer:/home/kamal-proxy/.config/kamal-proxy
|
||||
|
||||
otel_collector-load-balancer:
|
||||
image: otel/opentelemetry-collector-contrib:0.126.0
|
||||
port: 9394
|
||||
files:
|
||||
- config/otel_collector.yml:/etc/otelcol-contrib/config.yaml
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
options:
|
||||
user: 0
|
||||
host: fizzy-lb-101
|
||||
|
||||
@@ -39,11 +39,21 @@ accessories:
|
||||
|
||||
load-balancer:
|
||||
image: basecamp/kamal-proxy:lb
|
||||
roles:
|
||||
- web
|
||||
host: fizzy-staging-lb-01
|
||||
options:
|
||||
publish:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- load-balancer:/home/kamal-proxy/.config/kamal-proxy
|
||||
|
||||
otel_collector-load-balancer:
|
||||
image: otel/opentelemetry-collector-contrib:0.126.0
|
||||
port: 9394
|
||||
files:
|
||||
- config/otel_collector.yml:/etc/otelcol-contrib/config.yaml
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
options:
|
||||
user: 0
|
||||
host: fizzy-staging-lb-01
|
||||
|
||||
Reference in New Issue
Block a user