Merge branch 'main' into activity-score
* main: (22 commits) Fix layout issue that caused comment form to be unselectable Stick with stock buttons for now Still a little odd that it's a separate form but this conceptually belongs here We've got a utility for this Fix navbar alignment Kind of hate that icon, let's try something else Use new bubble shape Prevent bubble getting squished Fix image fit, try animation Don't assume `@filter` is set Clicking assignees filters by that assignee Restore behavior: clicking tags filters by that tag Make these consist from view-to-view Improve hover motion for meta bubbles No longer used Improve assignee bubble display, especially when there are multiple assignees name -> key ** not required Swap one? and many? branches Change title based on selected buckets ...
This commit is contained in:
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m2.6 21.4c-.9-.7-1.4-1.9-1.3-3 .2-1.6 1.5-3.3 2.9-3.9 5.8-2.6 8.3 10.9.5 8.1-.5-.2-.8-.4-1.3-.5-.4-.2-.6-.4-.9-.6z"/><path d="m22.1 20.3c-.4.8-1.2 1.3-2.1 1.4-1.3.1-2.7-.5-3.4-1.5-2.9-3.8 7-7.7 6-1.7 0 .4-.1.7-.2 1 0 .3-.2.5-.3.8z"/><path d="m17.4 1.9c.9-.6 2.1-.7 3-.3 1.4.5 2.6 1.9 2.8 3.4.8 5.5-12.1 4.1-7.4-1.5.3-.3.5-.6.8-.9.3-.2.5-.5.8-.6z"/><path d="m.7 5c0-1.3.5-2.6 1.6-3.3 1.5-1.1 3.8-1.2 5.5-.5 6.8 3.1-2.9 15.2-6.4 6.4-.2-.5-.4-1-.5-1.5-.1-.4-.3-.8-.2-1.3z"/><path d="m6.5 12c0 .4.3.7.7.7h4s.1 0 .1.1v4c0 .4.3.7.7.7s.7-.3.7-.7v-4s0-.1.1-.1h4c.4 0 .7-.3.7-.7s-.3-.7-.7-.7h-4s-.1 0-.1-.1v-4c0-.4-.3-.7-.7-.7s-.7.3-.7.7v4s0 .1-.1.1h-4c-.4 0-.7.3-.7.7z"/></svg>
|
||||
|
Before Width: | Height: | Size: 738 B |
@@ -51,3 +51,11 @@
|
||||
50% { border-radius: 46% 54% 61% 39% / 50% 51% 49% 50%; }
|
||||
75% { border-radius: 54% 46% 61% 39% / 57% 49% 51% 43%; }
|
||||
}
|
||||
|
||||
@keyframes wobble-img {
|
||||
15% { border-radius: 66% 34% 72% 28% / 39% 63% 37% 61%; }
|
||||
25% { border-radius: 55% 47% 62% 40% / 58% 50% 52% 44%; }
|
||||
33% { border-radius: 46% 54% 61% 39% / 50% 51% 49% 50%; }
|
||||
50% { border-radius: 54% 46% 61% 39% / 57% 49% 51% 43%; }
|
||||
75% { border-radius: 53% 45% 60% 38% / 56% 48% 50% 42%; }
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
}
|
||||
|
||||
.bubble {
|
||||
--hover-size: 0;
|
||||
--bubble-border-width: 0.2rem;
|
||||
--bubble-color: var(--color-ink);
|
||||
--hover-size: 0;
|
||||
|
||||
aspect-ratio: 1;
|
||||
block-size: var(--bubble-size);
|
||||
@@ -56,6 +57,7 @@
|
||||
}
|
||||
|
||||
.bubble__perma & {
|
||||
--bubble-border-width: 0.3rem;
|
||||
--bubble-size: 100% !important;
|
||||
|
||||
z-index: 1;
|
||||
@@ -64,7 +66,7 @@
|
||||
|
||||
.bubble__bubble {
|
||||
background-color: var(--color-bg);
|
||||
border: max(3px, 0.2em) solid var(--bubble-color);
|
||||
border: var(--bubble-border-width) solid var(--bubble-color);
|
||||
border-radius: var(--bubble-shape);
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
@@ -73,13 +75,20 @@
|
||||
color: var(--bubble-color);
|
||||
}
|
||||
|
||||
&:is(.bubble__boosts) {
|
||||
aspect-ratio: 1;
|
||||
&.bubble__boosts {
|
||||
--rotation: 45deg;
|
||||
|
||||
aspect-ratio: 6/9;
|
||||
display: flex;
|
||||
inset: 75cqi 5cqi auto auto;
|
||||
min-inline-size: 6ch;
|
||||
inset: 70cqi 7cqi auto auto;
|
||||
min-inline-size: 7ch;
|
||||
padding: 0;
|
||||
place-items: center;
|
||||
transform: rotate(var(--rotation));
|
||||
|
||||
span {
|
||||
transform: rotate(calc(var(--rotation) * -1));
|
||||
}
|
||||
|
||||
form {
|
||||
block-size: 100%;
|
||||
@@ -95,13 +104,15 @@
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.windshield .bubble:hover & {
|
||||
transform: translate(0, 1rem) !important;
|
||||
}
|
||||
|
||||
&.boosting {
|
||||
animation: bubble-up 500ms normal forwards ease-out;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.windshield .bubble:hover & {
|
||||
transform: rotate(calc(var(--rotation) + var(--bubble-shift) * 1)) translate(0rem, 1rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bubble__tag {
|
||||
@@ -115,10 +126,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.windshield &:has(.bubble__tag--new) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.windshield .bubble:hover & {
|
||||
transform: translate(-1rem, -1rem);
|
||||
@@ -137,56 +144,53 @@
|
||||
&.bubble__assignee {
|
||||
aspect-ratio: 1;
|
||||
font-size: 4.5cqi;
|
||||
inset: -2cqi auto auto 26cqi;
|
||||
padding: 0.4em;
|
||||
inset: 4cqb auto auto -2cqi;
|
||||
padding: 0.2em;
|
||||
|
||||
+ & {
|
||||
inset: 1cqb auto auto 10cqi;
|
||||
|
||||
+ & {
|
||||
inset: -1cqb auto auto 25cqi;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
inset: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: var(--bubble-shape);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.windshield .bubble:hover & {
|
||||
transform: translate(1rem, 0);
|
||||
transform: translate(1rem, -1rem);
|
||||
}
|
||||
|
||||
.windshield .bubble:hover & + & {
|
||||
transform: translate(1rem, -1rem);
|
||||
}
|
||||
|
||||
.windshield .bubble:hover & + & + & {
|
||||
transform: translate(1.5rem, -0.5rem);;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bubble__assignee--new {
|
||||
.windshield & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.bubble__attachment {
|
||||
aspect-ratio: 1;
|
||||
font-size: 4cqi;
|
||||
inset: -5cqb 26cqi auto auto;
|
||||
|
||||
.btn {
|
||||
font-size: 4cqi;
|
||||
}
|
||||
|
||||
.windshield & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.bubble__color {
|
||||
cursor: pointer;
|
||||
inset: 8cqb auto auto 0.5cqi;
|
||||
padding: 0.4em;
|
||||
|
||||
.windshield & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.bubble__date {
|
||||
aspect-ratio: 1;
|
||||
--rotation: -45deg;
|
||||
|
||||
aspect-ratio: 5/7;
|
||||
cursor: pointer;
|
||||
font-size: 4.5cqi;
|
||||
inset: 1cqb 1cqi auto auto;
|
||||
transform: rotate(var(--rotation));
|
||||
|
||||
.bubble__date-text {
|
||||
transform: rotate(calc(var(--rotation) * -1));
|
||||
}
|
||||
|
||||
label {
|
||||
display: grid;
|
||||
@@ -196,13 +200,11 @@
|
||||
grid-area: 1/1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bubble__date--new {
|
||||
padding: 0.7em;
|
||||
|
||||
.windshield & {
|
||||
display: none;
|
||||
@media (hover: hover) {
|
||||
.windshield .bubble:hover & {
|
||||
transform: rotate(calc(var(--rotation) + var(--bubble-shift) * 1)) translate(0rem, 0.5rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,9 +266,9 @@
|
||||
border-radius: var(--bubble-shape);
|
||||
block-size: 100cqi;
|
||||
inline-size: 100cqi;
|
||||
overflow: clip;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
transform: rotate(var(--bubble-rotate)) scale(0.9);
|
||||
transform: rotate(var(--bubble-rotate)) scale(0.92);
|
||||
transition: 0.2s ease;
|
||||
|
||||
@media (hover: hover) {
|
||||
@@ -278,13 +280,18 @@
|
||||
img {
|
||||
block-size: 100cqi;
|
||||
inline-size: 100cqi;
|
||||
max-inline-size: none;
|
||||
object-fit: cover;
|
||||
transform: rotate(calc(var(--bubble-rotate) * -1));
|
||||
transform: rotate(calc(var(--bubble-rotate) * -1)) scale(1.1);
|
||||
|
||||
&:is([src=""]) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:is(.windshield, .bubbles-list) .bubble--wobble & {
|
||||
animation: wobble-img 1200ms normal forwards ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__link {
|
||||
@@ -294,13 +301,9 @@
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.bubble__notes {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bubble__perma {
|
||||
block-size: 100%;
|
||||
max-block-size: 65dvh;
|
||||
max-block-size: 40dvh;
|
||||
max-inline-size: 100%;
|
||||
}
|
||||
|
||||
@@ -400,18 +403,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__popped {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
background-color: red;
|
||||
color: white;
|
||||
padding: 1rem 2rem;
|
||||
font-size: 200%;
|
||||
border-radius: 4px;
|
||||
transform: rotate(-35deg) translate(-25%, -50%);
|
||||
}
|
||||
|
||||
.bubble__shape {
|
||||
background-color: var(--bubble-color);
|
||||
block-size: 1.2em;
|
||||
@@ -425,7 +416,7 @@
|
||||
|
||||
.bubble & {
|
||||
background-color: color(from var(--bubble-color) srgb r g b / 0.15);
|
||||
border: 0.2em solid var(--bubble-color);
|
||||
border: var(--bubble-border-width) solid var(--bubble-color);
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
}
|
||||
@@ -434,10 +425,6 @@
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.bubble__perma & {
|
||||
border-width: 0.4em;
|
||||
}
|
||||
|
||||
:is(.windshield, .bubbles-list) .bubble--wobble & {
|
||||
animation: wobble 1200ms normal forwards ease-out;
|
||||
}
|
||||
|
||||
@@ -195,14 +195,6 @@
|
||||
--btn-padding: 0;
|
||||
--hover-size: 0;
|
||||
--outline-size: 0;
|
||||
|
||||
@media (hover: hover) {
|
||||
transition: scale 200ms ease-out;
|
||||
|
||||
&:has(img):hover {
|
||||
scale: 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn--positive {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
body {
|
||||
display: grid;
|
||||
grid-template-rows: auto auto 1fr auto var(--block-space);
|
||||
grid-template-rows: auto 1fr auto var(--block-space);
|
||||
}
|
||||
|
||||
:where(#main) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
module FiltersHelper
|
||||
def filter_chip_tag(text, name:, value:)
|
||||
tag.button class: "btn txt-small btn--remove", data: { action: "filter-form#removeFilter form#submit", filter_form_target: "chip" } do
|
||||
concat hidden_field_tag(name, value, id: nil)
|
||||
def filter_chip_tag(text, params)
|
||||
link_to bubbles_path(params), class: "btn txt-small btn--remove" do
|
||||
concat tag.span(text)
|
||||
concat image_tag("close.svg", aria: { hidden: true }, size: 24)
|
||||
end
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = [ "chip" ]
|
||||
|
||||
connect() {
|
||||
this.chipTargets.forEach(button => this.#showChip(button))
|
||||
}
|
||||
|
||||
removeFilter(event) {
|
||||
event.preventDefault()
|
||||
this.#hideChip(event.target.closest("button"))
|
||||
}
|
||||
|
||||
clearCategory({ params: { name } }) {
|
||||
name.split(",").forEach(name => {
|
||||
this.element.querySelectorAll(`input[name="${name}"]`).forEach(input => {
|
||||
@@ -19,14 +8,4 @@ export default class extends Controller {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#showChip(button) {
|
||||
button.querySelector("input").disabled = false
|
||||
button.hidden = false
|
||||
}
|
||||
|
||||
#hideChip(button) {
|
||||
button.querySelector("input").disabled = true
|
||||
button.hidden = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,11 @@ module Filter::Params
|
||||
params[:filter_id] = id if persisted?
|
||||
end
|
||||
end
|
||||
|
||||
def params_without(key, value)
|
||||
to_params.tap do |params|
|
||||
params[key].delete(value) if params[key].is_a?(Array)
|
||||
params.delete(key) if params[key] == value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
class: "btn btn--plain",
|
||||
data: { action: "toggle-class#toggle" },
|
||||
form_class: "full-width" do %>
|
||||
+ <%= bubble.boost_count if bubble.boost_count.positive? %>
|
||||
<%= tag.span("+ #{bubble.boost_count}") if bubble.boost_count.positive? %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
<% if bubble.assignments.any? %>
|
||||
<% bubble.assignments.each do |assignment| %>
|
||||
<div class="bubble__bubble bubble__meta bubble__assignee">
|
||||
<%= form_with url: bucket_bubble_assignments_path(bubble.bucket, bubble), data: { controller: "form" } do |form| %>
|
||||
<label class="btn btn--plain position-relative fill-transparent" style="<%= "--btn-icon-size: 2em;" unless bubble.assignees.any? %>">
|
||||
<% if bubble.assignees.any? %>
|
||||
<% if bubble.assignees.many? %>
|
||||
<div class="avatar__group">
|
||||
<% bubble.assignees.each do |assignee| %>
|
||||
<%= avatar_image_tag assignee, loading: :lazy, class: "avatar flex-item-no-shrink" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= avatar_image_tag bubble.assignees.first, loading: :lazy, class: "avatar flex-item-no-shrink" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<label class="btn btn--plain position-relative fill-transparent">
|
||||
<%= avatar_image_tag assignment.assignee, loading: :lazy, class: "avatar flex-item-no-shrink" %>
|
||||
|
||||
<%= form.collection_select :assignee_id, bubble.bucket.users.active, :id, :name, { prompt: "Assign to…", selected: bubble.assignees.pluck(:id) },
|
||||
class: "input input--hidden txt-medium",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<% if bubble.due_on.present? %>
|
||||
<%= form_with model: bubble, url: bucket_bubble_path(bubble.bucket, bubble), data: { controller: "form" } do |form| %>
|
||||
<label class="bubble__bubble bubble__meta bubble__date">
|
||||
<%= html_escape bubble.due_on.strftime("%b <br> %d").html_safe %>
|
||||
<span class="bubble__date-text"><%= html_escape bubble.due_on.strftime("%b <br> %d").html_safe %></span>
|
||||
<%= form.date_field :due_on, class: "input input--hidden", data: { action: "change->form#submit click->form#showPicker" } %>
|
||||
<span class="for-screen-reader">Change the due date</span>
|
||||
</label>
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<div class="flex flex-column gap-half align-center" data-controller="dialog filter-form"
|
||||
data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside turbo:before-cache@document->dialog#close">
|
||||
<h1 class="txt-large flex align-center gap-half">
|
||||
<%= filter.buckets.first&.name || "All projects" %>
|
||||
<% if filter.buckets.none? %>
|
||||
All projects
|
||||
<% elsif filter.buckets.one? %>
|
||||
<%= filter.buckets.first.name %>
|
||||
<% else %>
|
||||
<%= pluralize(filter.buckets.size, "project") %>
|
||||
<% end %>
|
||||
</h1>
|
||||
|
||||
<div class="filters flex-inline align-center gap-half">
|
||||
@@ -10,33 +16,35 @@
|
||||
<span class="for-screen-reader">Filter</span>
|
||||
</button>
|
||||
|
||||
<%= form_with url: bubbles_path, method: :get, class: "flex-inline center align-center gap-half", data: { controller: "form" } do %>
|
||||
<%= filter_chip_tag filter.indexed_by.humanize, name: "indexed_by", value: filter.indexed_by unless filter.default_indexed_by? %>
|
||||
<div class="flex-inline center align-center gap-half">
|
||||
<%= filter_chip_tag filter.indexed_by.humanize, filter.params_without(:indexed_by, filter.indexed_by) unless filter.default_indexed_by? %>
|
||||
|
||||
<% filter.tags.each do |tag| %>
|
||||
<%= filter_chip_tag tag.hashtag, name: "tag_ids[]", value: tag.id %>
|
||||
<%= filter_chip_tag tag.hashtag, filter.params_without(:tag_ids, tag.id) %>
|
||||
<% end %>
|
||||
|
||||
<% filter.assignees.each do |assignee| %>
|
||||
<%= filter_chip_tag "for #{assignee.name}", name: "assignee_ids[]", value: assignee.id %>
|
||||
<%= filter_chip_tag "for #{assignee.name}", filter.params_without(:assignee_ids, assignee.id) %>
|
||||
<% end %>
|
||||
|
||||
<% if filter.assignments.present? %>
|
||||
<%= filter_chip_tag filter.assignments.humanize, name: "assignments", value: filter.assignments %>
|
||||
<%= filter_chip_tag filter.assignments.humanize, filter.params_without(:assignments, filter.assignments) %>
|
||||
<% end %>
|
||||
|
||||
<% filter.assigners.each do |assigner| %>
|
||||
<%= filter_chip_tag "by #{assigner.name}", name: "assigner_ids[]", value: assigner.id %>
|
||||
<%= filter_chip_tag "by #{assigner.name}", filter.params_without(:assigner_ids, assigner.id) %>
|
||||
<% end %>
|
||||
|
||||
<% filter.buckets.each do |bucket| %>
|
||||
<%= filter_chip_tag "in #{bucket.name}", name: "bucket_ids[]", value: bucket.id %>
|
||||
<% if filter.buckets.many? %>
|
||||
<% filter.buckets.each do |bucket| %>
|
||||
<%= filter_chip_tag "in #{bucket.name}", filter.params_without(:bucket_ids, bucket.id) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% filter.terms.each do |term| %>
|
||||
<%= filter_chip_tag %Q("#{term}"), name: "terms[]", value: term %>
|
||||
<%= filter_chip_tag %Q("#{term}"), filter.params_without(:terms, term) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dialog class="filter__popup dialog panel fill-white shadow" data-dialog-target="dialog" data-dialog-modal-value="true">
|
||||
@@ -57,7 +65,22 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<%= form_with url: bubbles_path, id: :filter_form, method: :get, class: "flex flex-column gap full-width margin-block-start", style: "--border-color: var(--color-subtle)" do %>
|
||||
<div class="pad fill-shade border-radius margin-block-end">
|
||||
<%= form_tag bubbles_path, class: "flex align-center gap input input--actor txt-small fill-white border-radius", method: :get do %>
|
||||
<% @filter.to_params.each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<%= search_field_tag "terms[]", nil, class: "input full-width", placeholder: "By keyword…", id: nil %>
|
||||
|
||||
<button class="btn">
|
||||
<span class="for-screen-reader">Apply</span>
|
||||
<%= image_tag "arrow-right.svg", aria: { hidden: true }, size: 24 %>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= form_with url: bubbles_path, id: :filter_form, method: :get, class: "flex flex-column gap full-width", style: "--border-color: var(--color-subtle)" do %>
|
||||
<% Array(params[:terms]).each do |term| %>
|
||||
<%= hidden_field_tag "terms[]", term, id: nil %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<% @filter ||= Current.user.filters.last %>
|
||||
|
||||
<% bubble.tags.last(3).each do |tag| %>
|
||||
<%= link_to tag.hashtag, bubbles_path(bucket_id: bubble.bucket, tag_ids: tag), class: "bubble__bubble bubble__meta bubble__tag" %>
|
||||
<%= link_to tag.hashtag, bubbles_path(@filter&.to_params&.merge(tag_ids: [ tag.id ])), class: "bubble__bubble bubble__meta bubble__tag" %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<% @page_title = @filter.plain_summary %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<nav>
|
||||
<%= link_to root_path, class: "btn btn--plain flex-item-justify-start" do %>
|
||||
<%= image_tag "bubbles.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">All Projects</span>
|
||||
<nav class="align-start">
|
||||
<%= link_to root_path, class: "btn flex-item-justify-start" do %>
|
||||
<%= image_tag "arrow-left.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Go back</span>
|
||||
<% end %>
|
||||
|
||||
<header class="txt-align-center">
|
||||
@@ -12,14 +12,12 @@
|
||||
</header>
|
||||
|
||||
<% if @filter.buckets.any? %>
|
||||
<%= button_to bucket_bubbles_path(@filter.buckets.first), method: :post, class: "btn btn--plain", form_class: "flex-item-justify-end" do %>
|
||||
<%= image_tag "bubble-add.svg", aria: { hidden: true }, size: 24 %>
|
||||
<%= button_to bucket_bubbles_path(@filter.buckets.first), method: :post, class: "btn", form_class: "flex-item-justify-end" do %>
|
||||
<%= image_tag "add.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Create a new bubble</span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="flex-item-justify-end" style="height: var(--btn-size); width: var(--btn-size);">
|
||||
<%# FIXME: This is a placeholder to keep the same layout without a "new bubble" button %>
|
||||
</span>
|
||||
<span class="btn btn--placeholder flex-item-justify-end"></span>
|
||||
<% end %>
|
||||
</nav>
|
||||
<% end %>
|
||||
@@ -33,16 +31,6 @@
|
||||
</section>
|
||||
|
||||
<section class="bubbles-list unpad-inline center margin-block-start">
|
||||
<header class="flex-inline align-center gap txt-small margin-block-end-half center">
|
||||
<%= form_tag bubbles_path, method: :get do %>
|
||||
<% @filter.to_params.each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<%= search_field_tag "terms[]", nil, class: "input center flex-inline", placeholder: "Type to filter…", id: nil %>
|
||||
<% end %>
|
||||
</header>
|
||||
|
||||
<ul class="unpad margin-none flex flex-column txt-align-start center">
|
||||
<%= render partial: "bubbles/list/bubble", collection: @bubbles, cached: true %>
|
||||
</ul>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<li class="flex align-center gap margin-none" style="--bubble-color: <%= bubble.color %>; <%= bubble_rotation(bubble) %>"
|
||||
data-controller="animation" data-animation-play-class="bubble--wobble" data-animation-play-on-load-value="true" data-action="mouseover->animation#play">
|
||||
<div class="bubble__shape"></div>
|
||||
<div class="bubble__shape flex-item-no-shrink"></div>
|
||||
|
||||
<%= link_to bucket_bubble_path(bubble.bucket, bubble), class: "bubble__title-link flex align-center gap flex-item-grow min-width" do %>
|
||||
<strong class="bubble__title-text flex--inline gap-half overflow-ellipsis"><%= bubble.title %></strong>
|
||||
@@ -14,16 +14,16 @@
|
||||
|
||||
<div class="flex align-center gap flex-item-no-shrink">
|
||||
<% bubble.assignees.each do |assignee| %>
|
||||
<span class="txt-small"><%= avatar_tag assignee, loading: :lazy %></span>
|
||||
<%= link_to bubbles_path(@filter.to_params.merge(assignee_ids: [ assignee.id ])), class: "btn avatar txt-small" do %>
|
||||
<%= avatar_image_tag assignee, loading: :lazy %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<small class="flex align-center gap flex-item-no-shrink">
|
||||
<% bubble.tags.each do |tag| %>
|
||||
<%= button_tag tag.hashtag, type: :button,
|
||||
class: "btn btn--plain", style: "color: #{bubble.color}", data: {
|
||||
controller: "query-merger", action: "query-merger#merge",
|
||||
query_merger_key_param: "tag_ids", query_merger_value_param: tag.id } %>
|
||||
<%= link_to tag.hashtag, bubbles_path(@filter.to_params.merge(tag_ids: [ tag.id ])),
|
||||
class: "btn btn--plain", style: "color: #{bubble.color}" %>
|
||||
<% end %>
|
||||
|
||||
<%= tag.time bubble.created_at, class: "txt-nowrap flex-item-justify-end" do %>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<span class="for-screen-reader">Account settings</span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to new_bucket_path, class: "btn btn--plain flex-item-justify-end", style: "view-transition-name: new-bucket" do %>
|
||||
<%= image_tag "bubbles-add.svg", aria: { hidden: true }, size: 24 %>
|
||||
<%= link_to new_bucket_path, class: "btn flex-item-justify-end", style: "view-transition-name: new-bucket" do %>
|
||||
<%= image_tag "add.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Add a new project</span>
|
||||
<% end %>
|
||||
</nav>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<div class="panel shadow center" style="--panel-size: 55ch; view-transition-name: new-bucket">
|
||||
<%= form_with model: @bucket, class: "flex flex-column gap txt-large" do |form| %>
|
||||
<%= image_tag "bubbles-add.svg", aria: { hidden: "true" }, size: 150, class: "colorize--black center" %>
|
||||
<%= image_tag "bubbles.svg", aria: { hidden: "true" }, size: 150, class: "colorize--black center" %>
|
||||
<label class="flex align-center gap">
|
||||
<%= form.text_field :name, required: true, class: "input full-width", autofocus: true, placeholder: "Give it a name…" %>
|
||||
</label>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<% @page_title = "Set up Fizzy" %>
|
||||
|
||||
<div class="panel shadow center margin-block-double <%= "shake" if flash[:alert] %>" style="--panel-size: 55ch;">
|
||||
<div class="bubble center" style="--bubble-color: var(--color-ink); --bubble-rotate: 90deg; --bubble-size: 12cqi;">
|
||||
<svg class="bubble__svg" viewBox="0 0 990 990" xmlns="http://www.w3.org/2000/svg" style="stroke-width: 1.7em;">
|
||||
<path d="m0 0h990v990h-990z" fill="none" stroke="none" />
|
||||
<path d="m391.65 879.47c-110.52-15.95-212.21-91.86-255.92-191.23-66.78-143.65-41.62-347.61 48.08-481.17 368.33-516.3 1252.97 520.2 451.03 660.78-44.07 8.84-88.98 13.49-133.01 15.68-36.69 2-73.37 1.91-109.99-4.03z"/>
|
||||
</svg>
|
||||
<span class="bubble__bubble bubble__meta bubble__date" style="border-width: 0.5em;"></span>
|
||||
<span class="bubble__bubble bubble__meta bubble__tag" style="border-width: 0.5em;"> </span>
|
||||
<span class="bubble__bubble bubble__meta bubble__tag" style="border-width: 0.5em;"> </span>
|
||||
<div class="bubble center" style="--bubble-size: 12cqi;">
|
||||
<span class="bubble__shape"></span>
|
||||
<span class="bubble__bubble bubble__meta bubble__date"> </span>
|
||||
<span class="bubble__bubble bubble__meta bubble__tag"> </span>
|
||||
<span class="bubble__bubble bubble__meta bubble__tag"> </span>
|
||||
</div>
|
||||
|
||||
<h1 class="margin-block-start-half margin-block-end-double">Fizzy</h1>
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a href="#main-content" class="skip-navigation btn">Skip to main content</a>
|
||||
|
||||
<header id="header">
|
||||
<a href="#main-content" class="skip-navigation btn">Skip to main content</a>
|
||||
<%= yield :header %>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<% @page_title = "Sign in" %>
|
||||
|
||||
<div class="panel shadow center margin-block-double <%= "shake" if flash[:alert] %>" style="--panel-size: 55ch;">
|
||||
<div class="bubble center" style="--bubble-color: var(--color-ink); --bubble-rotate: 90deg; --bubble-size: 12cqi;">
|
||||
<svg class="bubble__svg" viewBox="0 0 990 990" xmlns="http://www.w3.org/2000/svg" style="stroke-width: 1.7em;">
|
||||
<path d="m0 0h990v990h-990z" fill="none" stroke="none" />
|
||||
<path d="m391.65 879.47c-110.52-15.95-212.21-91.86-255.92-191.23-66.78-143.65-41.62-347.61 48.08-481.17 368.33-516.3 1252.97 520.2 451.03 660.78-44.07 8.84-88.98 13.49-133.01 15.68-36.69 2-73.37 1.91-109.99-4.03z"/>
|
||||
</svg>
|
||||
<span class="bubble__bubble bubble__meta bubble__date" style="border-width: 0.5em;"></span>
|
||||
<span class="bubble__bubble bubble__meta bubble__tag" style="border-width: 0.5em;"> </span>
|
||||
<span class="bubble__bubble bubble__meta bubble__tag" style="border-width: 0.5em;"> </span>
|
||||
<div class="bubble center" style="--bubble-size: 12cqi;">
|
||||
<span class="bubble__shape"></span>
|
||||
<span class="bubble__bubble bubble__meta bubble__date"> </span>
|
||||
<span class="bubble__bubble bubble__meta bubble__tag"> </span>
|
||||
<span class="bubble__bubble bubble__meta bubble__tag"> </span>
|
||||
</div>
|
||||
|
||||
<h1 class="margin-block-start-half margin-block-end-double">Fizzy</h1>
|
||||
|
||||
@@ -99,4 +99,20 @@ class FilterTest < ActiveSupport::TestCase
|
||||
test "plain summary" do
|
||||
assert_equal "Most discussed, tagged #Mobile, and assigned to JZ in all projects", filters(:jz_assignments).plain_summary
|
||||
end
|
||||
|
||||
test "params without a key-value pair" do
|
||||
filter = users(:david).filters.new indexed_by: "most_discussed", assignee_ids: [ users(:jz).id, users(:kevin).id ]
|
||||
|
||||
expected = { indexed_by: "most_discussed", assignee_ids: [ users(:kevin).id ] }
|
||||
assert_equal expected.stringify_keys, filter.params_without(:assignee_ids, users(:jz).id).to_h
|
||||
|
||||
expected = { assignee_ids: [ users(:jz).id, users(:kevin).id ] }
|
||||
assert_equal expected.stringify_keys, filter.params_without(:indexed_by, "most_discussed").to_h
|
||||
|
||||
expected = { indexed_by: "most_discussed", assignee_ids: [ users(:jz).id, users(:kevin).id ] }
|
||||
assert_equal expected.stringify_keys, filter.params_without(:indexed_by, "most_active").to_h
|
||||
|
||||
expected = { indexed_by: "most_discussed", assignee_ids: [ users(:jz).id, users(:kevin).id ] }
|
||||
assert_equal expected.stringify_keys, filter.params_without(:assignee_ids, users(:david).id).to_h
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user