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:
Jose Farias
2024-11-19 13:09:57 -06:00
21 changed files with 170 additions and 187 deletions
-1
View File
@@ -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

+8
View File
@@ -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%; }
}
+66 -79
View File
@@ -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;
}
-8
View File
@@ -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 -1
View File
@@ -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) {
+2 -3
View File
@@ -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
}
}
+7
View File
@@ -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
+1 -1
View File
@@ -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 %>
+3 -13
View File
@@ -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 -1
View File
@@ -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>
+35 -12
View File
@@ -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 %>
+3 -1
View File
@@ -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 %>
+7 -19
View File
@@ -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>
+6 -6
View File
@@ -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 %>
+2 -2
View File
@@ -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>
+1 -1
View File
@@ -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>
+5 -8
View File
@@ -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;">&nbsp; &nbsp; &nbsp; &nbsp;</span>
<span class="bubble__bubble bubble__meta bubble__tag" style="border-width: 0.5em;">&nbsp; &nbsp;</span>
<div class="bubble center" style="--bubble-size: 12cqi;">
<span class="bubble__shape"></span>
<span class="bubble__bubble bubble__meta bubble__date">&nbsp; &nbsp; &nbsp; &nbsp;</span>
<span class="bubble__bubble bubble__meta bubble__tag">&nbsp; &nbsp; &nbsp; &nbsp;</span>
<span class="bubble__bubble bubble__meta bubble__tag">&nbsp; &nbsp;</span>
</div>
<h1 class="margin-block-start-half margin-block-end-double">Fizzy</h1>
+1 -2
View File
@@ -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>
+5 -8
View File
@@ -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;">&nbsp; &nbsp; &nbsp; &nbsp;</span>
<span class="bubble__bubble bubble__meta bubble__tag" style="border-width: 0.5em;">&nbsp; &nbsp;</span>
<div class="bubble center" style="--bubble-size: 12cqi;">
<span class="bubble__shape"></span>
<span class="bubble__bubble bubble__meta bubble__date">&nbsp; &nbsp; &nbsp; &nbsp;</span>
<span class="bubble__bubble bubble__meta bubble__tag">&nbsp; &nbsp; &nbsp; &nbsp;</span>
<span class="bubble__bubble bubble__meta bubble__tag">&nbsp; &nbsp;</span>
</div>
<h1 class="margin-block-start-half margin-block-end-double">Fizzy</h1>
+16
View File
@@ -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