Merge branch 'main' into modal-scroll-block
This commit is contained in:
+1
-1
@@ -449,7 +449,7 @@ GEM
|
||||
timeout (0.6.0)
|
||||
trilogy (2.9.0)
|
||||
tsort (0.2.0)
|
||||
turbo-rails (2.0.20)
|
||||
turbo-rails (2.0.21)
|
||||
actionpack (>= 7.1.0)
|
||||
railties (>= 7.1.0)
|
||||
tzinfo (2.0.6)
|
||||
|
||||
+1
-1
@@ -568,7 +568,7 @@ GEM
|
||||
timeout (0.6.0)
|
||||
trilogy (2.9.0)
|
||||
tsort (0.2.0)
|
||||
turbo-rails (2.0.20)
|
||||
turbo-rails (2.0.21)
|
||||
actionpack (>= 7.1.0)
|
||||
railties (>= 7.1.0)
|
||||
tzinfo (2.0.6)
|
||||
|
||||
@@ -281,10 +281,7 @@
|
||||
|
||||
/* Overlap the card BG by half the button height */
|
||||
&:has(.btn) {
|
||||
&,
|
||||
~ .card-perma__closure-message {
|
||||
translate: 0 calc(-1 * var(--half-btn-height));
|
||||
}
|
||||
translate: 0 calc(-1 * var(--half-btn-height));
|
||||
}
|
||||
|
||||
form {
|
||||
@@ -297,12 +294,6 @@
|
||||
--btn-color: var(--color-ink-inverted);
|
||||
}
|
||||
|
||||
.btn--plain {
|
||||
--btn-color: var(--card-color);
|
||||
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn--reversed {
|
||||
--btn-background: var(--color-canvas);
|
||||
--btn-color: var(--card-color);
|
||||
@@ -330,11 +321,25 @@
|
||||
.card-perma__closure-message {
|
||||
color: var(--card-color);
|
||||
grid-area: closure-message;
|
||||
margin-block-start: 0.5ch;
|
||||
margin-block: var(--block-space) var(--block-space-double);
|
||||
padding-inline: 1ch;
|
||||
|
||||
form {
|
||||
display: inline;
|
||||
.btn--plain {
|
||||
--btn-color: var(--card-color);
|
||||
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 799px) {
|
||||
margin-block: var(--block-space-half);
|
||||
translate: 0 calc(-0.5 * var(--half-btn-height));
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.card-perma__notch--bottom:has(.btn) ~ & {
|
||||
margin-block: var(--block-space-half) var(--block-space);
|
||||
translate: 0 calc(-0.5 * var(--half-btn-height));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
--custom-safe-inset-bottom: var(--injected-safe-inset-bottom, env(safe-area-inset-bottom, 0px));
|
||||
--custom-safe-inset-left: var(--injected-safe-inset-left, env(safe-area-inset-left, 0px));
|
||||
|
||||
--footer-height: 0;
|
||||
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
.hide-on-native {
|
||||
@@ -28,11 +30,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Card columns
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
.board-tools.card {
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
/* Card perma
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
.card-perma {
|
||||
margin-block-start: 0;
|
||||
|
||||
&:not(:has(.card-perma__notch-new-card-buttons)) .card-perma__bg {
|
||||
padding-block: clamp(0.25rem, 2vw, var(--padding-block));
|
||||
}
|
||||
}
|
||||
|
||||
.card-perma__closure-message {
|
||||
margin-block: var(--block-space);
|
||||
translate: unset;
|
||||
}
|
||||
|
||||
/* Search
|
||||
@@ -43,3 +61,25 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-bridge-components~=form] {
|
||||
[data-controller~=bridge--form] {
|
||||
[data-bridge--form-target~=submit] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-bridge-components~=overflow-menu] {
|
||||
[data-controller~=bridge--overflow-menu] {
|
||||
[data-bridge--overflow-menu-target~=item] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-bridge-components~=buttons] {
|
||||
[data-bridge--buttons-target~=button] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
.popup__title {
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
|
||||
&[tabindex="-1"]:focus-visible {
|
||||
outline: unset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide lists when all the items within are hidden */
|
||||
|
||||
@@ -48,7 +48,8 @@ module AccessesHelper
|
||||
params: { show_watchers: show_watchers, involvement: next_involvement(access.involvement), icon_only: icon_only },
|
||||
aria: { labelledby: dom_id(board, :involvement_label) },
|
||||
title: (label_text if icon_only),
|
||||
class: class_names("btn", { "btn--reversed": access.watching? && icon_only })) do
|
||||
class: class_names("btn", { "btn--reversed": access.watching? && icon_only }),
|
||||
data: !icon_only && { bridge__overflow_menu_target: "item", bridge_title: label_text }) do
|
||||
icon_tag("notification-bell-#{icon_only ? 'reverse-' : nil}#{access.involvement.dasherize}") +
|
||||
tag.span(label_text, class: class_names("txt-nowrap txt-uppercase", "for-screen-reader": icon_only), id: dom_id(board, :involvement_label))
|
||||
end
|
||||
|
||||
@@ -4,7 +4,8 @@ module BoardsHelper
|
||||
end
|
||||
|
||||
def link_to_edit_board(board)
|
||||
link_to edit_board_path(board), class: "btn", data: { controller: "tooltip" } do
|
||||
link_to edit_board_path(board), class: "btn",
|
||||
data: { controller: "tooltip", bridge__overflow_menu_target: "item", bridge_title: "Board settings" } do
|
||||
icon_tag("settings") + tag.span("Settings for #{board.name}", class: "for-screen-reader")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
module BridgeHelper
|
||||
def bridge_icon(name)
|
||||
asset_url("#{name}.svg")
|
||||
end
|
||||
end
|
||||
@@ -40,6 +40,10 @@ module FiltersHelper
|
||||
}, &block
|
||||
end
|
||||
|
||||
def filter_title(title)
|
||||
tag.strong title, class: "popup__title pad-inline-half", tabindex: "-1", data: { dialog_target: "focusTouch" }
|
||||
end
|
||||
|
||||
def collapsible_nav_section(title, **properties, &block)
|
||||
tag.details class: "nav__section popup__section", data: { action: "toggle->nav-section-expander#toggle", nav_section_expander_target: "section", nav_section_expander_key_value: title.parameterize }, open: true, **properties do
|
||||
concat(tag.summary(class: "popup__section-title") do
|
||||
|
||||
@@ -9,4 +9,23 @@ module FormsHelper
|
||||
form_with(**attributes, data: data) { }
|
||||
end
|
||||
end
|
||||
|
||||
def bridged_form_with(**attributes, &)
|
||||
data = attributes.delete(:data) || {}
|
||||
controllers = [ data[:controller], "bridge--form" ].compact.join(" ").strip
|
||||
actions = [
|
||||
data[:action],
|
||||
"turbo:submit-start->bridge--form#submitStart",
|
||||
"turbo:submit-end->bridge--form#submitEnd"
|
||||
].compact.join(" ").strip
|
||||
|
||||
data[:controller] = controllers
|
||||
data[:action] = actions
|
||||
|
||||
if block_given?
|
||||
form_with **attributes, data: data, &
|
||||
else
|
||||
form_with(**attributes, data: data) { }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ module WebhooksHelper
|
||||
def link_to_webhooks(board, &)
|
||||
link_to board_webhooks_path(board_id: board),
|
||||
class: [ "btn", { "btn--reversed": board.webhooks.any? } ],
|
||||
data: { controller: "tooltip" } do
|
||||
data: { controller: "tooltip", bridge__overflow_menu_target: "item", bridge_title: "Webhooks" } do
|
||||
icon_tag("world") + tag.span("Webhooks", class: "for-screen-reader")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
|
||||
import "@hotwired/turbo-rails"
|
||||
import "@hotwired/hotwire-native-bridge"
|
||||
import "initializers"
|
||||
import "controllers"
|
||||
|
||||
import "lexxy"
|
||||
import "@rails/actiontext"
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
||||
import { BridgeElement } from "@hotwired/hotwire-native-bridge"
|
||||
|
||||
export default class extends BridgeComponent {
|
||||
static component = "buttons"
|
||||
static targets = [ "button" ]
|
||||
|
||||
buttonTargetConnected() {
|
||||
this.notifyBridgeOfConnect()
|
||||
}
|
||||
|
||||
buttonTargetDisconnected() {
|
||||
if (!this.#isControllerTearingDown()) {
|
||||
this.notifyBridgeOfConnect()
|
||||
}
|
||||
}
|
||||
|
||||
notifyBridgeOfConnect() {
|
||||
const buttons = this.#enabledButtonTargets
|
||||
.map((target, index) => {
|
||||
const element = new BridgeElement(target)
|
||||
return { ...element.getButton(), index }
|
||||
})
|
||||
|
||||
this.send("connect", { buttons }, message => {
|
||||
this.#clickButton(message)
|
||||
})
|
||||
}
|
||||
|
||||
#clickButton(message) {
|
||||
const selectedIndex = message.data.selectedIndex
|
||||
this.#enabledButtonTargets[selectedIndex].click()
|
||||
}
|
||||
|
||||
get #enabledButtonTargets() {
|
||||
return this.buttonTargets
|
||||
.filter(target => !target.closest("[data-bridge-disabled]"))
|
||||
}
|
||||
|
||||
#isControllerTearingDown() {
|
||||
return !document.body.contains(this.element)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
||||
import { BridgeElement } from "@hotwired/hotwire-native-bridge"
|
||||
|
||||
export default class extends BridgeComponent {
|
||||
static component = "form"
|
||||
static targets = [ "submit", "cancel" ]
|
||||
static values = { submitTitle: String }
|
||||
|
||||
submitTargetConnected() {
|
||||
this.notifyBridgeOfConnect()
|
||||
this.#observeSubmitTarget()
|
||||
}
|
||||
|
||||
submitTargetDisconnected() {
|
||||
this.notifyBridgeOfDisonnect()
|
||||
this.submitObserver?.disconnect()
|
||||
}
|
||||
|
||||
notifyBridgeOfConnect() {
|
||||
const submitElement = new BridgeElement(this.submitTarget)
|
||||
const cancelElement = this.hasCancelTarget ? new BridgeElement(this.cancelTarget) : null
|
||||
|
||||
const submitButton = { title: submitElement.title }
|
||||
const cancelButton = cancelElement ? { title: cancelElement.title } : null
|
||||
|
||||
this.send("connect", { submitButton, cancelButton }, message => this.receive(message))
|
||||
}
|
||||
|
||||
receive(message) {
|
||||
switch (message.event) {
|
||||
case "submit":
|
||||
this.submitTarget.click()
|
||||
break
|
||||
case "cancel":
|
||||
this.cancelTarget.click()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
notifyBridgeOfDisonnect() {
|
||||
this.send("disconnect")
|
||||
}
|
||||
|
||||
submitStart() {
|
||||
this.send("submitStart")
|
||||
}
|
||||
|
||||
submitEnd() {
|
||||
this.send("submitEnd")
|
||||
}
|
||||
|
||||
#observeSubmitTarget() {
|
||||
this.submitObserver = new MutationObserver(() => {
|
||||
this.send(this.submitTarget.disabled ? "submitDisabled" : "submitEnabled")
|
||||
})
|
||||
|
||||
this.submitObserver.observe(this.submitTarget, {
|
||||
attributes: true,
|
||||
attributeFilter: [ "disabled" ]
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
||||
|
||||
// Bridge component to control custom safe-area insets from native apps.
|
||||
// Sets CSS variables --injected-safe-inset-(top|right|bottom|left).
|
||||
export default class extends BridgeComponent {
|
||||
static component = "insets"
|
||||
|
||||
connect() {
|
||||
super.connect()
|
||||
this.notifyBridgeOfConnect()
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
super.disconnect()
|
||||
this.send("disconnect")
|
||||
}
|
||||
|
||||
notifyBridgeOfConnect() {
|
||||
this.send("connect", {}, message => {
|
||||
this.#setInsets(message.data)
|
||||
})
|
||||
}
|
||||
|
||||
#setInsets({ top, right, bottom, left }) {
|
||||
const root = document.documentElement.style
|
||||
root.setProperty("--injected-safe-inset-top", `${top}px`)
|
||||
root.setProperty("--injected-safe-inset-right", `${right}px`)
|
||||
root.setProperty("--injected-safe-inset-bottom", `${bottom}px`)
|
||||
root.setProperty("--injected-safe-inset-left", `${left}px`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
||||
import { BridgeElement } from "@hotwired/hotwire-native-bridge"
|
||||
|
||||
export default class extends BridgeComponent {
|
||||
static component = "overflow-menu"
|
||||
static targets = [ "item" ]
|
||||
|
||||
itemTargetConnected() {
|
||||
this.notifyBridgeOfConnect()
|
||||
}
|
||||
|
||||
itemTargetDisconnected() {
|
||||
if (!this.#isControllerTearingDown) {
|
||||
this.notifyBridgeOfConnect()
|
||||
}
|
||||
}
|
||||
|
||||
notifyBridgeOfConnect() {
|
||||
const items = this.#enabledItemTargets
|
||||
.map((target, index) => {
|
||||
const element = new BridgeElement(target)
|
||||
return { title: element.title, index }
|
||||
})
|
||||
|
||||
this.send("connect", { items }, message => {
|
||||
this.#clickItem(message)
|
||||
})
|
||||
}
|
||||
|
||||
#clickItem(message) {
|
||||
const selectedIndex = message.data.selectedIndex
|
||||
this.#enabledItemTargets[selectedIndex].click()
|
||||
}
|
||||
|
||||
get #enabledItemTargets() {
|
||||
return this.itemTargets
|
||||
.filter(target => !target.closest("[data-bridge-disabled]"))
|
||||
}
|
||||
|
||||
#isControllerTearingDown() {
|
||||
return !document.body.contains(this.element)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
||||
|
||||
export default class extends BridgeComponent {
|
||||
static component = "text-size"
|
||||
|
||||
connect() {
|
||||
super.connect()
|
||||
this.notifyBridgeOfConnect()
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
super.disconnect()
|
||||
this.send("disconnect")
|
||||
}
|
||||
|
||||
notifyBridgeOfConnect() {
|
||||
this.send("connect", {}, message => {
|
||||
this.#setTextSize(message.data)
|
||||
})
|
||||
}
|
||||
|
||||
#setTextSize(data) {
|
||||
document.documentElement.dataset.textSize = data.textSize
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
||||
import { viewport } from "helpers/bridge/viewport_helpers"
|
||||
import { nextFrame } from "helpers/timing_helpers"
|
||||
|
||||
export default class extends BridgeComponent {
|
||||
static component = "title"
|
||||
static targets = [ "header" ]
|
||||
static values = { title: String }
|
||||
|
||||
async connect() {
|
||||
super.connect()
|
||||
await nextFrame()
|
||||
this.#startObserver()
|
||||
window.addEventListener("resize", this.#windowResized)
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
super.disconnect()
|
||||
this.#stopObserver()
|
||||
window.removeEventListener("resize", this.#windowResized)
|
||||
}
|
||||
|
||||
notifyBridgeOfVisibilityChange(visible) {
|
||||
this.send("visibility", { title: this.#title, elementVisible: visible })
|
||||
}
|
||||
|
||||
// Intersection Observer
|
||||
|
||||
#startObserver() {
|
||||
if (!this.hasHeaderTarget) return
|
||||
|
||||
this.observer = new IntersectionObserver(([ entry ]) =>
|
||||
this.notifyBridgeOfVisibilityChange(entry.isIntersecting),
|
||||
{ rootMargin: `-${this.#topOffset}px 0px 0px 0px` }
|
||||
)
|
||||
|
||||
this.observer.observe(this.headerTarget)
|
||||
this.previousTopOffset = this.#topOffset
|
||||
}
|
||||
|
||||
#stopObserver() {
|
||||
this.observer?.disconnect()
|
||||
}
|
||||
|
||||
#updateObserverIfNeeded() {
|
||||
if (this.#topOffset === this.previousTopOffset) return
|
||||
|
||||
this.#stopObserver()
|
||||
this.#startObserver()
|
||||
}
|
||||
|
||||
#windowResized = () => {
|
||||
this.#updateObserverIfNeeded()
|
||||
}
|
||||
|
||||
get #title() {
|
||||
return this.titleValue ? this.titleValue : document.title
|
||||
}
|
||||
|
||||
get #topOffset() {
|
||||
return viewport.top
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
import { orient } from "helpers/orientation_helpers"
|
||||
import { isTouchDevice } from "helpers/platform_helpers"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = [ "dialog" ]
|
||||
static targets = [ "dialog", "focusMouse", "focusTouch" ]
|
||||
static values = {
|
||||
modal: { type: Boolean, default: false },
|
||||
sizing: { type: Boolean, default: true },
|
||||
@@ -14,6 +15,10 @@ export default class extends Controller {
|
||||
if (this.autoOpenValue) this.open()
|
||||
}
|
||||
|
||||
focusTouchTargetConnected() {
|
||||
this.#setupFocus()
|
||||
}
|
||||
|
||||
open() {
|
||||
const modal = this.modalValue
|
||||
|
||||
@@ -63,4 +68,10 @@ export default class extends Controller {
|
||||
captureKey(event) {
|
||||
if (event.key !== "Escape") { event.stopPropagation() }
|
||||
}
|
||||
|
||||
#setupFocus() {
|
||||
const touch = isTouchDevice()
|
||||
if (this.hasFocusMouseTarget) this.focusMouseTarget.autofocus = !touch
|
||||
if (this.hasFocusTouchTarget) this.focusTouchTarget.autofocus = touch
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
let top = 0
|
||||
const viewportTarget = window.visualViewport || window
|
||||
|
||||
export const viewport = {
|
||||
get top() {
|
||||
return top
|
||||
},
|
||||
get height() {
|
||||
return viewportTarget.height || window.innerHeight
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
requestAnimationFrame(() => {
|
||||
const styles = getComputedStyle(document.documentElement)
|
||||
const customInset = styles.getPropertyValue("--custom-safe-inset-top")
|
||||
const fallbackInset = styles.getPropertyValue("--safe-area-inset-top")
|
||||
const insetValue = (customInset || fallbackInset).trim()
|
||||
top = parseInt(insetValue || "0", 10) || 0
|
||||
})
|
||||
}
|
||||
|
||||
viewportTarget.addEventListener("resize", update)
|
||||
update()
|
||||
@@ -0,0 +1,18 @@
|
||||
import { BridgeElement } from "@hotwired/hotwire-native-bridge"
|
||||
|
||||
BridgeElement.prototype.getButton = function() {
|
||||
return {
|
||||
title: this.title,
|
||||
icon: this.getIcon()
|
||||
}
|
||||
}
|
||||
|
||||
BridgeElement.prototype.getIcon = function() {
|
||||
const url = this.bridgeAttribute(`icon-url`)
|
||||
|
||||
if (url) {
|
||||
return { url }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
import "initializers/current"
|
||||
import "initializers/bridge/bridge_element"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<% @page_title = "Account Settings" %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<h1 class="header__title">
|
||||
<h1 class="header__title" data-bridge--title-target="header">
|
||||
<%= @page_title %>
|
||||
<% unless Current.user.admin? %>
|
||||
<div class="txt-normal font-weight-normal">Only admins can change these settings</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= link_back_to_board(@board) %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= link_back_to_board(@board) %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= link_back_to_board(@column.board) %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= link_back_to_board(@board) %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= link_back_to_board(@board) %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title">
|
||||
<h1 class="header__title" data-bridge--title-target="header">
|
||||
<div><%= @page_title %></div>
|
||||
<% unless Current.user.can_administer_board?(@board) %>
|
||||
<div class="txt-normal font-weight-normal">Only admins can change these settings</div>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<% @page_title = "Create a new board" %>
|
||||
|
||||
<div class="panel panel--centered">
|
||||
<%= form_with model: @board, class: "flex flex-column gap", data: { controller: "form", action: "submit->form#preventEmptySubmit" } do |form| %>
|
||||
<%= bridged_form_with model: @board, class: "flex flex-column gap", data: { controller: "form", action: "submit->form#preventEmptySubmit" } do |form| %>
|
||||
<h1 class="txt-x-large margin-none font-weight-black"><%= @page_title %></h1>
|
||||
<%= form.text_field :name, required: true, class: "input full-width", autofocus: true, autocomplete: "off", placeholder: "Name it…", data: { form_target: "input", action: "keydown.esc@document->form#cancel", validation_message: "Board names can‘t be blank" } %>
|
||||
|
||||
<button type="submit" class="btn btn--link center">
|
||||
<button type="submit" class="btn btn--link center" data-bridge--form-target="submit">
|
||||
<span>Create board</span>
|
||||
<%= icon_tag "arrow-right" %>
|
||||
</button>
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
<%= turbo_stream_from @board %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<div class="header__actions header__actions--start">
|
||||
<div class="header__actions header__actions--start hide-on-native">
|
||||
<%= link_to_webhooks(@board) if Current.user.admin? %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @board.name %></span>
|
||||
</h1>
|
||||
|
||||
<div class="header__actions header__actions--end">
|
||||
<div class="header__actions header__actions--end hide-on-native">
|
||||
<%= link_to_edit_board @board %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
<%= render "boards/show/expander", title: "Maybe?", count: board.cards.awaiting_triage.count, column_id: "maybe" %>
|
||||
<%= render "boards/show/menu/maximize", column_path: board_columns_stream_path(board) %>
|
||||
</header>
|
||||
<%= render "columns/show/add_card_button", board: board %>
|
||||
<div data-bridge-disabled="true">
|
||||
<%= render "columns/show/add_card_button", board: board %>
|
||||
</div>
|
||||
<div class="cards__list hide-scrollbar" data-drag-drop-item-container>
|
||||
<% if page.used? %>
|
||||
<%= with_automatic_pagination "maybe", @page do %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<section id="<%= dom_id(card, :card_container) %>" class="card-perma" style="--card-color: <%= card.color %>;" data-controller="dialog-manager">
|
||||
<section id="<%= dom_id(card, :card_container) %>" class="card-perma" style="--card-color: <%= card.color %>;" data-controller="dialog-manager bridge--form">
|
||||
<% cache card do %>
|
||||
<div class="card-perma__actions card-perma__actions--left">
|
||||
<%= render "cards/container/gild", card: card if card.published? && !card.closed? %>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
dialog_target: "dialog",
|
||||
navigable_list_focus_on_selection_value: false,
|
||||
navigable_list_actionable_items_value: true } do %>
|
||||
<strong class="popup__title pad-inline-half">Move this card to…</strong>
|
||||
<%= filter_title "Move this card to…" %>
|
||||
|
||||
<%= text_field_tag :search, nil, placeholder: "Filter…", class: "input input--transparent txt-small margin-block-half font-weight-normal", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", dialog_target: "focusMouse", action: "input->filter#filter" } %>
|
||||
|
||||
<ul class="popup__list margin-block-start-half margin-none-block-end" data-filter-target="list">
|
||||
<% @boards.each do |board| %>
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
<div class="display-contents" id="<%= dom_id(card, :card_closure_toggle) %>">
|
||||
<% if card.closed? %>
|
||||
<div class="card-perma__notch card-perma__notch--bottom flex-column">
|
||||
<div class="flex gap-half margin-block-start-double margin-block-end">
|
||||
<span class="card-perma__closure-message">
|
||||
Completed by <%= card.closed_by.name %> on <%= local_datetime_tag(card.closed_at, style: :shortdate) %>.
|
||||
<%= button_to card_closure_path(card), method: :delete, class: "btn btn--plain borderless fill-transparent" do %>
|
||||
<span class="pad-inline-end">Undo</span>
|
||||
<% end %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-perma__closure-message flex gap-half justify-center">
|
||||
<span>Completed by <%= card.closed_by.name %> on <%= local_datetime_tag(card.closed_at, style: :shortdate) %>.</span>
|
||||
<%= button_to card_closure_path(card), method: :delete, class: "btn btn--plain borderless fill-transparent" do %>
|
||||
<span class="pad-inline-end">Undo</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="card-perma__notch card-perma__notch--bottom flex-column">
|
||||
<div class="card-perma__notch card-perma__notch--bottom">
|
||||
<%= render "cards/container/closure_buttons", card: card %>
|
||||
</div>
|
||||
<% if card.entropic? && card.open? && !card.postponed? %>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<div class="flex gap-half">
|
||||
<%= link_to edit_card_path(card), class: "btn btn--circle-mobile borderless", data: { controller: "hotkey", action: "keydown.e@document->hotkey#click", turbo_frame: dom_id(card, :edit) } do %>
|
||||
<%= link_to edit_card_path(card), class: "btn btn--circle-mobile borderless",
|
||||
data: { controller: "hotkey", action: "keydown.e@document->hotkey#click", bridge__buttons_target: "button", bridge_title: "Edit", bridge_icon_url: bridge_icon("pencil"), turbo_frame: dom_id(card, :edit) } do %>
|
||||
<%= icon_tag "pencil", class: "icon--mobile-only" %>
|
||||
<span>Edit</span>
|
||||
<kbd class="txt-x-small hide-on-touch">e</kbd>
|
||||
<% end %>
|
||||
|
||||
<%= button_to card_closure_path(card), class: "btn btn--circle-mobile borderless",
|
||||
data: { controller: "hotkey", form_target: "submit", action: "keydown.d@document->hotkey#click" },
|
||||
data: { controller: "hotkey", form_target: "submit", bridge__buttons_target: "button", bridge_title: "Mark as Done", bridge_icon_url: bridge_icon("check"), action: "keydown.d@document->hotkey#click" },
|
||||
form: { data: { controller: "form" } } do %>
|
||||
<%= icon_tag "check", class: "icon--mobile-only" %>
|
||||
<span class="overflow-ellipsis">Mark as Done</span>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<% if card.golden? %>
|
||||
<%= button_to card_goldness_path(card), method: :delete, class: "btn btn--reversed", data: { controller: "tooltip hotkey", action: "keydown.shift+g@document->hotkey#click" } do %>
|
||||
<%= button_to card_goldness_path(card), method: :delete, class: "btn btn--reversed",
|
||||
data: { controller: "tooltip hotkey", action: "keydown.shift+g@document->hotkey#click", bridge__overflow_menu_target: "item", bridge_title: "Demote to normal" } do %>
|
||||
<%= icon_tag "golden-ticket" %>
|
||||
<span class="for-screen-reader">Demote to normal (shift+g)</span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= button_to card_goldness_path(card), class: "btn", data: { controller: "tooltip hotkey", action: "keydown.shift+g@document->hotkey#click" } do %>
|
||||
<%= button_to card_goldness_path(card), class: "btn",
|
||||
data: { controller: "tooltip hotkey", action: "keydown.shift+g@document->hotkey#click", bridge__overflow_menu_target: "item", bridge_title: "Promote to Golden Ticket" } do %>
|
||||
<%= icon_tag "golden-ticket" %>
|
||||
<span class="for-screen-reader">Promote to Golden Ticket (shift+g)</span>
|
||||
<% end %>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<% if card.image.attached? %>
|
||||
<%= button_to card_image_path(card), method: :delete, class: "btn", data: { controller: "tooltip" } do %>
|
||||
<%= button_to card_image_path(card), method: :delete, class: "btn",
|
||||
data: { controller: "tooltip", bridge__overflow_menu_target: "item", bridge_title: "Remove background image" } do %>
|
||||
<%= icon_tag "picture-remove" %>
|
||||
<span class="for-screen-reader">Remove background image</span>
|
||||
<% end %>
|
||||
<% elsif !card.closed? %>
|
||||
<%= form_with model: card, data: { controller: "form" } do |form| %>
|
||||
<label class="card-perma__image-btn btn input--file" data-controller="tooltip">
|
||||
<label class="card-perma__image-btn btn input--file" data-controller="tooltip" data-bridge--overflow-menu-target="item" data-bridge-title="Add background image">
|
||||
<%= icon_tag "picture-add" %>
|
||||
<span class="for-screen-reader">Add background image</span>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="card-perma__notch card-perma__notch--bottom flex-column">
|
||||
<%= button_tag type: :submit, form: dom_id(card, :edit_form), class: "btn borderless",
|
||||
title: "Save changes (#{ hotkey_label(["ctrl", "enter"]) })",
|
||||
data: { controller: "hotkey", action: "keydown.ctrl+enter@document->hotkey#click keydown.meta+enter@document->hotkey#click" } do %>
|
||||
data: { controller: "hotkey", bridge__form_target: "submit", action: "keydown.ctrl+enter@document->hotkey#click keydown.meta+enter@document->hotkey#click" } do %>
|
||||
<span>Save changes</span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div class="card-perma__notch-new-card-buttons">
|
||||
<%= button_to card_publish_path(card), name: "creation_type", value: "add", class: "btn",
|
||||
title: "Create card (#{ hotkey_label(["ctrl", "enter"]) })",
|
||||
form: { data: { controller: "form" } },
|
||||
data: { form_target: "submit", controller: "clicker", action: "keydown.ctrl+enter@document->clicker#click keydown.meta+enter@document->clicker#click" } do %>
|
||||
form: { data: { controller: "form bridge--form" } },
|
||||
data: { form_target: "submit", bridge__form_target: "submit", controller: "clicker", action: "keydown.ctrl+enter@document->clicker#click keydown.meta+enter@document->clicker#click" } do %>
|
||||
<span>Create card</span>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<%= general_prompts(@card.board) %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to "Close editor and discard changes", @card, data: { form_target: "cancel" }, hidden: true %>
|
||||
<%= link_to "Close editor and discard changes", @card,
|
||||
data: { form_target: "cancel", bridge__form_target: "cancel", bridge_title: "Cancel" }, hidden: true %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<%= render "cards/broadcasts", filter: @filter %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis txt-capitalize-first-letter"><%= @user_filtering.selected_boards_label %></span>
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<div id="<%= dom_id(card, :pin_button) %>">
|
||||
<% if card.pinned_by? Current.user %>
|
||||
<%= button_to card_pin_path(card), method: :delete, class: "btn btn--reversed", data: { controller: "tooltip hotkey", action: "keydown.shift+p@document->hotkey#click" } do %>
|
||||
<%= button_to card_pin_path(card), method: :delete, class: "btn btn--reversed",
|
||||
data: { controller: "tooltip hotkey", action: "keydown.shift+p@document->hotkey#click", bridge__overflow_menu_target: "item", bridge_title: "Un-pin this card" } do %>
|
||||
<%= icon_tag "pinned" %> <span class="for-screen-reader">Un-pin this card (shift+p)</span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= button_to card_pin_path(card), class: "btn", data: { controller: "tooltip hotkey", action: "keydown.shift+p@document->hotkey#click" } do %>
|
||||
<%= button_to card_pin_path(card), class: "btn",
|
||||
data: { controller: "tooltip hotkey", action: "keydown.shift+p@document->hotkey#click", bridge__overflow_menu_target: "item", bridge_title: "Pin this card" } do %>
|
||||
<%= icon_tag "unpinned" %> <span class="for-screen-reader">Pin this card (shift+p)</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<div id="<%= dom_id(card, :watch_button) %>">
|
||||
<% if card.watched_by? Current.user %>
|
||||
<%= button_to card_watch_path(card), method: :delete, class: "btn btn--reversed", data: { controller: "tooltip hotkey", action: "keydown.shift+n@document->hotkey#click" } do %>
|
||||
<%= button_to card_watch_path(card), method: :delete, class: "btn btn--reversed",
|
||||
data: { controller: "tooltip hotkey", action: "keydown.shift+n@document->hotkey#click", bridge__overflow_menu_target: "item", bridge_title: "Stop watching" } do %>
|
||||
<%= icon_tag "bell" %>
|
||||
<span class="for-screen-reader">Stop watching (shift+n)</span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= button_to card_watch_path(card), class: "btn", data: { controller: "tooltip hotkey", action: "keydown.shift+n@document->hotkey#click" } do %>
|
||||
<%= button_to card_watch_path(card), class: "btn",
|
||||
data: { controller: "tooltip hotkey", action: "keydown.shift+n@document->hotkey#click", bridge__overflow_menu_target: "item", bridge_title: "Watch this" } do %>
|
||||
<%= icon_tag "bell-off" %>
|
||||
<span class="for-screen-reader">Watch this (shift+n)</span>
|
||||
<% end %>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<div class="board-tools card">
|
||||
<%= button_to board_cards_path(board), method: :post, class: "btn btn--link", form: { data: { turbo_frame: "_top" } }, data: { controller: "hotkey", action: "keydown.c@document->hotkey#click" } do %>
|
||||
<%= button_to board_cards_path(board), method: :post, class: "btn btn--link",
|
||||
form: { data: { turbo_frame: "_top" } },
|
||||
data: { controller: "hotkey", action: "keydown.c@document->hotkey#click", bridge__buttons_target: "button", bridge_title: "Add card", bridge_icon_url: bridge_icon("add") } do %>
|
||||
<%= icon_tag "add", class: "show-on-touch" %>
|
||||
<span>Add a card</span>
|
||||
<kbd class="hide-on-touch">C</kbd>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to "Activity", root_path, "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title">
|
||||
<h1 class="header__title" data-bridge--title-target="header">
|
||||
<%= @column.title %>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<% content_for :header do %>
|
||||
<%= render "events/index/add_card_button", user_filtering: @user_filtering %>
|
||||
|
||||
<h1 class="header__title" data-controller="dialog-manager">
|
||||
<h1 class="header__title" data-controller="dialog-manager" data-bridge--title-target="header">
|
||||
<% if @user_filtering.boards.many? %>
|
||||
<span>Activity <%= @user_filtering.filter.boards.any? ? "in" : "across" %></span>
|
||||
<% else %>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<div class="header__actions header__actions--end">
|
||||
<div>
|
||||
<%= link_to new_board_path, class: "btn btn--link btn--circle-mobile", data: { controller: "hotkey", action: "keydown.b@document->hotkey#click" } do %>
|
||||
<%= link_to new_board_path, class: "btn btn--link btn--circle-mobile",
|
||||
data: { controller: "hotkey", action: "keydown.b@document->hotkey#click", bridge__buttons_target: "button", bridge_title: "Add a board", bridge_icon_url: bridge_icon("board") } do %>
|
||||
<%= icon_tag "board" %>
|
||||
<span class="overflow-ellipsis">Add a board</span>
|
||||
<kbd class="hide-on-touch">B</kbd>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<div class="header__actions header__actions--start">
|
||||
<% if board = user_filtering.single_board_or_first %>
|
||||
<%= button_to board_cards_path(board), method: :post, class: "btn btn--link btn--circle-mobile", data: { controller: "hotkey", action: "keydown.c@document->hotkey#click" } do %>
|
||||
<%= button_to board_cards_path(board), method: :post, class: "btn btn--link btn--circle-mobile",
|
||||
data: { controller: "hotkey", action: "keydown.c@document->hotkey#click", bridge__buttons_target: "button", bridge_title: "Add a card", bridge_icon_url: bridge_icon("add") } do %>
|
||||
<%= icon_tag "add" %>
|
||||
<span class="overflow-ellipsis">Add a card</span>
|
||||
<kbd class="hide-on-touch">C</kbd>
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Board…" do %>
|
||||
<strong class="popup__title">Board…</strong>
|
||||
<%= filter_title "Board…" %>
|
||||
<%= text_field_tag nil, nil, id: nil, placeholder: "Filter…", class: "input input--transparent txt-small font-weight-normal", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", dialog_target: "focusMouse", action: "input->filter#filter" } %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
<% user_filtering.boards.each do |board| %>
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Person…" do %>
|
||||
<strong class="popup__title">Person…</strong>
|
||||
<%= filter_title "Person…" %>
|
||||
<%= text_field_tag nil, nil, id: nil, placeholder: "Filter…", class: "input input--transparent txt-small font-weight-normal", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", dialog_target: "focusMouse", action: "input->filter#filter" } %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
<% user_filtering.users.each do |user| %>
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Assigned to…" do %>
|
||||
<strong class="popup__title">Assigned to…</strong>
|
||||
|
||||
<%= filter_title "Assigned to…" %>
|
||||
<% if Current.account.users.active.many? %>
|
||||
<%= text_field_tag nil, nil, id: nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", dialog_target: "focusMouse", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Board…" do %>
|
||||
<strong class="popup__title">Board…</strong>
|
||||
|
||||
<%= filter_title "Board…" %>
|
||||
<% if user_filtering.boards.many? %>
|
||||
<%= text_field_tag nil, nil, id: nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", dialog_target: "focusMouse", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Closed by…" do %>
|
||||
<strong class="popup__title">Closed by…</strong>
|
||||
|
||||
<%= filter_title "Closed by…" %>
|
||||
<% if user_filtering.users.many? %>
|
||||
<%= text_field_tag nil, nil, id: nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", dialog_target: "focusMouse", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Added by…" do %>
|
||||
<strong class="popup__title">Added by…</strong>
|
||||
|
||||
<%= filter_title "Added by…" %>
|
||||
<% if user_filtering.users.many? %>
|
||||
<%= text_field_tag nil, nil, id: nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", dialog_target: "focusMouse", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Tagged…" do %>
|
||||
<strong class="popup__title">Tagged…</strong>
|
||||
|
||||
<%= filter_title "Tagged…" %>
|
||||
<% if user_filtering.tags.many? %>
|
||||
<%= text_field_tag nil, nil, id: nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", dialog_target: "focusMouse", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
<html lang="en">
|
||||
<%= render "layouts/shared/head" %>
|
||||
|
||||
<body class="<%= @body_class %>" data-controller="local-time timezone-cookie turbo-navigation theme" data-action="turbo:morph@window->local-time#refreshAll turbo:before-visit@document->turbo-navigation#rememberLocation" data-platform="<%= platform.type %>">
|
||||
<div id="global-container">
|
||||
<body class="<%= @body_class %>"
|
||||
data-controller="local-time timezone-cookie turbo-navigation theme bridge--title bridge--text-size bridge--insets"
|
||||
data-action="turbo:morph@window->local-time#refreshAll turbo:before-visit@document->turbo-navigation#rememberLocation"
|
||||
data-platform="<%= platform.type %>" data-bridge--title-title-value="<%= @page_title %>">
|
||||
<div id="global-container" data-controller="bridge--buttons bridge--overflow-menu">
|
||||
<header class="header header--mobile-actions-stack <%= @header_class %>" id="header">
|
||||
<a href="#main" class="header__skip-navigation btn" data-turbo="false">Skip to main content</a>
|
||||
<%= render "my/menu" if Current.user %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to "My profile", user_path(Current.user), "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
<% end %>
|
||||
|
||||
<section class="panel panel--wide shadow center webhooks">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to "tokens", my_access_tokens_path, "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
<% end %>
|
||||
|
||||
<article class="panel panel--wide shadow center txt-align-start" style="view-transition-name: <%= dom_id(@access_token) %>">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to "Tokens", my_access_tokens_path, "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
<% end %>
|
||||
|
||||
<article class="panel panel--wide shadow center txt-align-start" style="view-transition-name: <%= dom_id(@access_token) %>">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to "Home", root_path, "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
<% end %>
|
||||
|
||||
<div class="pins-list panel panel--wide flex center borderless unpad flex-column gap-half margin-block-start">
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
<%= back_link_to "Home", root_path, "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
|
||||
<div class="header__actions header__actions--end">
|
||||
<%= link_to notifications_settings_path, class: "btn" do %>
|
||||
<%= link_to notifications_settings_path, class: "btn", data: { bridge__overflow_menu_target: "item", bridge_title: "Notification settings" } do %>
|
||||
<%= icon_tag "settings" %> <span class="for-screen-reader">Notification settings</span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<% @page_title = "Notification Settings" %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
<% end %>
|
||||
|
||||
<section class="settings margin-block-start-half">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to @board.name, published_board_url(@board), "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to @board.name, published_board_url(@board), "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to @column.board.name, published_board_url(@column.board), "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to @board.name, published_board_url(@board), "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<% end %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<h1 class="header__title divider divider--fade full-width">
|
||||
<h1 class="header__title divider divider--fade full-width" data-bridge--title-target="header">
|
||||
<span class="overflow-ellipsis"><%= @page_title %></span>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to "Home", root_path, "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
<% end %>
|
||||
|
||||
<div class="search-perma margin-block-start">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= link_back_to_board(@board) %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
<% end %>
|
||||
|
||||
<%= tag.section class: "panel panel--wide shadow center webhooks" do %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= back_link_to "Webhooks", board_webhooks_path, "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>
|
||||
</div>
|
||||
|
||||
<h1 class="header__title"><%= @page_title %></h1>
|
||||
<h1 class="header__title" data-bridge--title-target="header"><%= @page_title %></h1>
|
||||
<% end %>
|
||||
|
||||
<article class="panel panel--wide center txt-align-start" style="view-transition-name: <%= dom_id(@webhook) %>">
|
||||
|
||||
@@ -4,11 +4,15 @@ pin "application"
|
||||
pin "@hotwired/turbo-rails", to: "turbo.min.js"
|
||||
pin "@hotwired/stimulus", to: "stimulus.min.js"
|
||||
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
|
||||
pin "@hotwired/hotwire-native-bridge", to: "@hotwired--hotwire-native-bridge.js"
|
||||
pin "@rails/request.js", to: "@rails--request.js" # @0.0.13
|
||||
|
||||
pin_all_from "app/javascript/controllers", under: "controllers"
|
||||
pin_all_from "app/javascript/helpers", under: "helpers"
|
||||
pin_all_from "app/javascript/initializers", under: "initializers"
|
||||
pin_all_from "app/javascript/bridge/initializers", under: "bridge/initializers"
|
||||
pin_all_from "app/javascript/bridge/helpers", under: "bridge/helpers"
|
||||
pin_all_from "app/javascript/bridge/controllers/bridge", under: "controllers/bridge", to: "bridge/controllers/bridge"
|
||||
pin "marked" # @15.0.11
|
||||
pin "lexxy"
|
||||
pin "@rails/activestorage", to: "activestorage.esm.js"
|
||||
|
||||
@@ -15,7 +15,9 @@ class NotificationTest < ActiveSupport::TestCase
|
||||
notification.read # Mark as read first
|
||||
|
||||
assert_turbo_stream_broadcasts([ notification.user, :notifications ], count: 1) do
|
||||
notification.unread
|
||||
perform_enqueued_jobs do
|
||||
notification.unread
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// @hotwired/hotwire-native-bridge@1.2.2 downloaded from https://ga.jspm.io/npm:@hotwired/hotwire-native-bridge@1.2.2/dist/hotwire-native-bridge.js
|
||||
|
||||
import{Controller as e}from"@hotwired/stimulus";var t=class{#e;#t;#s;#n;constructor(){this.#e=null;this.#t=0;this.#s=[];this.#n=new Map}start(){this.notifyApplicationAfterStart()}notifyApplicationAfterStart(){document.dispatchEvent(new Event("web-bridge:ready"))}supportsComponent(e){return!!this.#e&&this.#e.supportsComponent(e)}send({component:e,event:t,data:s,callback:n}){if(!this.#e){this.#i({component:e,event:t,data:s,callback:n});return null}if(!this.supportsComponent(e))return null;const i=this.generateMessageId();const r={id:i,component:e,event:t,data:s||{}};this.#e.receive(r);n&&this.#n.set(i,n);return i}receive(e){this.executeCallbackFor(e)}executeCallbackFor(e){const t=this.#n.get(e.id);t&&t(e)}removeCallbackFor(e){this.#n.has(e)&&this.#n.delete(e)}removePendingMessagesFor(e){this.#s=this.#s.filter((t=>t.component!=e))}generateMessageId(){const e=++this.#t;return e.toString()}setAdapter(e){this.#e=e;document.documentElement.dataset.bridgePlatform=this.#e.platform;this.adapterDidUpdateSupportedComponents();this.#r()}adapterDidUpdateSupportedComponents(){this.#e&&(document.documentElement.dataset.bridgeComponents=this.#e.supportedComponents.join(" "))}#i(e){this.#s.push(e)}#r(){this.#s.forEach((e=>this.send(e)));this.#s=[]}};var s=class{constructor(e){this.element=e}get title(){return(this.bridgeAttribute("title")||this.attribute("aria-label")||this.element.textContent||this.element.value).trim()}get enabled(){return!this.disabled}get disabled(){const e=this.bridgeAttribute("disabled");return e==="true"||e===this.platform}enableForComponent(e){e.enabled&&this.removeBridgeAttribute("disabled")}hasClass(e){return this.element.classList.contains(e)}attribute(e){return this.element.getAttribute(e)}bridgeAttribute(e){return this.attribute(`data-bridge-${e}`)}setBridgeAttribute(e,t){this.element.setAttribute(`data-bridge-${e}`,t)}removeBridgeAttribute(e){this.element.removeAttribute(`data-bridge-${e}`)}click(){this.platform=="android"&&this.element.removeAttribute("target");this.element.click()}get platform(){return document.documentElement.dataset.bridgePlatform}};var{userAgent:n}=window.navigator;function i(e){const t=n.match(/bridge-components: \[(.*?)\]/);return!!t&&t[1].split(" ").includes(e)}var r=class extends e{static component="";static get shouldLoad(){return i(this.component)}pendingMessageCallbacks=[];initialize(){this.pendingMessageCallbacks=[]}connect(){this.removeRestoreEventListener();this.addRestoreEventListener()}disconnect(){this.removePendingCallbacks();this.removePendingMessages();this.removeRestoreEventListener()}addRestoreEventListener(){this.restore=this.restore.bind(this);document.addEventListener("native:restore",this.restore)}removeRestoreEventListener(){document.removeEventListener("native:restore",this.restore)}restore(){this.connect()}get component(){return this.constructor.component}get platformOptingOut(){const{bridgePlatform:e}=document.documentElement.dataset;return this.identifier==this.element.getAttribute(`data-controller-optout-${e}`)}get enabled(){return!this.platformOptingOut&&this.bridge.supportsComponent(this.component)}send(e,t={},s){t.metadata={url:window.location.href};const n={component:this.component,event:e,data:t,callback:s};const i=this.bridge.send(n);s&&this.pendingMessageCallbacks.push(i)}removePendingCallbacks(){this.pendingMessageCallbacks.forEach((e=>this.bridge.removeCallbackFor(e)))}removePendingMessages(){this.bridge.removePendingMessagesFor(this.component)}get bridgeElement(){return new s(this.element)}get bridge(){return window.HotwireNative.web}};if(!window.HotwireNative){const e=new t;window.HotwireNative={web:e};a(e);e.start()}function a(e){window.Strada||(window.Strada={web:e});window.webBridge||(window.webBridge=e)}export{r as BridgeComponent,s as BridgeElement};
|
||||
|
||||
Reference in New Issue
Block a user