diff --git a/Gemfile.lock b/Gemfile.lock index 1a8e39cdb..02c28a0e0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -290,7 +290,7 @@ GEM logger (~> 1.6) letter_opener (1.10.0) launchy (>= 2.2, < 4) - lexxy (0.1.19.beta) + lexxy (0.1.20.beta) rails (>= 8.0.2) lint_roller (1.1.0) logger (1.7.0) diff --git a/app/assets/stylesheets/_global.css b/app/assets/stylesheets/_global.css index c18cf4090..9f1092f82 100644 --- a/app/assets/stylesheets/_global.css +++ b/app/assets/stylesheets/_global.css @@ -89,7 +89,7 @@ --lch-ink-darkest: 26% 0.05 264; --lch-ink-darker: 40% 0.026 262; - --lch-ink-dark: 57% 0.014 260; + --lch-ink-dark: 56% 0.014 260; --lch-ink-medium: 66% 0.008 258; --lch-ink-light: 84% 0.005 256; --lch-ink-lighter: 92% 0.003 254; diff --git a/app/assets/stylesheets/card-columns.css b/app/assets/stylesheets/card-columns.css index ba2d51e05..06831f4f6 100644 --- a/app/assets/stylesheets/card-columns.css +++ b/app/assets/stylesheets/card-columns.css @@ -3,6 +3,10 @@ /* ------------------------------------------------------------------------ */ #main:has(.card-columns) { + --main-padding: 0; + } + + .card-columns { --bubble-size: 3.5rem; --cards-gap: min(1.2cqi, 1.7rem); --column-gap: 8px; @@ -14,10 +18,7 @@ --progress-max-cards: 20; --progress-max-height: 50dvh; - padding-inline: var(--column-gap); - } - - .card-columns { + -ms-overflow-style: none; /* Hide x-scrollbar on Edge */ container-type: inline-size; display: grid; gap: var(--column-gap); @@ -26,7 +27,14 @@ max-inline-size: var(--main-width); overflow-x: auto; overflow-y: hidden; + padding-block-end: var(--column-width-collapsed); position: relative; + scrollbar-width: none; /* Hide x-scrollbar on FF */ + + /* Hide x-scrollbar on Chrome/Safari/Opera */ + &::-webkit-scrollbar { + display: none; + } /* When it has something expanded */ &:has(.card-columns__left .cards:not(.is-collapsed), .card-columns__right .cards:not(.is-collapsed)) { @@ -51,10 +59,12 @@ .card-columns__left { justify-content: end; + padding-inline-start: var(--column-gap); } .card-columns__right { justify-content: start; + padding-inline-end: var(--column-gap); } /* Column diff --git a/app/assets/stylesheets/cards.css b/app/assets/stylesheets/cards.css index 2b61ac4ce..8b62d9e93 100644 --- a/app/assets/stylesheets/cards.css +++ b/app/assets/stylesheets/cards.css @@ -498,5 +498,9 @@ margin-inline: auto; text-align: start; } + + code { + text-align: left; + } } } diff --git a/app/assets/stylesheets/header.css b/app/assets/stylesheets/header.css index d8b5a2a43..be5448991 100644 --- a/app/assets/stylesheets/header.css +++ b/app/assets/stylesheets/header.css @@ -13,7 +13,8 @@ "menu menu menu" "actions-start title actions-end"; max-inline-size: 100dvw; - padding: calc(var(--block-space-half) + env(safe-area-inset-top)) var(--main-padding); + padding-block: calc(var(--block-space-half) + env(safe-area-inset-top)) var(--block-space-half); + padding-inline: var(--main-padding); /* Change the grid size depending on how many buttons are present */ &:has(.header__actions > *:nth-child(1)) { --header-button-count: 1; } @@ -78,4 +79,16 @@ --left-offset: var(--inline-space); } } + + .header__logo { + color: var(--color-ink); + inline-size: auto; + margin-block-start: 0.1em; + + img { + block-size: auto; + inline-size: 1.15em; + margin-inline-end: 0.8ch; + } + } } diff --git a/app/assets/stylesheets/boxcar-menu.css b/app/assets/stylesheets/nav.css similarity index 79% rename from app/assets/stylesheets/boxcar-menu.css rename to app/assets/stylesheets/nav.css index e60a56bb9..8d0ecef2d 100644 --- a/app/assets/stylesheets/boxcar-menu.css +++ b/app/assets/stylesheets/nav.css @@ -1,17 +1,5 @@ @layer components { - .boxcar-header-logo { - color: var(--color-ink); - inline-size: auto; - margin-block-start: 0.1em; - - img { - block-size: auto; - inline-size: 1.15em; - margin-inline-end: 0.8ch; - } - } - - .input:is(.boxcar-menu-trigger) { + .nav__trigger { --input-background: var(--color-canvas); --input-border-color: transparent; --input-padding: 0.3em 2em 0.3em 0.75em; @@ -58,9 +46,10 @@ } } - .boxcar-menu:is(.panel) { + .nav__menu.popup { --panel-border-color: var(--color-selected-dark); --panel-border-radius: 1.4em; + --panel-padding: var(--block-space) var(--block-space) 0 var(--block-space); --panel-size: 45ch; align-items: stretch; @@ -71,24 +60,15 @@ flex-direction: column; gap: 2px; scrollbar-gutter: stable both-edges; - - /* Safari doesn't position the sticky footer properly during the - * transition, so we need to delay the footer entrance. */ - .popup__footer { - animation: safari-sticky-footer-hack 0s; - animation-delay: var(--dialog-duration); - animation-fill-mode: both; - inset-inline: var(--block-space); - } } - .boxcar-menu__close { + .nav__close { @media (any-hover: hover) { display: none; } } - .boxcar-menu__hotkeys { + .nav__hotkeys { --gap: 8px; align-items: center; @@ -152,4 +132,28 @@ } } } + + /* Safari doesn't position the sticky footer properly during the + * transition, so we need to delay the footer entrance. */ + .nav__footer { + animation: safari-sticky-footer-hack 0s; + animation-delay: var(--dialog-duration); + animation-fill-mode: both; + background-color: var(--color-canvas); + border-block-start: 1px solid var(--color-ink-lighter); + font-size: var(--text-small); + inset: auto 0 0; + inset-inline: var(--block-space); + line-height: 1.6; + margin-block-start: var(--block-space-half); + padding: 1.5ch; + position: sticky; + text-align: center; + z-index: 1; + } + + @keyframes safari-sticky-footer-hack { + 0% { position: absolute; } + 100% { position: sticky; } + } } diff --git a/app/assets/stylesheets/popup.css b/app/assets/stylesheets/popup.css index 825414807..84c17c193 100644 --- a/app/assets/stylesheets/popup.css +++ b/app/assets/stylesheets/popup.css @@ -14,39 +14,9 @@ position: absolute; transform: translateX(-50%); z-index: var(--z-popup); - opacity: 0; - transform: scale(0.2) translateX(-50%); - transform-origin: top left; - transition: var(--dialog-duration) allow-discrete; - transition-property: display, opacity, overlay, transform; - - &::backdrop { - background-color: var(--color-always-black); - opacity: 0; - transform: scale(1); - transition: var(--dialog-duration) allow-discrete; - transition-property: display, opacity, overlay; - } &[open] { display: flex; - opacity: 1; - transform: scale(1) translateX(-50%); - - &::backdrop { - opacity: 0.5; - } - } - - @starting-style { - &[open] { - opacity: 0; - transform: scale(0.2) translateX(-50%); - } - - &[open]::backdrop { - opacity: 0; - } } &.orient-left { @@ -59,10 +29,6 @@ transform: translateX(0); } - &:has(.popup__footer) { - --panel-padding: var(--block-space) var(--block-space) 0 var(--block-space); - } - form { display: contents; } @@ -196,21 +162,42 @@ } } - .popup__footer { - background-color: var(--color-canvas); - border-block-start: 1px solid var(--color-ink-lighter); - font-size: var(--text-small); - inset: auto 0 0; - line-height: 1.6; - margin-block-start: var(--block-space-half); - padding: 1.5ch; - position: sticky; - text-align: center; - z-index: 1; - } + /* Animated + /* -------------------------------------------------------------------------- */ - @keyframes safari-sticky-footer-hack { - 0% { position: absolute; } - 100% { position: sticky; } + .popup--animated { + opacity: 0; + transform: scale(0.2) translateX(-50%); + transform-origin: top left; + transition: var(--dialog-duration) allow-discrete; + transition-property: display, opacity, overlay, transform; + + &::backdrop { + background-color: var(--color-always-black); + opacity: 0; + transform: scale(1); + transition: var(--dialog-duration) allow-discrete; + transition-property: display, opacity, overlay; + } + + &[open] { + opacity: 1; + transform: scale(1) translateX(-50%); + + &::backdrop { + opacity: 0.5; + } + } + + @starting-style { + &[open] { + opacity: 0; + transform: scale(0.2) translateX(-50%); + } + + &[open]::backdrop { + opacity: 0; + } + } } } diff --git a/app/assets/stylesheets/print.css b/app/assets/stylesheets/print.css index df7f8d3a8..890e27ac3 100644 --- a/app/assets/stylesheets/print.css +++ b/app/assets/stylesheets/print.css @@ -35,8 +35,8 @@ print-color-adjust: exact; } - .boxcar-menu, - .boxcar-menu-trigger, + .nav__menu, + .nav__trigger, .header__actions { display: none; } diff --git a/app/assets/stylesheets/reactions.css b/app/assets/stylesheets/reactions.css index 664aa7941..80bde798a 100644 --- a/app/assets/stylesheets/reactions.css +++ b/app/assets/stylesheets/reactions.css @@ -29,6 +29,7 @@ } .reactions__trigger { + --btn-border-color: var(--color-ink-lightest); background-color: var(--color-ink-lightest); &:not(:hover) { @@ -38,10 +39,23 @@ } } + .reactions__trigger { + --btn-border-color: var(--reaction-border-color); + + img { + block-size: 65%; + inline-size: 65%; + } + } + .reactions__list { display: inline-flex; flex-wrap: wrap; gap: var(--inline-space-half); + + &:not(:has(.reaction)) { + display: none; + } } /* Single reaction diff --git a/app/assets/stylesheets/rich-text-content.css b/app/assets/stylesheets/rich-text-content.css index 1fa0c0759..5e871260f 100644 --- a/app/assets/stylesheets/rich-text-content.css +++ b/app/assets/stylesheets/rich-text-content.css @@ -375,6 +375,12 @@ } } + action-text-attachment[content-type^='application/vnd.actiontext.mention'] { + img { + object-fit: cover; + } + } + [data-lexical-cursor] { animation: blink 1s step-end infinite; block-size: 1lh; diff --git a/app/assets/stylesheets/utilities.css b/app/assets/stylesheets/utilities.css index 99bac2252..6ad6b2089 100644 --- a/app/assets/stylesheets/utilities.css +++ b/app/assets/stylesheets/utilities.css @@ -16,7 +16,7 @@ .txt-ink { color: var(--color-ink); } .txt-reversed { color: var(--color-ink-inverted); } .txt-negative { color: var(--color-negative); } - .txt-subtle { color: var(--color-ink-medium); } + .txt-subtle { color: var(--color-ink-dark); } .txt-alert { color: var(--color-marker); } .txt-undecorated { text-decoration: none; } .txt-underline { text-decoration: underline; } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index dc70236ef..235b9c2a0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,6 +4,7 @@ class ApplicationController < ActionController::Base include Authorization include CurrentRequest, CurrentTimezone, SetPlatform include TurboFlash, ViewTransitions + include Saas stale_when_importmap_changes allow_browser versions: :modern diff --git a/app/controllers/concerns/saas.rb b/app/controllers/concerns/saas.rb new file mode 100644 index 000000000..fd4ca8491 --- /dev/null +++ b/app/controllers/concerns/saas.rb @@ -0,0 +1,11 @@ +module Saas + extend ActiveSupport::Concern + + included do + helper_method :signups_allowed? + end + + def signups_allowed? + defined?(Signup) && defined?(saas) + end +end diff --git a/app/controllers/join_codes_controller.rb b/app/controllers/join_codes_controller.rb index f9980a8db..a4b6768b9 100644 --- a/app/controllers/join_codes_controller.rb +++ b/app/controllers/join_codes_controller.rb @@ -4,6 +4,8 @@ class JoinCodesController < ApplicationController before_action :set_join_code before_action :ensure_join_code_is_valid + layout "public" + def new @account_name = ApplicationRecord.with_tenant(tenant) { Account.sole.name } end @@ -14,7 +16,8 @@ class JoinCodesController < ApplicationController identity.memberships.find_or_create_by!(tenant: tenant) do |membership| membership.join_code = code end - identity.send_magic_link + magic_link = identity.send_magic_link + flash[:magic_link_code] = magic_link&.code if Rails.env.development? end session[:return_to_after_authenticating] = landing_url(script_name: "/#{tenant}") diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 10a3c9773..6ed69afa4 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,4 +1,9 @@ class SessionsController < ApplicationController + # FIXME: Remove this before launch! + SIGNUP_USERNAME = Rails.env.test? ? "testname" : Rails.application.credentials.account_signup_http_basic_auth.name + SIGNUP_PASSWORD = Rails.env.test? ? "testpassword" : Rails.application.credentials.account_signup_http_basic_auth.password + http_basic_authenticate_with name: SIGNUP_USERNAME, password: SIGNUP_PASSWORD, realm: "Fizzy Signup", only: :create, unless: -> { Identity.exists?(email_address: email_address) } + require_untenanted_access require_unauthenticated_access except: :destroy rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_path, alert: "Try again later." } @@ -9,8 +14,15 @@ class SessionsController < ApplicationController end def create - Identity.find_by_email_address(email_address)&.send_magic_link - redirect_to session_magic_link_path + if identity = Identity.find_by_email_address(email_address) + magic_link = identity.send_magic_link + flash[:magic_link_code] = magic_link&.code if Rails.env.development? + redirect_to session_magic_link_path + elsif signups_allowed? + Signup.new(email_address: email_address).create_identity + session[:return_to_after_authenticating] = saas.new_signup_membership_path + redirect_to session_magic_link_path + end end def destroy diff --git a/app/controllers/users/joins_controller.rb b/app/controllers/users/joins_controller.rb index d811a6203..73a9ae296 100644 --- a/app/controllers/users/joins_controller.rb +++ b/app/controllers/users/joins_controller.rb @@ -3,6 +3,8 @@ class Users::JoinsController < ApplicationController before_action :set_join_code, :ensure_join_code_is_valid + layout "public" + def new end diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index 3dccac678..f572434ec 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -19,6 +19,16 @@ module AvatarsHelper end end + def mail_avatar_tag(user, size: 48, **options) + if user.avatar.attached? + image_tag user_avatar_url(user), alt: user.name, class: "avatar", size: size, **options + else + tag.span class: "avatar", style: "background-color: #{avatar_background_color(user)};" do + user.initials + end + end + end + def avatar_preview_tag(user, hidden_for_screen_reader: false, **options) tag.span class: class_names("avatar", options.delete(:class)), aria: { hidden: hidden_for_screen_reader, label: user.name }, diff --git a/app/javascript/controllers/dialog_controller.js b/app/javascript/controllers/dialog_controller.js index 16204bd28..4fbf25dc5 100644 --- a/app/javascript/controllers/dialog_controller.js +++ b/app/javascript/controllers/dialog_controller.js @@ -24,6 +24,7 @@ export default class extends Controller { limitHeightToViewport(this.dialogTarget, true) + this.#loadLazyFrames() this.dialogTarget.setAttribute("aria-hidden", "false") this.dispatch("show") } @@ -54,4 +55,8 @@ export default class extends Controller { event.stopPropagation() } } + + #loadLazyFrames() { + Array.from(this.dialogTarget.querySelectorAll("turbo-frame")).forEach(frame => { frame.loading = "eager" }) + } } diff --git a/app/javascript/controllers/dialog_manager_controller.js b/app/javascript/controllers/dialog_manager_controller.js new file mode 100644 index 000000000..71552e2c8 --- /dev/null +++ b/app/javascript/controllers/dialog_manager_controller.js @@ -0,0 +1,24 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + this.element.addEventListener("dialog:show", this.handleDialogShow.bind(this)) + } + + disconnect() { + this.element.removeEventListener("dialog:show", this.handleDialogShow.bind(this)) + } + + handleDialogShow(event) { + this.#dialogControllers.forEach(dialogController => { + if (dialogController !== event.target) { + const dialog = dialogController.querySelector("dialog") + dialog.removeAttribute("open") + } + }) + } + + get #dialogControllers() { + return this.element.querySelectorAll('[data-controller~="dialog"]') + } +} diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 4e7878b62..884e0d240 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,5 +1,5 @@ class ApplicationMailer < ActionMailer::Base - default from: "The Fizzy team " + default from: "Fizzy " layout "mailer" append_view_path Rails.root.join("app/views/mailers") diff --git a/app/mailers/magic_link_mailer.rb b/app/mailers/magic_link_mailer.rb index 391e64f6d..f23cc4fbf 100644 --- a/app/mailers/magic_link_mailer.rb +++ b/app/mailers/magic_link_mailer.rb @@ -3,7 +3,7 @@ class MagicLinkMailer < ApplicationMailer @magic_link = magic_link @identity = @magic_link.identity - mail to: @identity.email_address, subject: "Sign in to Fizzy" + mail to: @identity.email_address, subject: "Your Fizzy verification code" end private diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb deleted file mode 100644 index 09926c09b..000000000 --- a/app/mailers/user_mailer.rb +++ /dev/null @@ -1,8 +0,0 @@ -class UserMailer < ApplicationMailer - def email_change_confirmation(user:, email_address:, token:) - @user = user - @token = token - - mail to: email_address, subject: "Confirm your new email address" - end -end diff --git a/app/models/board/accessible.rb b/app/models/board/accessible.rb index 6d62c0b21..75b2e982e 100644 --- a/app/models/board/accessible.rb +++ b/app/models/board/accessible.rb @@ -45,6 +45,7 @@ module Board::Accessible mentions_for_user(user).destroy_all notifications_for_user(user).destroy_all + watches_for(user).destroy_all end def watchers @@ -89,4 +90,8 @@ module Board::Accessible (notifications.source_type = 'Event' AND events.eventable_type = 'Comment' AND event_comment_cards.board_id = ?)", id, id) end + + def watches_for(user) + Watch.where(card: cards, user: user) + end end diff --git a/app/models/identity.rb b/app/models/identity.rb index f5daf3be1..99c90271f 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -5,7 +5,7 @@ class Identity < UntenantedRecord has_many :magic_links, dependent: :destroy has_many :sessions, dependent: :destroy - normalizes :email_address, with: ->(value) { value.strip.downcase } + normalizes :email_address, with: ->(value) { value.strip.downcase.presence } def send_magic_link magic_links.create!.tap do |magic_link| diff --git a/app/views/boards/edit.html.erb b/app/views/boards/edit.html.erb index 206bc5ed5..45edcfbc6 100644 --- a/app/views/boards/edit.html.erb +++ b/app/views/boards/edit.html.erb @@ -33,6 +33,6 @@
<%= render "boards/edit/auto_close", board: @board %> <%= render "boards/edit/publication", board: @board %> - <%= render "boards/edit/delete", board: @board %> + <%= render "boards/edit/delete", board: @board if Current.user.can_administer_card?(@board) %>
diff --git a/app/views/cards/comments/reactions/_reactions.html.erb b/app/views/cards/comments/reactions/_reactions.html.erb index bf3ff746a..6de217842 100644 --- a/app/views/cards/comments/reactions/_reactions.html.erb +++ b/app/views/cards/comments/reactions/_reactions.html.erb @@ -6,7 +6,7 @@ <%= turbo_frame_tag comment, :new_reaction do %> <%= link_to new_card_comment_reaction_path(comment.card, comment), role: "button", - class: "reactions__trigger btn btn--circle borderless", action: "soft-keyboard#open", + class: "reactions__trigger btn btn--circle", action: "soft-keyboard#open", data: { turbo_frame: dom_id(comment, :new_reaction), action: "dialog#close" } do %> <%= image_tag "boost-color.svg", aria: { hidden: true } %> Add your own reaction diff --git a/app/views/cards/display/perma/_assignees.html.erb b/app/views/cards/display/perma/_assignees.html.erb index a115f39b2..1292573d4 100644 --- a/app/views/cards/display/perma/_assignees.html.erb +++ b/app/views/cards/display/perma/_assignees.html.erb @@ -1,3 +1,3 @@ <%= render "cards/display/common/assignees", card: card do %> - <%= turbo_frame_tag card, :assignment, src: new_card_assignment_path(card), refresh: "morph" %> + <%= turbo_frame_tag card, :assignment, src: new_card_assignment_path(card), loading: :lazy, refresh: "morph" %> <% end %> diff --git a/app/views/cards/display/perma/_board.html.erb b/app/views/cards/display/perma/_board.html.erb index f816683b9..e78a33579 100644 --- a/app/views/cards/display/perma/_board.html.erb +++ b/app/views/cards/display/perma/_board.html.erb @@ -6,7 +6,7 @@ - <%= turbo_frame_tag "board_picker", src: edit_card_board_path(card), target: "_top", refresh: "morph" %> + <%= turbo_frame_tag "board_picker", src: edit_card_board_path(card), target: "_top", loading: :lazy, refresh: "morph" %> <% end %> diff --git a/app/views/cards/display/perma/_tags.html.erb b/app/views/cards/display/perma/_tags.html.erb index 015f7990a..b618ada12 100644 --- a/app/views/cards/display/perma/_tags.html.erb +++ b/app/views/cards/display/perma/_tags.html.erb @@ -1,12 +1,16 @@
-
> - - - <%= turbo_frame_tag card, :tagging, src: new_card_tagging_path(card), refresh: "morph" %> + + <%= turbo_frame_tag card, :tagging, src: new_card_tagging_path(card), loading: :lazy, refresh: :morph %>
diff --git a/app/views/filters/_settings.html.erb b/app/views/filters/_settings.html.erb index ae604011c..52137b5de 100644 --- a/app/views/filters/_settings.html.erb +++ b/app/views/filters/_settings.html.erb @@ -1,7 +1,7 @@ <%= tag.aside \ class: class_names("filters margin-block-end", { "filters--expanded": user_filtering.expanded? }), data: { - controller: "toggle-enable toggle-class filter-settings", + controller: "toggle-enable toggle-class filter-settings dialog-manager", toggle_class_toggle_class: "filters--expanded", filter_settings_filters_set_class: "filters--has-filters-set", filter_settings_no_filtering_url_value: no_filtering_url, diff --git a/app/views/filters/settings/_assignees.html.erb b/app/views/filters/settings/_assignees.html.erb index 996116d63..0a60a4878 100644 --- a/app/views/filters/settings/_assignees.html.erb +++ b/app/views/filters/settings/_assignees.html.erb @@ -1,5 +1,5 @@ <% filter = user_filtering.filter %> -<%= tag.div class: "quick-filter position-relative", +<%= tag.div class: "quick-filter", data: { controller: "dialog multi-selection-combobox", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", diff --git a/app/views/filters/settings/_boards.html.erb b/app/views/filters/settings/_boards.html.erb index 5caf96d65..97a21618d 100644 --- a/app/views/filters/settings/_boards.html.erb +++ b/app/views/filters/settings/_boards.html.erb @@ -1,6 +1,6 @@ <% filter = user_filtering.filter %> -<%= tag.div class: "quick-filter position-relative", +<%= tag.div class: "quick-filter", data: { controller: "dialog multi-selection-combobox", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", diff --git a/app/views/filters/settings/_closers.html.erb b/app/views/filters/settings/_closers.html.erb index 5da789245..24e542b1e 100644 --- a/app/views/filters/settings/_closers.html.erb +++ b/app/views/filters/settings/_closers.html.erb @@ -1,6 +1,6 @@ <% filter = user_filtering.filter %> -<%= tag.div class: "quick-filter position-relative", +<%= tag.div class: "quick-filter", data: { controller: "dialog multi-selection-combobox", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", diff --git a/app/views/filters/settings/_creators.html.erb b/app/views/filters/settings/_creators.html.erb index 92385f7a2..8453fe745 100644 --- a/app/views/filters/settings/_creators.html.erb +++ b/app/views/filters/settings/_creators.html.erb @@ -1,6 +1,6 @@ <% filter = user_filtering.filter %> -<%= tag.div class: "quick-filter position-relative", +<%= tag.div class: "quick-filter", data: { controller: "dialog multi-selection-combobox", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", diff --git a/app/views/filters/settings/_indexed_by.html.erb b/app/views/filters/settings/_indexed_by.html.erb index 48bf476da..8175fea9e 100644 --- a/app/views/filters/settings/_indexed_by.html.erb +++ b/app/views/filters/settings/_indexed_by.html.erb @@ -1,6 +1,6 @@ <% filter = user_filtering.filter %> -<%= tag.div class: class_names("quick-filter position-relative"), +<%= tag.div class: class_names("quick-filter"), data: { controller: "dialog combobox", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_indexed_by?, diff --git a/app/views/filters/settings/_sorted_by.html.erb b/app/views/filters/settings/_sorted_by.html.erb index 5379cfd17..e5c0adc4e 100644 --- a/app/views/filters/settings/_sorted_by.html.erb +++ b/app/views/filters/settings/_sorted_by.html.erb @@ -1,6 +1,6 @@ <% filter = user_filtering.filter %> -<%= tag.div class: class_names("quick-filter position-relative"), +<%= tag.div class: class_names("quick-filter"), data: { controller: "dialog combobox", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", diff --git a/app/views/filters/settings/_time_window.html.erb b/app/views/filters/settings/_time_window.html.erb index cfc827ecc..b747384ac 100644 --- a/app/views/filters/settings/_time_window.html.erb +++ b/app/views/filters/settings/_time_window.html.erb @@ -1,5 +1,5 @@ <% filter = user_filtering.filter %> -<%= tag.div class: "quick-filter position-relative", +<%= tag.div class: "quick-filter", data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: filter.public_send("#{name}_window").present? } do %> <% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 31a162329..5a364182e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -5,7 +5,7 @@ diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb index 5e3c6e69f..cd7502ec1 100644 --- a/app/views/layouts/mailer.html.erb +++ b/app/views/layouts/mailer.html.erb @@ -43,27 +43,29 @@ width: 100% !important; } - .avatar { - border-radius: 50%; - height: 2.75em; - margin-right: 0.2.75em; - max-height: 2.75em; - min-height: 2.75em; - overflow: hidden; - width: 2.75em; - } - .avatar__container { - padding-top: 1em; vertical-align: top; width: 3.25em; } + .avatar { + border-radius: 50%; + color: white; + display: block; + font-weight: 600; + height: 2.75em; + line-height: 2.75em; + mso-line-height-rule: exactly; + overflow: hidden; + text-align: center; + width: 2.75em; + } + .btn { background: #2d71e5; border-color: #2d71e5; border-radius: 3rem; - color: #ffffff; + color: white !important; font-weight: 500; padding: 0.5em 1em; text-decoration: none; diff --git a/app/views/layouts/public.html.erb b/app/views/layouts/public.html.erb index c217f44bb..f2843d978 100644 --- a/app/views/layouts/public.html.erb +++ b/app/views/layouts/public.html.erb @@ -1,16 +1,18 @@ - + <%= render "layouts/shared/head" %>
diff --git a/app/views/layouts/shared/_head.html.erb b/app/views/layouts/shared/_head.html.erb index 997bc48db..fd4b7cab7 100644 --- a/app/views/layouts/shared/_head.html.erb +++ b/app/views/layouts/shared/_head.html.erb @@ -1,8 +1,7 @@ <%= page_title_tag %> - - + <% unless @disable_view_transition %> <% end %> diff --git a/app/views/mailers/identity_mailer/email_change_confirmation.html.erb b/app/views/mailers/identity_mailer/email_change_confirmation.html.erb index 438dc18e9..dd55d602e 100644 --- a/app/views/mailers/identity_mailer/email_change_confirmation.html.erb +++ b/app/views/mailers/identity_mailer/email_change_confirmation.html.erb @@ -1,5 +1,4 @@ -

Confirm your email address change

-

Hit the button below to use this email address in Fizzy.

+

Confirm your email address change

<%= link_to "Yes use use this email address", email_address_confirmation_url(membership_id: @membership.id, email_address_token: @token), class: "btn" %> diff --git a/app/views/mailers/magic_link_mailer/sign_in_instructions.html.erb b/app/views/mailers/magic_link_mailer/sign_in_instructions.html.erb index b966ecfa6..82f4049cc 100644 --- a/app/views/mailers/magic_link_mailer/sign_in_instructions.html.erb +++ b/app/views/mailers/magic_link_mailer/sign_in_instructions.html.erb @@ -1,11 +1,13 @@ -

Sign in to Fizzy

-

Hit the button below to sign in to Fizzy on this device

-<%= link_to "Sign in to Fizzy", session_magic_link_url(code: @magic_link.code), class: "btn" %> +<% if @identity.memberships.any? %> +

Fizzy verification code

+

Please enter this 6-character verification code on the Fizzy sign-in page:

+<% else %> +

Welcome to Fizzy!

+

Please enter this 6-character verification code on the Fizzy sign-up page to create your new account:

+<% end %> -

If you’re signing in on another device, enter this special code: -
<%= @magic_link.code %> -

+<%= @magic_link.code %> diff --git a/app/views/mailers/magic_link_mailer/sign_in_instructions.text.erb b/app/views/mailers/magic_link_mailer/sign_in_instructions.text.erb index f44e1c908..2de3e5533 100644 --- a/app/views/mailers/magic_link_mailer/sign_in_instructions.text.erb +++ b/app/views/mailers/magic_link_mailer/sign_in_instructions.text.erb @@ -1,8 +1,7 @@ -Sign in to Fizzy -<%= "=" * 80 %> +<% if @identity.memberships.any? %> +Please enter this 6-character verification code on the Fizzy sign-in page: +<% else %> +Please enter this 6-character verification code on the Fizzy sign-up page to create your new account: +<% end %> -Open this link in your browser to login on this device: -<%= session_magic_link_url(code: @magic_link.code) %> - -If you're signing in on another device, enter this code: <%= @magic_link.code %> diff --git a/app/views/mailers/notification/bundle_mailer/_notification.html.erb b/app/views/mailers/notification/bundle_mailer/_notification.html.erb index 5dfddcf31..543f1515c 100644 --- a/app/views/mailers/notification/bundle_mailer/_notification.html.erb +++ b/app/views/mailers/notification/bundle_mailer/_notification.html.erb @@ -1,8 +1,15 @@ - + + + + + diff --git a/app/views/memberships/email_addresses/new.html.erb b/app/views/memberships/email_addresses/new.html.erb index f88456679..e99596471 100644 --- a/app/views/memberships/email_addresses/new.html.erb +++ b/app/views/memberships/email_addresses/new.html.erb @@ -13,7 +13,7 @@

<%= @page_title %>

-

Enter your new email address. We'll send you a confirmation to verify it.

+

Enter your new email address, then hit the link to confirm it

<%= form_with url: email_addresses_path(membership_id: @membership.id), method: :post, class: "flex flex-column gap", data: { controller: "form", turbo: false } do |form| %> @@ -23,8 +23,8 @@ - <% end %> diff --git a/app/views/my/menus/_button.html.erb b/app/views/my/menus/_button.html.erb index 85b2c9a93..3f8162624 100644 --- a/app/views/my/menus/_button.html.erb +++ b/app/views/my/menus/_button.html.erb @@ -1,4 +1,4 @@ -<%= tag.button class:"boxcar-menu-trigger input input--select center flex-inline align-center txt-normal", +<%= tag.button class:"nav__trigger input input--select center flex-inline align-center txt-normal", data: { action: "click->dialog#open:stop keydown.j@document->hotkey#click keydown.meta+j@document->hotkey#click keydown.ctrl+j@document->hotkey#click", controller: "hotkey" } do %> diff --git a/app/views/my/menus/_footer.html.erb b/app/views/my/menus/_footer.html.erb index 9bcea3d54..4a28550a5 100644 --- a/app/views/my/menus/_footer.html.erb +++ b/app/views/my/menus/_footer.html.erb @@ -1,3 +1,3 @@ -
+
Fizzy™ is designed, built, and backed by <%= icon_tag "37signals", class: "v-align-middle" %> 37signals™
diff --git a/app/views/my/menus/_hotkeys.html.erb b/app/views/my/menus/_hotkeys.html.erb index 198f766f9..4b1792fbb 100644 --- a/app/views/my/menus/_hotkeys.html.erb +++ b/app/views/my/menus/_hotkeys.html.erb @@ -1,4 +1,4 @@ -
+
<%= image_tag user_avatar_url(notification.creator), alt: notification.creator.name, class: "avatar", size: 48 %>  <%= render "notification/bundle_mailer/header", notification: notification %> +
+ <%= mail_avatar_tag(notification.creator) %> + <%= render "notification/bundle_mailer/#{notification.source_type.underscore}/body", notification: notification %>