Merge branch 'main' into cascade-layers

* main:
  Fix merge issues
  Reload stages with morphing too
  Make frames reload compatible with page refreshes to avoid flickering
  Persist terminal turbo frame across navigations
  Enable page refreshes with morphing
  Rework the flow for closing and moving between columns
This commit is contained in:
Andy Smith
2025-04-03 11:35:58 -05:00
10 changed files with 125 additions and 44 deletions
+11 -3
View File
@@ -107,7 +107,11 @@
position: relative;
z-index: 0;
.btn {
&:has(dialog[open]) {
z-index: 1;
}
.btn:not(.popup__item, .btn--plain) {
--btn-background: var(--bubble-color);
--btn-color: var(--color-ink-reversed);
}
@@ -356,6 +360,10 @@
}
}
.card__move-button {
--btn-background: color-mix(in srgb, var(--bubble-color) 40%, var(--color-ink));
}
.card__stages {
flex: 1 1 25%;
}
@@ -450,9 +458,9 @@
font-size: var(--text-rel-large);
font-weight: 900;
text-shadow:
-2px -2px 0 var(--bubble-color),
-2px -2px 0 var(--bubble-color),
2px -2px 0 var(--bubble-color),
-2px 2px 0 var(--bubble-color),
-2px 2px 0 var(--bubble-color),
2px 2px 0 var(--bubble-color);
}
}
@@ -2,7 +2,11 @@ class Bubbles::StagingsController < ApplicationController
include BubbleScoped, BucketScoped
def create
@bubble.toggle_stage Current.account.stages.find(params[:stage_id])
if params[:stage_id].present?
@bubble.toggle_stage Current.account.stages.find(params[:stage_id])
else
@bubble.update!(stage: nil)
end
redirect_to @bubble
end
end
@@ -1,5 +1,5 @@
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 = ["input"]
@@ -10,7 +10,7 @@ export default class extends Controller {
}
connect() {
this.#restoreContent()
this.restoreContent()
}
submit({ detail: { success } }) {
@@ -28,20 +28,22 @@ export default class extends Controller {
}
}
// Private
#clear() {
localStorage.removeItem(this.keyValue)
}
#restoreContent() {
async restoreContent() {
await nextFrame()
const savedContent = localStorage.getItem(this.keyValue)
if (savedContent) {
this.inputTarget.value = savedContent
this.#triggerChangeEvent(savedContent)
}
}
// Private
#clear() {
localStorage.removeItem(this.keyValue)
}
#triggerChangeEvent(newValue) {
if (this.inputTarget.tagName === "HOUSE-MD") {
this.inputTarget.dispatchEvent(new CustomEvent('house-md:change', {
+8 -1
View File
@@ -30,7 +30,14 @@
<% end %>
</div>
<%= turbo_frame_tag dom_id(bubble, :stage_picker), src: new_bucket_bubble_stage_picker_path(bubble.bucket, bubble) unless (previewing_card? && bubble.popped?) %>
<%= turbo_frame_tag dom_id(bubble, :stage_picker), src: new_bucket_bubble_stage_picker_path(bubble.bucket, bubble), refresh: :morph unless (previewing_card? && bubble.popped?) %>
<% if bubble.stage.nil? %>
<%= button_to bucket_bubble_stagings_path(bubble.bucket, bubble, stage_id: bubble.bucket&.workflow&.stages&.first), method: :post, class: "card__move-button card__hide-on-index btn btn--reversed" do %>
<span class="txt-nowrap">Move to Doing</span>
<%= icon_tag "arrow-right" %>
<% end %>
<% end %>
</div>
<footer class="card__footer full-width flex align-start gap">
+34 -4
View File
@@ -5,11 +5,41 @@
<span>Un-do</span>
<% end %>
<% else %>
<%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn borderless" do %>
<span>Mark as done</span>
<% end %>
<div class="flex-inline center position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn borderless" data-action="click->dialog#open:stop">
<span>Close as…</span>
</button>
<dialog class="popup panel flex-column align-start gap-half fill-white shadow" style="--row-gap: 0.2em;"
aria-label="In stage…" aria-description="In stage…"
data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">Close as…</strong>
<%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn popup__item full-width", form_class: "full-width" do %>
<span class="overflow-ellipsis">Completed</span>
<% end %>
<%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn popup__item full-width", form_class: "full-width" do %>
<span class="overflow-ellipsis">Duplicate</span>
<% end %>
<%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn popup__item full-width", form_class: "full-width" do %>
<span class="overflow-ellipsis">Maybe later</span>
<% end %>
<%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn popup__item full-width", form_class: "full-width" do %>
<span class="overflow-ellipsis">Working as intended</span>
<% end %>
<% if bubble.stage.present? %>
<%= button_to bucket_bubble_stagings_path(bubble.bucket, bubble, stage_id: ""), method: :post, class: "btn popup__item full-width" do %>
<span class="overflow-ellipsis">Move back to Considering</span>
<% end %>
<% end %>
</dialog>
</div>
<span class="card__pop-message">
Auto-closes <%= local_datetime_tag(bubble.auto_pop_at, style: :indays) %>.
<% if bubble.stage.present? %>
Returns to <em>Considering</em> if no activity <%= local_datetime_tag(bubble.auto_pop_at, style: :indays) %>.
<% else %>
Auto-closes if no activity <%= local_datetime_tag(bubble.auto_pop_at, style: :indays) %>.
<% end %>
</span>
<% end %>
</div>
-1
View File
@@ -1,6 +1,5 @@
<% @page_title = @filter.summary %>
<% turbo_refreshes_with method: :morph, scroll: :preserve %>
<%= render "filters/broadcasts", filter: @filter %>
<% content_for :header do %>
+9 -22
View File
@@ -51,32 +51,19 @@
<% end %>
</div>
<% if @bubble.published? %>
<div class="card__actions card__actions--right flex flex-column gap-half">
<%= turbo_frame_tag dom_id(@bubble, :watch), src: bucket_bubble_watch_path(@bubble.bucket, @bubble) %>
<%= turbo_frame_tag dom_id(@bubble, :pin), src: bucket_bubble_pin_path(@bubble.bucket, @bubble) %>
<%= turbo_frame_tag dom_id(@bubble, :watch), src: bucket_bubble_watch_path(@bubble.bucket, @bubble), refresh: :morph %>
<%= turbo_frame_tag dom_id(@bubble, :pin), src: bucket_bubble_pin_path(@bubble.bucket, @bubble), refresh: :morph %>
</div>
<% end %>
</div>
<% unless @bubble.drafted? || @bubble.creating? %>
<% if @bubble.stage.present? %>
<div class="card__actions-wrapper">
<%= render "bubbles/pop_toggle", bubble: @bubble %>
</div>
<% else %>
<div class="card__actions-wrapper">
<div class="card__actions-container center border-radius flex-inline align-center justify-center gap" style="--bubble-color: <%= @bubble.color %>">
<%= button_to bucket_bubble_stagings_path(@bubble.bucket, @bubble, stage_id: @bubble.bucket&.workflow&.stages&.first), method: :post, class: "btn borderless" do %>
<span>Were doing this</span>
<% end %>
<%= button_to bucket_bubble_pop_path(@bubble.bucket, @bubble), class: "btn borderless" do %>
<span>Not now</span>
<% end %>
</div>
</div>
<% end %>
<div class="card__actions-wrapper">
<%= render "bubbles/pop_toggle", bubble: @bubble %>
</div>
<% end %>
<% if @bubble.published? %>
@@ -90,12 +77,12 @@
<div class="comment__content flex-inline flex-column full-width">
<div class="comment__body txt-align-start">
<form data-controller="outlet-auto-save paste"
<form data-controller="outlet-auto-save paste"
class="flex flex-column gap full-width"
data-outlet-auto-save-auto-save-outlet="#bubble_form"
data-action="paste->paste#pasteFiles">
<%= tag.house_md @bubble.draft_comment, name: "bubble[draft_comment]", class: "input comment__input",
form: "bubble_form",
<%= tag.house_md @bubble.draft_comment, name: "bubble[draft_comment]", class: "input comment__input",
form: "bubble_form",
placeholder: new_comment_placeholder(@bubble),
data: { action: "house-md:change->outlet-auto-save#change focusout->outlet-auto-save#submit", uploads_url: uploads_url(format: "json") } %>
</form>
+1 -1
View File
@@ -10,7 +10,7 @@
local_save_key_value: "comment-#{bubble.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 paste->paste#pasteFiles" } do |form| %>
<%= form.markdown_area :body, class: "input comment__input", required: true, placeholder: new_comment_placeholder(bubble),
data: { local_save_target: "input", action: "house-md:change->local-save#save" } %>
data: { local_save_target: "input", action: "house-md:change->local-save#save turbo:morph-element->local-save#restoreContent" } %>
<%= form.button class: "comment__submit btn btn--reversed flex-item-justify-start" do %>
<span>Post this comment</span>
<% end %>
+3 -1
View File
@@ -12,6 +12,8 @@
<%= csp_meta_tag %>
<%= tag.meta name: "current-user-id", content: Current.user.id if Current.user %>
<% turbo_refreshes_with method: :morph, scroll: :preserve %>
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
@@ -47,7 +49,7 @@
<% if Current.user %>
<%= render "notifications/tray" %>
<%= render "bubbles/pins/tray" %>
<%= turbo_frame_tag "terminal", src: terminal_path %>
<%= turbo_frame_tag "terminal", src: terminal_path, data: { turbo_permanent: true } %>
<% end %>
</footer>
+43 -1
View File
File diff suppressed because one or more lines are too long