diff --git a/app/assets/stylesheets/card-columns.css b/app/assets/stylesheets/card-columns.css index 022201a26..0b193b0d5 100644 --- a/app/assets/stylesheets/card-columns.css +++ b/app/assets/stylesheets/card-columns.css @@ -96,6 +96,7 @@ border-color: var(--card-color) !important; border-style: dashed !important; + box-shadow: none !important; } .card__background { diff --git a/app/assets/stylesheets/card-perma.css b/app/assets/stylesheets/card-perma.css index af825bb32..4f25c7810 100644 --- a/app/assets/stylesheets/card-perma.css +++ b/app/assets/stylesheets/card-perma.css @@ -100,7 +100,7 @@ z-index: 1; } - .btn:not(.popup__item, .btn--plain) { + .btn:not(.popup__item, .btn--plain, .btn--reversed) { --btn-background: var(--card-color); --btn-color: var(--color-ink-reversed); } @@ -110,6 +110,11 @@ text-decoration: underline; } + + .btn--reversed { + --btn-background: var(--color-bg); + --btn-color: var(--card-color); + } } .card-perma__closure-message { @@ -119,29 +124,4 @@ padding-left: 1ch; } } - - /* Variants - /* ------------------------------------------------------------------------ */ - - .card-perma--pointing { - --arrow-size: 20em; - --aspect-ratio: 7; - - position: relative; - margin-block-end: calc(var(--arrow-size) / var(--aspect-ratio)); - - &::after { - aspect-ratio: var(--aspect-ratio); - background-color: var(--color-container); - clip-path: polygon(50% 100%, 100% 0, 0 0); - inline-size: var(--arrow-size); - content: ""; - display: block; - inset-block-start: 99%; - inset-inline-start: 50%; - position: absolute; - transform: translateX(-50%); - z-index: -1; - } - } } diff --git a/app/assets/stylesheets/cards.css b/app/assets/stylesheets/cards.css index 6f869df5c..4be6b06ed 100644 --- a/app/assets/stylesheets/cards.css +++ b/app/assets/stylesheets/cards.css @@ -99,18 +99,42 @@ padding-block: var(--card-padding-block); } + .card__description { + house-md-toolbar, + .house-md-content { + color: color-mix(in srgb, var(--card-color) 40%, var(--color-ink)); + } + + .house-md-content { + min-block-size: 3lh; + padding: var(--block-space-half) var(--inline-space) 0 0; + } + + & ~ .btn { + --btn-background: var(--card-color); + --btn-color: var(--color-ink-reversed); + } + } + .card__title { --hover-size: 0; --input-border-radius: 0; + --input-color: color-mix(in srgb, var(--card-color) 40%, var(--color-ink)); + --lines: 3; + color: inherit; flex: 2 1 75%; font-size: var(--text-xx-large); font-weight: 900; - line-height: 1.1; + line-height: 1.2; min-block-size: 3lh; text-wrap: balance; - .card__title-field { + .card-perma__bg & { + min-block-size: unset; + } + + .card-field__title { &:is(textarea)::placeholder { color: inherit; opacity: 0.5; @@ -118,8 +142,6 @@ } .card__title-link { - --lines: 3; - color: inherit; } } @@ -130,11 +152,11 @@ flex-direction: column; max-width: 100%; min-width: 0; - padding-block: var(--block-space); + padding-block: var(--block-space-half); } .card__move-button { - --btn-background: color-mix(in srgb, var(--card-color) 40%, var(--color-ink)); + --btn-background: color-mix(in srgb, inherit 40%, var(--color-ink)); margin-block-start: calc(var(--block-space) * 1.2); margin-inline-end: calc(var(--inline-space) * -4); diff --git a/app/assets/stylesheets/comments.css b/app/assets/stylesheets/comments.css index 2db3016db..5ac91e94e 100644 --- a/app/assets/stylesheets/comments.css +++ b/app/assets/stylesheets/comments.css @@ -68,6 +68,7 @@ padding: var(--comment-padding-block) var(--comment-padding-inline); + word-wrap: break-word; } .comment__edit { diff --git a/app/assets/stylesheets/house.css b/app/assets/stylesheets/house.css index 30982ad76..e1ce84325 100644 --- a/app/assets/stylesheets/house.css +++ b/app/assets/stylesheets/house.css @@ -58,7 +58,6 @@ /* Markdown Content */ .house-md-content { - caret-color: var(--color-link); flex-grow: 1; font-family: var(--font-sans); text-align: left; @@ -67,7 +66,7 @@ &.house-md-content-empty::before { content: attr(placeholder); - color: var(--color-ink); + color: currentColor; opacity: 0.5; pointer-events: none; display: block; diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index eacc517b6..d535f26d9 100644 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -54,7 +54,7 @@ class CardsController < ApplicationController end def card_params - params.expect(card: [ :status, :title, :color, :due_on, :image, :draft_comment, tag_ids: [] ]) + params.expect(card: [ :status, :title, :description, :image, tag_ids: [] ]) end def render_card_replacement diff --git a/app/helpers/cards_helper.rb b/app/helpers/cards_helper.rb index 028a4e715..31c370479 100644 --- a/app/helpers/cards_helper.rb +++ b/app/helpers/cards_helper.rb @@ -19,7 +19,8 @@ module CardsHelper classes = [ options.delete(:class), ("card--golden" if card.golden?), - ("card--doing" if card.doing?) + ("card--doing" if card.doing?), + ("card--drafted" if card.drafted?) ].compact.join(" ") tag.article \ diff --git a/app/models/card.rb b/app/models/card.rb index 7237e1f58..541d761a9 100644 --- a/app/models/card.rb +++ b/app/models/card.rb @@ -1,5 +1,5 @@ class Card < ApplicationRecord - include Assignable, Colored, DraftCommenting, Engageable, Eventable, Golden, + include Assignable, Colored, Engageable, Eventable, Golden, Messages, Notifiable, Pinnable, Closeable, Searchable, Staged, Statuses, Taggable, Watchable @@ -10,6 +10,8 @@ class Card < ApplicationRecord has_one_attached :image, dependent: :purge_later + has_markdown :description + scope :reverse_chronologically, -> { order created_at: :desc, id: :desc } scope :chronologically, -> { order created_at: :asc, id: :asc } scope :latest, -> { order updated_at: :desc, id: :desc } diff --git a/app/models/card/draft_commenting.rb b/app/models/card/draft_commenting.rb deleted file mode 100644 index 615d23916..000000000 --- a/app/models/card/draft_commenting.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Card::DraftCommenting - extend ActiveSupport::Concern - - included do - after_save :capture_draft_comment - end - - def draft_comment - find_or_build_initial_comment.body.content - end - - def draft_comment=(body) - if body.present? - @draft_comment = body - else - messages.comments.destroy_all - end - end - - private - def find_or_build_initial_comment - message = messages.comments.first || messages.new(messageable: Comment.new) - message.comment - end - - def capture_draft_comment - if @draft_comment.present? - find_or_build_initial_comment.update! body: @draft_comment, creator: creator - end - - @draft_comment = nil - end -end diff --git a/app/models/card/searchable.rb b/app/models/card/searchable.rb index 3627a555b..2e01fef9b 100644 --- a/app/models/card/searchable.rb +++ b/app/models/card/searchable.rb @@ -4,7 +4,7 @@ module Card::Searchable included do include ::Searchable - searchable_by :title, using: :cards_search_index + searchable_by :title_and_description, using: :cards_search_index, as: :title scope :mentioning, ->(query) do if query = sanitize_query_syntax(query) @@ -18,25 +18,31 @@ module Card::Searchable end end - class_methods do - def sanitize_query_syntax(terms) - terms = terms.to_s - terms = remove_invalid_search_characters(terms) - terms = remove_unbalanced_quotes(terms) - terms.presence + class_methods do + def sanitize_query_syntax(terms) + terms = terms.to_s + terms = remove_invalid_search_characters(terms) + terms = remove_unbalanced_quotes(terms) + terms.presence + end + + private + def remove_invalid_search_characters(terms) + terms.gsub(/[^\w"]/, " ") end - private - def remove_invalid_search_characters(terms) - terms.gsub(/[^\w"]/, " ") + def remove_unbalanced_quotes(terms) + if terms.count("\"").even? + terms + else + terms.gsub("\"", " ") end + end + end - def remove_unbalanced_quotes(terms) - if terms.count("\"").even? - terms - else - terms.gsub("\"", " ") - end - end + private + # TODO: Temporary until we stabilize the search API + def title_and_description + [ title, description.to_plain_text ].join(" ") end end diff --git a/app/views/cards/_container.html.erb b/app/views/cards/_container.html.erb index 9c2d11aaf..034106e59 100644 --- a/app/views/cards/_container.html.erb +++ b/app/views/cards/_container.html.erb @@ -1,8 +1,9 @@
" style="--card-color: <%= card.color %>;"> + class="card-perma" style="--card-color: <%= card.color %>;"> <%= render "cards/container/engagement", card: card %>
diff --git a/app/views/cards/_description_as_draft_comment.html.erb b/app/views/cards/_description_as_draft_comment.html.erb deleted file mode 100644 index 5e7a1cd71..000000000 --- a/app/views/cards/_description_as_draft_comment.html.erb +++ /dev/null @@ -1,29 +0,0 @@ -
-
- - -
-
-
- <%= tag.house_md card.draft_comment, name: "card[draft_comment]", class: "input comment__input", - form: "card_form", - placeholder: new_comment_placeholder(card), - data: { action: "house-md:change->outlet-auto-save#change focusout->outlet-auto-save#submit", uploads_url: uploads_url(format: "json") } %> -
- - <% if card.creating? %> -
- <%= button_to "Create card", card_publish_path(card), class: "btn btn--reversed" %> - <%= button_to "Save as draft", collection_card_path(card.collection, card), name: "card[status]", value: "drafted", method: :put, class: "btn" %> -
- <% end %> -
-
-
-
- diff --git a/app/views/cards/container/_closure.html.erb b/app/views/cards/container/_closure.html.erb index 661b8edea..e9006f3aa 100644 --- a/app/views/cards/container/_closure.html.erb +++ b/app/views/cards/container/_closure.html.erb @@ -1,4 +1,4 @@ -
+
<% if card.closed? %>
Completed by <%= card.closed_by.name %> on <%= local_datetime_tag(card.closed_at, style: :shortdate) %>. diff --git a/app/views/cards/container/_edit.html.erb b/app/views/cards/container/_edit.html.erb new file mode 100644 index 000000000..23ea9f48d --- /dev/null +++ b/app/views/cards/container/_edit.html.erb @@ -0,0 +1,4 @@ +<%= link_to edit_collection_card_path(card.collection, card), class: "btn", data: { turbo_frame: dom_id(card, :edit) } do %> + <%= icon_tag "pencil" %> + Edit +<% end %> diff --git a/app/views/cards/container/_title.html.erb b/app/views/cards/container/_title.html.erb index b62eb2fb4..a959e888f 100644 --- a/app/views/cards/container/_title.html.erb +++ b/app/views/cards/container/_title.html.erb @@ -1,14 +1,27 @@ -

- <% if card.published? %> - <%= turbo_frame_tag card, :edit do %> - <%= link_to card.title, edit_collection_card_path(card.collection, card), class: "card__title-link overflow-line-clamp" %> - <% end %> - <% else %> - <%= form_with model: card, url: collection_card_path(card.collection, card), id: "card_form", data: { controller: "auto-save" } do |form| %> +<% if card.published? %> + <%= turbo_frame_tag card, :edit do %> +
+

+ <%= link_to card.title, edit_collection_card_path(card.collection, card), class: "card__title-link" %> +

+

+ <%= sanitize card.description_html %> +

+
+ <% end %> +<% else %> + <%= form_with model: card, url: collection_card_path(card.collection, card), id: "card_form", class: "full-width", data: { controller: "auto-save" } do |form| %> +

<%= form.text_area :title, placeholder: "Name it…", - class: "input input--textarea full-width borderless txt-align-start #{ "fill-highlight" if card.creating? }", + class: "input input--textarea full-width borderless txt-align-start", autofocus: card.title.blank?, data: { action: "auto-save#change blur->auto-save#submit keydown.enter->auto-save#submit:prevent keydown.ctrl+enter->auto-save#submit:prevent" } %> - <% end %> +

+
+ <%= form.markdown_area :description, class: "input input--textarea full-width borderless txt-align-start card-field__description", + placeholder: "Add some notes, context, pictures, or video about this…", + data: { action: "keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop paste->paste#pasteFiles" } %> +
+ <%= form.button "Save changes", type: :submit, class: "btn"%> <% end %> - +<% end %> \ No newline at end of file diff --git a/app/views/cards/container/footer/_draft.html.erb b/app/views/cards/container/footer/_draft.html.erb new file mode 100644 index 000000000..f46e08b41 --- /dev/null +++ b/app/views/cards/container/footer/_draft.html.erb @@ -0,0 +1,4 @@ +
+ <%= button_to "Create card", card_publish_path(card), class: "btn" %> + <%= button_to "Save as draft", collection_card_path(card.collection, card), name: "card[status]", value: "drafted", method: :put, class: "btn btn--reversed" %> +
diff --git a/app/views/cards/container/footer/_published.html.erb b/app/views/cards/container/footer/_published.html.erb new file mode 100644 index 000000000..c4e0a0cdf --- /dev/null +++ b/app/views/cards/container/footer/_published.html.erb @@ -0,0 +1,7 @@ +<%# FIXME: Let's move this aside outside of the card container section so these frames don't reload/flicker when card is replaced %> + + +<%= render "cards/container/closure", card: card %> diff --git a/app/views/cards/display/_preview.html.erb b/app/views/cards/display/_preview.html.erb index e1ed5b946..43284b534 100644 --- a/app/views/cards/display/_preview.html.erb +++ b/app/views/cards/display/_preview.html.erb @@ -6,8 +6,8 @@
-

- <%= card.title %> +

+ <%= card.title %>

<%= link_to collection_card_path(card.collection, card), class: "card__link" do %> diff --git a/app/views/cards/display/common/_assignees.html.erb b/app/views/cards/display/common/_assignees.html.erb index 7cfa48447..c89cdcc57 100644 --- a/app/views/cards/display/common/_assignees.html.erb +++ b/app/views/cards/display/common/_assignees.html.erb @@ -4,7 +4,7 @@ <% end %>
> - diff --git a/app/views/cards/display/perma/_tags.html.erb b/app/views/cards/display/perma/_tags.html.erb index cecde410e..46e66c56e 100644 --- a/app/views/cards/display/perma/_tags.html.erb +++ b/app/views/cards/display/perma/_tags.html.erb @@ -12,7 +12,7 @@
> - diff --git a/app/views/cards/edit.html.erb b/app/views/cards/edit.html.erb index 5e5e0d1d9..ad509b0e0 100644 --- a/app/views/cards/edit.html.erb +++ b/app/views/cards/edit.html.erb @@ -1,13 +1,19 @@ <%= turbo_frame_tag @card, :edit do %> - <%= form_with model: @card, url: collection_card_path(@card.collection, @card), class: "flex flex-column gap full-width", data: { controller: "form" } do |form| %> - <%= form.label :title, class: "flex flex-column align-center" do %> - <%= form.text_area :title, class: "input input--textarea full-width borderless txt-align-start card__title-field", - required: true, autofocus: true, placeholder: "Name it…", - rows: 3, - data: { action: "keydown.enter->form#submit:prevent keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel focus->form#select" }, - style: "color: var(--spat-color); --input-border-radius: 0" %> - <% end %> - <%= form.button "Save", type: :submit, hidden: true %> + <%= form_with model: @card, url: collection_card_path(@card.collection, @card), class: "full-width", data: { controller: "form paste" } do |form| %> +

+ <%= form.label :title, class: "flex flex-column align-center" do %> + <%= form.text_area :title, class: "input input--textarea full-width borderless txt-align-start card-field__title", + required: true, autofocus: true, placeholder: "Name it…", + rows: 1, + data: { action: "keydown.enter->form#submit:prevent keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel focus->form#select" } %> + <% end %> +

+
+ <%= form.markdown_area :description, class: "input input--textarea full-width borderless txt-align-start card-field__description", + placeholder: "Add some notes, context, pictures, or video about this…", + data: { action: "keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop paste->paste#pasteFiles" } %> +
+ <%= form.button "Save changes", type: :submit, class: "btn"%> <%= link_to "Close editor and discard changes", collection_card_path(@card.collection, @card), data: { form_target: "cancel" }, hidden: true %> <% end %> <% end %> diff --git a/app/views/cards/show.html.erb b/app/views/cards/show.html.erb index df993c968..56ca920bb 100644 --- a/app/views/cards/show.html.erb +++ b/app/views/cards/show.html.erb @@ -34,7 +34,5 @@ <% if @card.published? %> <%= render "cards/messages", card: @card %> - <% else %> - <%= render "cards/description_as_draft_comment", card: @card %> <% end %>
diff --git a/test/controllers/cards_controller_test.rb b/test/controllers/cards_controller_test.rb index 5272dc182..5cb3a6582 100644 --- a/test/controllers/cards_controller_test.rb +++ b/test/controllers/cards_controller_test.rb @@ -36,19 +36,17 @@ class CardsControllerTest < ActionDispatch::IntegrationTest patch collection_card_path(collections(:writebook), cards(:logo)), params: { card: { title: "Logo needs to change", - due_on: 1.week.from_now, image: fixture_file_upload("moon.jpg", "image/jpeg"), - draft_comment: "Something more in-depth", + description: "Something more in-depth", tag_ids: [ tags(:mobile).id ] } } assert_response :success card = cards(:logo).reload assert_equal "Logo needs to change", card.title - assert_equal 1.week.from_now.to_date, card.due_on assert_equal "moon.jpg", card.image.filename.to_s assert_equal [ tags(:mobile) ], card.tags - assert_equal "Something more in-depth", card.messages.comments.first.comment.body_plain_text.strip + assert_equal "Something more in-depth", card.description_plain_text.strip end test "users can only see cards in collections they have access to" do diff --git a/test/models/card/messages_test.rb b/test/models/card/messages_test.rb index 08ade7f0f..31d730306 100644 --- a/test/models/card/messages_test.rb +++ b/test/models/card/messages_test.rb @@ -6,41 +6,4 @@ class Card::MessagesTest < ActiveSupport::TestCase assert_empty card.messages end - - test "creating a card with an initial draft comment" do - card = collections(:writebook).cards.create! creator: users(:kevin), title: "New", - draft_comment: "This is a comment" - - assert_equal 1, card.messages.count - assert_equal "This is a comment", card.draft_comment.strip - end - - test "updating the draft comment" do - card = collections(:writebook).cards.create! creator: users(:kevin), title: "New", - draft_comment: "This is a comment" - - card.update! draft_comment: "This is an updated comment" - - assert_equal 1, card.messages.count - assert_equal "This is an updated comment", card.draft_comment.strip - end - - test "setting the draft comment to be blank removes it" do - card = collections(:writebook).cards.create! creator: users(:kevin), title: "New", - draft_comment: "This is a comment" - - card.update! draft_comment: " " - - assert card.messages.first.nil? - end - - test "omitting the draft comment does not remove it" do - card = collections(:writebook).cards.create! creator: users(:kevin), title: "New", - draft_comment: "This is a comment" - - card.update! title: "Newer" - - assert_equal 1, card.messages.count - assert_equal "This is a comment", card.draft_comment.strip - end end