diff --git a/app/assets/stylesheets/card-columns.css b/app/assets/stylesheets/card-columns.css
index 0b193b0d5..022201a26 100644
--- a/app/assets/stylesheets/card-columns.css
+++ b/app/assets/stylesheets/card-columns.css
@@ -96,7 +96,6 @@
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 4f25c7810..af825bb32 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--reversed) {
+ .btn:not(.popup__item, .btn--plain) {
--btn-background: var(--card-color);
--btn-color: var(--color-ink-reversed);
}
@@ -110,11 +110,6 @@
text-decoration: underline;
}
-
- .btn--reversed {
- --btn-background: var(--color-bg);
- --btn-color: var(--card-color);
- }
}
.card-perma__closure-message {
@@ -124,4 +119,29 @@
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 4be6b06ed..6f869df5c 100644
--- a/app/assets/stylesheets/cards.css
+++ b/app/assets/stylesheets/cards.css
@@ -99,42 +99,18 @@
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.2;
+ line-height: 1.1;
min-block-size: 3lh;
text-wrap: balance;
- .card-perma__bg & {
- min-block-size: unset;
- }
-
- .card-field__title {
+ .card__title-field {
&:is(textarea)::placeholder {
color: inherit;
opacity: 0.5;
@@ -142,6 +118,8 @@
}
.card__title-link {
+ --lines: 3;
+
color: inherit;
}
}
@@ -152,11 +130,11 @@
flex-direction: column;
max-width: 100%;
min-width: 0;
- padding-block: var(--block-space-half);
+ padding-block: var(--block-space);
}
.card__move-button {
- --btn-background: color-mix(in srgb, inherit 40%, var(--color-ink));
+ --btn-background: color-mix(in srgb, var(--card-color) 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 5ac91e94e..2db3016db 100644
--- a/app/assets/stylesheets/comments.css
+++ b/app/assets/stylesheets/comments.css
@@ -68,7 +68,6 @@
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 e1ce84325..30982ad76 100644
--- a/app/assets/stylesheets/house.css
+++ b/app/assets/stylesheets/house.css
@@ -58,6 +58,7 @@
/* Markdown Content */
.house-md-content {
+ caret-color: var(--color-link);
flex-grow: 1;
font-family: var(--font-sans);
text-align: left;
@@ -66,7 +67,7 @@
&.house-md-content-empty::before {
content: attr(placeholder);
- color: currentColor;
+ color: var(--color-ink);
opacity: 0.5;
pointer-events: none;
display: block;
diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb
index d535f26d9..eacc517b6 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, :description, :image, tag_ids: [] ])
+ params.expect(card: [ :status, :title, :color, :due_on, :image, :draft_comment, tag_ids: [] ])
end
def render_card_replacement
diff --git a/app/helpers/cards_helper.rb b/app/helpers/cards_helper.rb
index 31c370479..028a4e715 100644
--- a/app/helpers/cards_helper.rb
+++ b/app/helpers/cards_helper.rb
@@ -19,8 +19,7 @@ module CardsHelper
classes = [
options.delete(:class),
("card--golden" if card.golden?),
- ("card--doing" if card.doing?),
- ("card--drafted" if card.drafted?)
+ ("card--doing" if card.doing?)
].compact.join(" ")
tag.article \
diff --git a/app/models/card.rb b/app/models/card.rb
index 541d761a9..7237e1f58 100644
--- a/app/models/card.rb
+++ b/app/models/card.rb
@@ -1,5 +1,5 @@
class Card < ApplicationRecord
- include Assignable, Colored, Engageable, Eventable, Golden,
+ include Assignable, Colored, DraftCommenting, Engageable, Eventable, Golden,
Messages, Notifiable, Pinnable, Closeable, Searchable, Staged,
Statuses, Taggable, Watchable
@@ -10,8 +10,6 @@ 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
new file mode 100644
index 000000000..615d23916
--- /dev/null
+++ b/app/models/card/draft_commenting.rb
@@ -0,0 +1,33 @@
+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 2e01fef9b..3627a555b 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_and_description, using: :cards_search_index, as: :title
+ searchable_by :title, using: :cards_search_index
scope :mentioning, ->(query) do
if query = sanitize_query_syntax(query)
@@ -18,31 +18,25 @@ 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
- end
-
- private
- def remove_invalid_search_characters(terms)
- terms.gsub(/[^\w"]/, " ")
+ 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
- def remove_unbalanced_quotes(terms)
- if terms.count("\"").even?
- terms
- else
- terms.gsub("\"", " ")
+ private
+ def remove_invalid_search_characters(terms)
+ terms.gsub(/[^\w"]/, " ")
end
- end
- end
- private
- # TODO: Temporary until we stabilize the search API
- def title_and_description
- [ title, description.to_plain_text ].join(" ")
+ def remove_unbalanced_quotes(terms)
+ if terms.count("\"").even?
+ terms
+ else
+ terms.gsub("\"", " ")
+ end
+ end
end
end
diff --git a/app/views/cards/_container.html.erb b/app/views/cards/_container.html.erb
index 034106e59..9c2d11aaf 100644
--- a/app/views/cards/_container.html.erb
+++ b/app/views/cards/_container.html.erb
@@ -1,9 +1,8 @@
+ class="card-perma <%= "card-perma--pointing" unless card.published? %>" style="--card-color: <%= card.color %>;">
<%= render "cards/container/engagement", card: card %>
- <%= render "cards/container/edit", card: card if card.published? %>
<%= render "cards/container/gild", card: card if card.doing? %>
<%= render "cards/container/image", card: card %>
@@ -33,8 +32,11 @@
<% if card.published? %>
- <%= render "cards/container/footer/published", card: card %>
- <% elsif card.creating? %>
- <%= render "cards/container/footer/draft", card: card %>
+
+ <%= turbo_frame_tag card, :watch, src: card_watch_path(card), data: { turbo_permanent: true } %>
+ <%= turbo_frame_tag card, :pin, src: card_pin_path(card), data: { turbo_permanent: true } %>
+
+
+ <%= render "cards/container/closure", card: card %>
<% end %>
diff --git a/app/views/cards/_description_as_draft_comment.html.erb b/app/views/cards/_description_as_draft_comment.html.erb
new file mode 100644
index 000000000..5e7a1cd71
--- /dev/null
+++ b/app/views/cards/_description_as_draft_comment.html.erb
@@ -0,0 +1,29 @@
+
+
diff --git a/app/views/cards/container/_closure.html.erb b/app/views/cards/container/_closure.html.erb
index e9006f3aa..661b8edea 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
deleted file mode 100644
index 23ea9f48d..000000000
--- a/app/views/cards/container/_edit.html.erb
+++ /dev/null
@@ -1,4 +0,0 @@
-<%= 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 a959e888f..b62eb2fb4 100644
--- a/app/views/cards/container/_title.html.erb
+++ b/app/views/cards/container/_title.html.erb
@@ -1,27 +1,14 @@
-<% 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| %>
-
+
+ <% 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| %>
<%= form.text_area :title, placeholder: "Name it…",
- class: "input input--textarea full-width borderless txt-align-start",
+ class: "input input--textarea full-width borderless txt-align-start #{ "fill-highlight" if card.creating? }",
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" } %>
-
-
- <%= 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 %>
-<% 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
deleted file mode 100644
index f46e08b41..000000000
--- a/app/views/cards/container/footer/_draft.html.erb
+++ /dev/null
@@ -1,4 +0,0 @@
-
- <%= 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
deleted file mode 100644
index c4e0a0cdf..000000000
--- a/app/views/cards/container/footer/_published.html.erb
+++ /dev/null
@@ -1,7 +0,0 @@
-<%# FIXME: Let's move this aside outside of the card container section so these frames don't reload/flicker when card is replaced %>
-
- <%= turbo_frame_tag card, :watch, src: card_watch_path(card) %>
- <%= turbo_frame_tag card, :pin, src: card_pin_path(card) %>
-
-
-<%= 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 43284b534..e1ed5b946 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 c89cdcc57..7cfa48447 100644
--- a/app/views/cards/display/common/_assignees.html.erb
+++ b/app/views/cards/display/common/_assignees.html.erb
@@ -4,7 +4,7 @@
<% end %>
>
-
+ " data-action="click->dialog#open:stop">
<%= icon_tag "person-add" %>
Assign
diff --git a/app/views/cards/display/perma/_tags.html.erb b/app/views/cards/display/perma/_tags.html.erb
index 46e66c56e..cecde410e 100644
--- a/app/views/cards/display/perma/_tags.html.erb
+++ b/app/views/cards/display/perma/_tags.html.erb
@@ -12,7 +12,7 @@
>
-
+ " data-action="click->dialog#open:stop">
<%= icon_tag "tag" %>
Add a tag
diff --git a/app/views/cards/edit.html.erb b/app/views/cards/edit.html.erb
index ad509b0e0..5e5e0d1d9 100644
--- a/app/views/cards/edit.html.erb
+++ b/app/views/cards/edit.html.erb
@@ -1,19 +1,13 @@
<%= turbo_frame_tag @card, :edit do %>
- <%= 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"%>
+ <%= 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 %>
<%= 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 56ca920bb..df993c968 100644
--- a/app/views/cards/show.html.erb
+++ b/app/views/cards/show.html.erb
@@ -34,5 +34,7 @@
<% 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 5cb3a6582..5272dc182 100644
--- a/test/controllers/cards_controller_test.rb
+++ b/test/controllers/cards_controller_test.rb
@@ -36,17 +36,19 @@ 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"),
- description: "Something more in-depth",
+ draft_comment: "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.description_plain_text.strip
+ assert_equal "Something more in-depth", card.messages.comments.first.comment.body_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 31d730306..08ade7f0f 100644
--- a/test/models/card/messages_test.rb
+++ b/test/models/card/messages_test.rb
@@ -6,4 +6,41 @@ 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