Replace House with lexical-powered actiontext
This commit is contained in:
@@ -24,9 +24,10 @@ gem "thruster", require: false
|
||||
gem "bcrypt", "~> 3.1.7"
|
||||
gem "geared_pagination", "~> 1.2"
|
||||
gem "rqrcode"
|
||||
gem "redcarpet"
|
||||
gem "rouge"
|
||||
gem "jbuilder"
|
||||
gem "actiontext-lexical", path: "/Users/jorge/Work/jorgemanrubia/actiontext-lexical"
|
||||
gem "image_processing", "~> 1.14"
|
||||
|
||||
# Telemetry and logging
|
||||
gem "sentry-ruby"
|
||||
@@ -51,3 +52,4 @@ group :test do
|
||||
gem "webmock"
|
||||
gem "vcr"
|
||||
end
|
||||
|
||||
|
||||
+46
-11
@@ -1,6 +1,6 @@
|
||||
GIT
|
||||
remote: https://github.com/basecamp/active_record-tenanted
|
||||
revision: 612f5e8b7f77b7076a7eb21521920630161461aa
|
||||
revision: 173048c2af29e9a723811e552bc59e3154e82e2a
|
||||
specs:
|
||||
active_record-tenanted (0.1.0)
|
||||
activerecord (>= 8.1.alpha)
|
||||
@@ -128,6 +128,16 @@ GIT
|
||||
thor (~> 1.0, >= 1.2.2)
|
||||
zeitwerk (~> 2.6)
|
||||
|
||||
PATH
|
||||
remote: /Users/jorge/Work/jorgemanrubia/actiontext-lexical
|
||||
specs:
|
||||
actiontext-lexical (0.1.0)
|
||||
capybara
|
||||
cuprite
|
||||
image_processing
|
||||
rails (>= 8.0.2)
|
||||
selenium-webdriver
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
@@ -163,13 +173,17 @@ GEM
|
||||
bigdecimal
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
cuprite (0.17)
|
||||
capybara (~> 3.0)
|
||||
ferrum (~> 0.17.0)
|
||||
date (3.4.1)
|
||||
debug (1.10.0)
|
||||
irb (~> 1.10)
|
||||
reline (>= 0.3.8)
|
||||
dotenv (3.1.8)
|
||||
drb (2.2.1)
|
||||
drb (2.2.3)
|
||||
ed25519 (1.4.0)
|
||||
erb (5.0.1)
|
||||
erubi (1.13.1)
|
||||
et-orbi (1.2.11)
|
||||
tzinfo
|
||||
@@ -184,6 +198,16 @@ GEM
|
||||
net-http (>= 0.5.0)
|
||||
faraday-retry (2.3.1)
|
||||
faraday (~> 2.0)
|
||||
ferrum (0.17.1)
|
||||
addressable (~> 2.5)
|
||||
base64 (~> 0.2)
|
||||
concurrent-ruby (~> 1.1)
|
||||
webrick (~> 1.7)
|
||||
websocket-driver (~> 0.7)
|
||||
ffi (1.17.2)
|
||||
ffi (1.17.2-arm64-darwin)
|
||||
ffi (1.17.2-x86_64-darwin)
|
||||
ffi (1.17.2-x86_64-linux-gnu)
|
||||
fugit (1.11.1)
|
||||
et-orbi (~> 1, >= 1.2.11)
|
||||
raabro (~> 1.4)
|
||||
@@ -195,6 +219,9 @@ GEM
|
||||
hashdiff (1.1.2)
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
image_processing (1.14.0)
|
||||
mini_magick (>= 4.9.5, < 6)
|
||||
ruby-vips (>= 2.0.17, < 3)
|
||||
importmap-rails (2.1.0)
|
||||
actionpack (>= 6.0.0)
|
||||
activesupport (>= 6.0.0)
|
||||
@@ -222,7 +249,7 @@ GEM
|
||||
language_server-protocol (3.17.0.4)
|
||||
lint_roller (1.1.0)
|
||||
logger (1.7.0)
|
||||
loofah (2.24.0)
|
||||
loofah (2.24.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
mail (2.8.1)
|
||||
@@ -232,8 +259,11 @@ GEM
|
||||
net-smtp
|
||||
marcel (1.0.4)
|
||||
matrix (0.4.2)
|
||||
mini_magick (5.2.0)
|
||||
benchmark
|
||||
logger
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.8)
|
||||
mini_portile2 (2.8.9)
|
||||
minitest (5.25.5)
|
||||
msgpack (1.8.0)
|
||||
multipart-post (2.4.1)
|
||||
@@ -277,7 +307,7 @@ GEM
|
||||
activesupport (>= 7.0.0)
|
||||
rack
|
||||
railties (>= 7.0.0)
|
||||
psych (5.2.3)
|
||||
psych (5.2.6)
|
||||
date
|
||||
stringio
|
||||
public_suffix (6.0.1)
|
||||
@@ -285,7 +315,7 @@ GEM
|
||||
nio4r (~> 2.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.8.1)
|
||||
rack (3.1.14)
|
||||
rack (3.1.15)
|
||||
rack-contrib (2.5.0)
|
||||
rack (< 4)
|
||||
rack-session (2.1.1)
|
||||
@@ -295,7 +325,7 @@ GEM
|
||||
rack (>= 1.3)
|
||||
rackup (2.2.1)
|
||||
rack (>= 3)
|
||||
rails-dom-testing (2.2.0)
|
||||
rails-dom-testing (2.3.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
@@ -305,9 +335,9 @@ GEM
|
||||
rainbow (3.1.1)
|
||||
rake (13.2.1)
|
||||
rb_sys (0.9.106)
|
||||
rdoc (6.13.1)
|
||||
rdoc (6.14.0)
|
||||
erb
|
||||
psych (>= 4.0.0)
|
||||
redcarpet (3.6.1)
|
||||
regexp_parser (2.10.0)
|
||||
reline (0.6.1)
|
||||
io-console (~> 0.5)
|
||||
@@ -346,6 +376,9 @@ GEM
|
||||
rubocop-performance (>= 1.24)
|
||||
rubocop-rails (>= 2.30)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-vips (2.2.3)
|
||||
ffi (~> 1.12)
|
||||
logger
|
||||
rubyzip (2.4.1)
|
||||
securerandom (0.4.1)
|
||||
selenium-webdriver (4.31.0)
|
||||
@@ -423,6 +456,7 @@ GEM
|
||||
addressable (>= 2.8.0)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
webrick (1.9.1)
|
||||
websocket (1.2.11)
|
||||
websocket-driver (0.7.7)
|
||||
base64
|
||||
@@ -430,7 +464,7 @@ GEM
|
||||
websocket-extensions (0.1.5)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.7.2)
|
||||
zeitwerk (2.7.3)
|
||||
|
||||
PLATFORMS
|
||||
arm64-darwin
|
||||
@@ -440,6 +474,7 @@ PLATFORMS
|
||||
x86_64-mingw32
|
||||
|
||||
DEPENDENCIES
|
||||
actiontext-lexical!
|
||||
active_record-tenanted!
|
||||
bcrypt (~> 3.1.7)
|
||||
bootsnap
|
||||
@@ -448,6 +483,7 @@ DEPENDENCIES
|
||||
capybara
|
||||
debug
|
||||
geared_pagination (~> 1.2)
|
||||
image_processing (~> 1.14)
|
||||
importmap-rails
|
||||
jbuilder
|
||||
kamal
|
||||
@@ -455,7 +491,6 @@ DEPENDENCIES
|
||||
puma (>= 5.0)
|
||||
rails!
|
||||
rails_structured_logging!
|
||||
redcarpet
|
||||
rouge
|
||||
rqrcode
|
||||
rubocop-rails-omakase
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* Default Trix editor styles. See Action Text overwrites below.
|
||||
*/
|
||||
|
||||
trix-editor {
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 3px;
|
||||
margin: 0;
|
||||
padding: 0.4em 0.6em;
|
||||
min-height: 5em;
|
||||
outline: none; }
|
||||
|
||||
trix-toolbar * {
|
||||
box-sizing: border-box; }
|
||||
|
||||
trix-toolbar .trix-button-row {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
overflow-x: auto; }
|
||||
|
||||
trix-toolbar .trix-button-group {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #bbb;
|
||||
border-top-color: #ccc;
|
||||
border-bottom-color: #888;
|
||||
border-radius: 3px; }
|
||||
trix-toolbar .trix-button-group:not(:first-child) {
|
||||
margin-left: 1.5vw; }
|
||||
@media (max-width: 768px) {
|
||||
trix-toolbar .trix-button-group:not(:first-child) {
|
||||
margin-left: 0; } }
|
||||
|
||||
trix-toolbar .trix-button-group-spacer {
|
||||
flex-grow: 1; }
|
||||
@media (max-width: 768px) {
|
||||
trix-toolbar .trix-button-group-spacer {
|
||||
display: none; } }
|
||||
|
||||
trix-toolbar .trix-button {
|
||||
position: relative;
|
||||
float: left;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
font-size: 0.75em;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
padding: 0 0.5em;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-radius: 0;
|
||||
background: transparent; }
|
||||
trix-toolbar .trix-button:not(:first-child) {
|
||||
border-left: 1px solid #ccc; }
|
||||
trix-toolbar .trix-button.trix-active {
|
||||
background: #cbeefa;
|
||||
color: black; }
|
||||
trix-toolbar .trix-button:not(:disabled) {
|
||||
cursor: pointer; }
|
||||
trix-toolbar .trix-button:disabled {
|
||||
color: rgba(0, 0, 0, 0.125); }
|
||||
@media (max-width: 768px) {
|
||||
trix-toolbar .trix-button {
|
||||
letter-spacing: -0.01em;
|
||||
padding: 0 0.3em; } }
|
||||
|
||||
trix-toolbar .trix-button--icon {
|
||||
font-size: inherit;
|
||||
width: 2.6em;
|
||||
height: 1.6em;
|
||||
max-width: calc(0.8em + 4vw);
|
||||
text-indent: -9999px; }
|
||||
@media (max-width: 768px) {
|
||||
trix-toolbar .trix-button--icon {
|
||||
height: 2em;
|
||||
max-width: calc(0.8em + 3.5vw); } }
|
||||
trix-toolbar .trix-button--icon::before {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
opacity: 0.6;
|
||||
content: "";
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain; }
|
||||
@media (max-width: 768px) {
|
||||
trix-toolbar .trix-button--icon::before {
|
||||
right: 6%;
|
||||
left: 6%; } }
|
||||
trix-toolbar .trix-button--icon.trix-active::before {
|
||||
opacity: 1; }
|
||||
trix-toolbar .trix-button--icon:disabled::before {
|
||||
opacity: 0.125; }
|
||||
|
||||
trix-toolbar .trix-button--icon-attach::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M10.5%2018V7.5c0-2.25%203-2.25%203%200V18c0%204.125-6%204.125-6%200V7.5c0-6.375%209-6.375%209%200V18%22%20stroke%3D%22%23000%22%20stroke-width%3D%222%22%20stroke-miterlimit%3D%2210%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E");
|
||||
top: 8%;
|
||||
bottom: 4%; }
|
||||
|
||||
trix-toolbar .trix-button--icon-bold::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M6.522%2019.242a.5.5%200%200%201-.5-.5V5.35a.5.5%200%200%201%20.5-.5h5.783c1.347%200%202.46.345%203.24.982.783.64%201.216%201.562%201.216%202.683%200%201.13-.587%202.129-1.476%202.71a.35.35%200%200%200%20.049.613c1.259.56%202.101%201.742%202.101%203.22%200%201.282-.483%202.334-1.363%203.063-.876.726-2.132%201.12-3.66%201.12h-5.89ZM9.27%207.347v3.362h1.97c.766%200%201.347-.17%201.733-.464.38-.291.587-.716.587-1.27%200-.53-.183-.928-.513-1.198-.334-.273-.838-.43-1.505-.43H9.27Zm0%205.606v3.791h2.389c.832%200%201.448-.177%201.853-.497.399-.315.614-.786.614-1.423%200-.62-.22-1.077-.63-1.385-.418-.313-1.053-.486-1.905-.486H9.27Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-italic::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M9%205h6.5v2h-2.23l-2.31%2010H13v2H6v-2h2.461l2.306-10H9V5Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-link::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M18.948%205.258a4.337%204.337%200%200%200-6.108%200L11.217%206.87a.993.993%200%200%200%200%201.41c.392.39%201.027.39%201.418%200l1.623-1.613a2.323%202.323%200%200%201%203.271%200%202.29%202.29%200%200%201%200%203.251l-2.393%202.38a3.021%203.021%200%200%201-4.255%200l-.05-.049a1.007%201.007%200%200%200-1.418%200%20.993.993%200%200%200%200%201.41l.05.049a5.036%205.036%200%200%200%207.091%200l2.394-2.38a4.275%204.275%200%200%200%200-6.072Zm-13.683%2013.6a4.337%204.337%200%200%200%206.108%200l1.262-1.255a.993.993%200%200%200%200-1.41%201.007%201.007%200%200%200-1.418%200L9.954%2017.45a2.323%202.323%200%200%201-3.27%200%202.29%202.29%200%200%201%200-3.251l2.344-2.331a2.579%202.579%200%200%201%203.631%200c.392.39%201.027.39%201.419%200a.993.993%200%200%200%200-1.41%204.593%204.593%200%200%200-6.468%200l-2.345%202.33a4.275%204.275%200%200%200%200%206.072Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-strike::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M6%2014.986c.088%202.647%202.246%204.258%205.635%204.258%203.496%200%205.713-1.728%205.713-4.463%200-.275-.02-.536-.062-.781h-3.461c.398.293.573.654.573%201.123%200%201.035-1.074%201.787-2.646%201.787-1.563%200-2.773-.762-2.91-1.924H6ZM6.432%2010h3.763c-.632-.314-.914-.715-.914-1.273%200-1.045.977-1.739%202.432-1.739%201.475%200%202.52.723%202.617%201.914h2.764c-.05-2.548-2.11-4.238-5.39-4.238-3.145%200-5.392%201.719-5.392%204.316%200%20.363.04.703.12%201.02ZM4%2011a1%201%200%201%200%200%202h15a1%201%200%201%200%200-2H4Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-quote::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M4.581%208.471c.44-.5%201.056-.834%201.758-.995C8.074%207.17%209.201%207.822%2010%208.752c1.354%201.578%201.33%203.555.394%205.277-.941%201.731-2.788%203.163-4.988%203.56a.622.622%200%200%201-.653-.317c-.113-.205-.121-.49.16-.764.294-.286.567-.566.791-.835.222-.266.413-.54.524-.815.113-.28.156-.597.026-.908-.128-.303-.39-.524-.72-.69a3.02%203.02%200%200%201-1.674-2.7c0-.905.283-1.59.72-2.088Zm9.419%200c.44-.5%201.055-.834%201.758-.995%201.734-.306%202.862.346%203.66%201.276%201.355%201.578%201.33%203.555.395%205.277-.941%201.731-2.789%203.163-4.988%203.56a.622.622%200%200%201-.653-.317c-.113-.205-.122-.49.16-.764.294-.286.567-.566.791-.835.222-.266.412-.54.523-.815.114-.28.157-.597.026-.908-.127-.303-.39-.524-.72-.69a3.02%203.02%200%200%201-1.672-2.701c0-.905.283-1.59.72-2.088Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-heading-1::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M21.5%207.5v-3h-12v3H14v13h3v-13h4.5ZM9%2013.5h3.5v-3h-10v3H6v7h3v-7Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-code::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3.293%2011.293a1%201%200%200%200%200%201.414l4%204a1%201%200%201%200%201.414-1.414L5.414%2012l3.293-3.293a1%201%200%200%200-1.414-1.414l-4%204Zm13.414%205.414%204-4a1%201%200%200%200%200-1.414l-4-4a1%201%200%201%200-1.414%201.414L18.586%2012l-3.293%203.293a1%201%200%200%200%201.414%201.414Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-bullet-list::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%207.5a1.5%201.5%200%201%200%200-3%201.5%201.5%200%200%200%200%203ZM8%206a1%201%200%200%201%201-1h11a1%201%200%201%201%200%202H9a1%201%200%200%201-1-1Zm1%205a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm0%206a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm-2.5-5a1.5%201.5%200%201%201-3%200%201.5%201.5%200%200%201%203%200ZM5%2019.5a1.5%201.5%200%201%200%200-3%201.5%201.5%200%200%200%200%203Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-number-list::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3%204h2v4H4V5H3V4Zm5%202a1%201%200%200%201%201-1h11a1%201%200%201%201%200%202H9a1%201%200%200%201-1-1Zm1%205a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm0%206a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm-3.5-7H6v1l-1.5%202H6v1H3v-1l1.667-2H3v-1h2.5ZM3%2017v-1h3v4H3v-1h2v-.5H4v-1h1V17H3Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-undo::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3%2014a1%201%200%200%200%201%201h6a1%201%200%201%200%200-2H6.257c2.247-2.764%205.151-3.668%207.579-3.264%202.589.432%204.739%202.356%205.174%205.405a1%201%200%200%200%201.98-.283c-.564-3.95-3.415-6.526-6.825-7.095C11.084%207.25%207.63%208.377%205%2011.39V8a1%201%200%200%200-2%200v6Zm2-1Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-redo::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M21%2014a1%201%200%200%201-1%201h-6a1%201%200%201%201%200-2h3.743c-2.247-2.764-5.151-3.668-7.579-3.264-2.589.432-4.739%202.356-5.174%205.405a1%201%200%200%201-1.98-.283c.564-3.95%203.415-6.526%206.826-7.095%203.08-.513%206.534.614%209.164%203.626V8a1%201%200%201%201%202%200v6Zm-2-1Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-decrease-nesting-level::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%206a1%201%200%200%201%201-1h12a1%201%200%201%201%200%202H6a1%201%200%200%201-1-1Zm4%205a1%201%200%201%200%200%202h9a1%201%200%201%200%200-2H9Zm-3%206a1%201%200%201%200%200%202h12a1%201%200%201%200%200-2H6Zm-3.707-5.707a1%201%200%200%200%200%201.414l2%202a1%201%200%201%200%201.414-1.414L4.414%2012l1.293-1.293a1%201%200%200%200-1.414-1.414l-2%202Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-button--icon-increase-nesting-level::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%206a1%201%200%200%201%201-1h12a1%201%200%201%201%200%202H6a1%201%200%200%201-1-1Zm4%205a1%201%200%201%200%200%202h9a1%201%200%201%200%200-2H9Zm-3%206a1%201%200%201%200%200%202h12a1%201%200%201%200%200-2H6Zm-2.293-2.293%202-2a1%201%200%200%200%200-1.414l-2-2a1%201%200%201%200-1.414%201.414L3.586%2012l-1.293%201.293a1%201%200%201%200%201.414%201.414Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
||||
|
||||
trix-toolbar .trix-dialogs {
|
||||
position: relative; }
|
||||
|
||||
trix-toolbar .trix-dialog {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
font-size: 0.75em;
|
||||
padding: 15px 10px;
|
||||
background: #fff;
|
||||
box-shadow: 0 0.3em 1em #ccc;
|
||||
border-top: 2px solid #888;
|
||||
border-radius: 5px;
|
||||
z-index: 5; }
|
||||
|
||||
trix-toolbar .trix-input--dialog {
|
||||
font-size: inherit;
|
||||
font-weight: normal;
|
||||
padding: 0.5em 0.8em;
|
||||
margin: 0 10px 0 0;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #bbb;
|
||||
background-color: #fff;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none; }
|
||||
trix-toolbar .trix-input--dialog.validate:invalid {
|
||||
box-shadow: #F00 0px 0px 1.5px 1px; }
|
||||
|
||||
trix-toolbar .trix-button--dialog {
|
||||
font-size: inherit;
|
||||
padding: 0.5em;
|
||||
border-bottom: none; }
|
||||
|
||||
trix-toolbar .trix-dialog--link {
|
||||
max-width: 600px; }
|
||||
|
||||
trix-toolbar .trix-dialog__link-fields {
|
||||
display: flex;
|
||||
align-items: baseline; }
|
||||
trix-toolbar .trix-dialog__link-fields .trix-input {
|
||||
flex: 1; }
|
||||
trix-toolbar .trix-dialog__link-fields .trix-button-group {
|
||||
flex: 0 0 content;
|
||||
margin: 0; }
|
||||
|
||||
trix-editor [data-trix-mutable]:not(.attachment__caption-editor) {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none; }
|
||||
|
||||
trix-editor [data-trix-mutable]::-moz-selection,
|
||||
trix-editor [data-trix-cursor-target]::-moz-selection, trix-editor [data-trix-mutable] ::-moz-selection {
|
||||
background: none; }
|
||||
|
||||
trix-editor [data-trix-mutable]::selection,
|
||||
trix-editor [data-trix-cursor-target]::selection, trix-editor [data-trix-mutable] ::selection {
|
||||
background: none; }
|
||||
|
||||
trix-editor .attachment__caption-editor:focus[data-trix-mutable]::-moz-selection {
|
||||
background: highlight; }
|
||||
|
||||
trix-editor .attachment__caption-editor:focus[data-trix-mutable]::selection {
|
||||
background: highlight; }
|
||||
|
||||
trix-editor [data-trix-mutable].attachment.attachment--file {
|
||||
box-shadow: 0 0 0 2px highlight;
|
||||
border-color: transparent; }
|
||||
|
||||
trix-editor [data-trix-mutable].attachment img {
|
||||
box-shadow: 0 0 0 2px highlight; }
|
||||
|
||||
trix-editor .attachment {
|
||||
position: relative; }
|
||||
trix-editor .attachment:hover {
|
||||
cursor: default; }
|
||||
|
||||
trix-editor .attachment--preview .attachment__caption:hover {
|
||||
cursor: text; }
|
||||
|
||||
trix-editor .attachment__progress {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
height: 20px;
|
||||
top: calc(50% - 10px);
|
||||
left: 5%;
|
||||
width: 90%;
|
||||
opacity: 0.9;
|
||||
transition: opacity 200ms ease-in; }
|
||||
trix-editor .attachment__progress[value="100"] {
|
||||
opacity: 0; }
|
||||
|
||||
trix-editor .attachment__caption-editor {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
border: none;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none; }
|
||||
|
||||
trix-editor .attachment__toolbar {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: -0.9em;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center; }
|
||||
|
||||
trix-editor .trix-button-group {
|
||||
display: inline-flex; }
|
||||
|
||||
trix-editor .trix-button {
|
||||
position: relative;
|
||||
float: left;
|
||||
color: #666;
|
||||
white-space: nowrap;
|
||||
font-size: 80%;
|
||||
padding: 0 0.8em;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background: transparent; }
|
||||
trix-editor .trix-button:not(:first-child) {
|
||||
border-left: 1px solid #ccc; }
|
||||
trix-editor .trix-button.trix-active {
|
||||
background: #cbeefa; }
|
||||
trix-editor .trix-button:not(:disabled) {
|
||||
cursor: pointer; }
|
||||
|
||||
trix-editor .trix-button--remove {
|
||||
text-indent: -9999px;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
width: 1.8em;
|
||||
height: 1.8em;
|
||||
line-height: 1.8em;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
border: 2px solid highlight;
|
||||
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.25); }
|
||||
trix-editor .trix-button--remove::before {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
opacity: 0.7;
|
||||
content: "";
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20height%3D%2224%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M19%206.41%2017.59%205%2012%2010.59%206.41%205%205%206.41%2010.59%2012%205%2017.59%206.41%2019%2012%2013.41%2017.59%2019%2019%2017.59%2013.41%2012z%22%2F%3E%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3C%2Fsvg%3E");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 90%; }
|
||||
trix-editor .trix-button--remove:hover {
|
||||
border-color: #333; }
|
||||
trix-editor .trix-button--remove:hover::before {
|
||||
opacity: 1; }
|
||||
|
||||
trix-editor .attachment__metadata-container {
|
||||
position: relative; }
|
||||
|
||||
trix-editor .attachment__metadata {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 2em;
|
||||
transform: translate(-50%, 0);
|
||||
max-width: 90%;
|
||||
padding: 0.1em 0.6em;
|
||||
font-size: 0.8em;
|
||||
color: #fff;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
border-radius: 3px; }
|
||||
trix-editor .attachment__metadata .attachment__name {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
vertical-align: bottom;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
trix-editor .attachment__metadata .attachment__size {
|
||||
margin-left: 0.2em;
|
||||
white-space: nowrap; }
|
||||
|
||||
.trix-content {
|
||||
line-height: 1.5;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word; }
|
||||
.trix-content * {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
.trix-content h1 {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.2; }
|
||||
.trix-content blockquote {
|
||||
border: 0 solid #ccc;
|
||||
border-left-width: 0.3em;
|
||||
margin-left: 0.3em;
|
||||
padding-left: 0.6em; }
|
||||
.trix-content [dir=rtl] blockquote,
|
||||
.trix-content blockquote[dir=rtl] {
|
||||
border-width: 0;
|
||||
border-right-width: 0.3em;
|
||||
margin-right: 0.3em;
|
||||
padding-right: 0.6em; }
|
||||
.trix-content li {
|
||||
margin-left: 1em; }
|
||||
.trix-content [dir=rtl] li {
|
||||
margin-right: 1em; }
|
||||
.trix-content pre {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
vertical-align: top;
|
||||
font-family: monospace;
|
||||
font-size: 0.9em;
|
||||
padding: 0.5em;
|
||||
white-space: pre;
|
||||
background-color: #eee;
|
||||
overflow-x: auto; }
|
||||
.trix-content img {
|
||||
max-width: 100%;
|
||||
height: auto; }
|
||||
.trix-content .attachment {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
max-width: 100%; }
|
||||
.trix-content .attachment a {
|
||||
color: inherit;
|
||||
text-decoration: none; }
|
||||
.trix-content .attachment a:hover, .trix-content .attachment a:visited:hover {
|
||||
color: inherit; }
|
||||
.trix-content .attachment__caption {
|
||||
text-align: center; }
|
||||
.trix-content .attachment__caption .attachment__name + .attachment__size::before {
|
||||
content: ' \2022 '; }
|
||||
.trix-content .attachment--preview {
|
||||
width: 100%;
|
||||
text-align: center; }
|
||||
.trix-content .attachment--preview .attachment__caption {
|
||||
color: #666;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.2; }
|
||||
.trix-content .attachment--file {
|
||||
color: #333;
|
||||
line-height: 1;
|
||||
margin: 0 2px 2px 2px;
|
||||
padding: 0.4em 1em;
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 5px; }
|
||||
.trix-content .attachment-gallery {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
position: relative; }
|
||||
.trix-content .attachment-gallery .attachment {
|
||||
flex: 1 0 33%;
|
||||
padding: 0 0.5em;
|
||||
max-width: 33%; }
|
||||
.trix-content .attachment-gallery.attachment-gallery--2 .attachment, .trix-content .attachment-gallery.attachment-gallery--4 .attachment {
|
||||
flex-basis: 50%;
|
||||
max-width: 50%; }
|
||||
|
||||
/*
|
||||
* We need to override trix.css’s image gallery styles to accommodate the
|
||||
* <action-text-attachment> element we wrap around attachments. Otherwise,
|
||||
* images in galleries will be squished by the max-width: 33%; rule.
|
||||
*/
|
||||
.trix-content .attachment-gallery > action-text-attachment,
|
||||
.trix-content .attachment-gallery > .attachment {
|
||||
flex: 1 0 33%;
|
||||
padding: 0 0.5em;
|
||||
max-width: 33%;
|
||||
}
|
||||
|
||||
.trix-content .attachment-gallery.attachment-gallery--2 > action-text-attachment,
|
||||
.trix-content .attachment-gallery.attachment-gallery--2 > .attachment, .trix-content .attachment-gallery.attachment-gallery--4 > action-text-attachment,
|
||||
.trix-content .attachment-gallery.attachment-gallery--4 > .attachment {
|
||||
flex-basis: 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.trix-content action-text-attachment .attachment {
|
||||
padding: 0 !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ module NotificationsHelper
|
||||
|
||||
def comment_notification_body(event)
|
||||
comment = event.eventable
|
||||
"#{strip_tags(comment.body_html).blank? ? "#{event.creator.name} replied" : "#{event.creator.name}:" } #{strip_tags(comment.body_html).truncate(200)}"
|
||||
"#{strip_tags(comment.body.to_s).blank? ? "#{event.creator.name} replied" : "#{event.creator.name}:" } #{strip_tags(comment.body.to_s).truncate(200)}"
|
||||
end
|
||||
|
||||
def card_notification_title(card)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
module RichTextareaHelper
|
||||
def rich_textarea_toolbar(id = "editor-toolbar")
|
||||
content_tag("lexical-toolbar", id: id) do
|
||||
safe_join([
|
||||
# Inline formatting
|
||||
rich_textarea_toolbar_button("Bold", "bold"),
|
||||
rich_textarea_toolbar_button("Italic", "italic"),
|
||||
rich_textarea_toolbar_button("Link", "link"),
|
||||
|
||||
# Block-level formatting
|
||||
rich_textarea_toolbar_button("Heading", "formatElement", data: { payload: "h2" }),
|
||||
rich_textarea_toolbar_button("Subheading", "formatElement", data: { payload: "h3" }),
|
||||
rich_textarea_toolbar_button("Code Block", "insertCodeBlock"),
|
||||
|
||||
# Lists
|
||||
rich_textarea_toolbar_button("• Bullet List", "insertUnorderedList"),
|
||||
rich_textarea_toolbar_button("1. Numbered List", "insertOrderedList"),
|
||||
|
||||
# Attachments
|
||||
rich_textarea_toolbar_button("Upload Attachment", "uploadAttachments")
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
def rich_textarea_toolbar_button(label, command, data: {}, **properties)
|
||||
data[:command] = command
|
||||
content_tag(:button, label, type: "button", data: data, **properties)
|
||||
end
|
||||
end
|
||||
@@ -3,3 +3,6 @@ import "@hotwired/turbo-rails"
|
||||
import "initializers"
|
||||
import "controllers"
|
||||
import "house"
|
||||
|
||||
import "actiontext-lexical"
|
||||
import "@rails/actiontext"
|
||||
|
||||
@@ -30,9 +30,11 @@ export default class extends Controller {
|
||||
|
||||
async restoreContent() {
|
||||
await nextFrame()
|
||||
const savedContent = localStorage.getItem(this.keyValue)
|
||||
let savedContent = localStorage.getItem(this.keyValue)
|
||||
|
||||
if (savedContent) {
|
||||
savedContent = `<div>${savedContent}</div>` // temporary for old markdown saves
|
||||
console.debug("Es", savedContent);
|
||||
this.inputTarget.value = savedContent
|
||||
this.#triggerChangeEvent(savedContent)
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ class Card < ApplicationRecord
|
||||
has_many :comments, dependent: :destroy
|
||||
has_one_attached :image, dependent: :purge_later
|
||||
|
||||
has_markdown :description
|
||||
has_rich_text :description
|
||||
|
||||
before_save :set_default_title, if: :published?
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ class Comment < ApplicationRecord
|
||||
belongs_to :creator, class_name: "User", default: -> { Current.user }
|
||||
has_many :reactions, dependent: :delete_all
|
||||
|
||||
has_markdown :body
|
||||
has_rich_text :body
|
||||
searchable_by :body_plain_text, using: :comments_search_index, as: :body
|
||||
|
||||
scope :chronologically, -> { order created_at: :asc, id: :desc }
|
||||
@@ -19,6 +19,10 @@ class Comment < ApplicationRecord
|
||||
end
|
||||
|
||||
private
|
||||
def body_plain_text
|
||||
body.to_plain_text
|
||||
end
|
||||
|
||||
def watch_card_by_creator
|
||||
card.watch_by creator
|
||||
end
|
||||
|
||||
@@ -14,7 +14,7 @@ module Mentions
|
||||
end
|
||||
|
||||
def mentionable_content
|
||||
markdown_associations.collect { send(it.name)&.to_plain_text }.compact.join(" ")
|
||||
rich_text_associations.collect { send(it.name)&.to_plain_text }.compact.join(" ")
|
||||
end
|
||||
|
||||
private
|
||||
@@ -32,12 +32,12 @@ module Mentions
|
||||
collection.users
|
||||
end
|
||||
|
||||
def markdown_associations
|
||||
self.class.reflect_on_all_associations(:has_one).filter { it.klass == ActionText::Markdown }
|
||||
def rich_text_associations
|
||||
self.class.reflect_on_all_associations(:has_one).filter { it.klass == ActionText::RichText }
|
||||
end
|
||||
|
||||
def mentionable_content_changed?
|
||||
markdown_associations.any? { send(it.name).content_previously_changed? }
|
||||
rich_text_associations.any? { send(it.name).body_previously_changed? }
|
||||
end
|
||||
|
||||
def create_mentions_later
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
|
||||
<% if blob.representable? %>
|
||||
<%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
|
||||
<% end %>
|
||||
|
||||
<figcaption class="attachment__caption">
|
||||
<% if caption = blob.try(:caption) %>
|
||||
<%= caption %>
|
||||
<% else %>
|
||||
<span class="attachment__name"><%= blob.filename %></span>
|
||||
<span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
|
||||
<% end %>
|
||||
</figcaption>
|
||||
</figure>
|
||||
@@ -29,7 +29,7 @@
|
||||
</div>
|
||||
|
||||
<div class="comment__body markdown-content txt-align-start">
|
||||
<%= sanitize comment.body_html %>
|
||||
<%= comment.body %>
|
||||
</div>
|
||||
|
||||
<%= render "cards/comments/reactions/reactions", comment: comment %>
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
data: { controller: "form paste local-save",
|
||||
local_save_key_value: "comment-#{card.id}",
|
||||
action: "turbo:submit-end->local-save#submit keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop paste->paste#pasteFiles" } do |form| %>
|
||||
<%= form.markdown_area :body, class: "input comment__input", required: true, placeholder: new_comment_placeholder(card),
|
||||
<%= rich_textarea_toolbar "editor-toolbar" %>
|
||||
<%= form.rich_textarea :body, class: "input comment__input", toolbar: "editor-toolbar", required: true, placeholder: new_comment_placeholder(card),
|
||||
data: { local_save_target: "input", action: "house-md:change->local-save#save turbo:morph-element->local-save#restoreContent" } %>
|
||||
<%= form.button class: "comment__submit btn btn--reversed flex-item-justify-start" do %>
|
||||
<span>Post this comment</span>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<div class="comment__body markdown-content txt-align-start">
|
||||
<%= form_with model: [ @card, @comment ], class: "flex flex-column gap full-width",
|
||||
data: { controller: "form paste", action: "keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop paste->paste#pasteFiles" } do |form| %>
|
||||
<%= form.markdown_area :body, class: "input comment__input", required: true, autofocus: true, placeholder: new_comment_placeholder(@card) %>
|
||||
<%= rich_textarea_toolbar "editor-toolbar" %>
|
||||
<%= form.rich_textarea :body, class: "input comment__input", toolbar: "editor-toolbar", required: true, autofocus: true, placeholder: new_comment_placeholder(@card) %>
|
||||
<div class="flex gap-half justify-start">
|
||||
<%= form.button class: "btn btn--reversed", type: :submit do %>
|
||||
<span>Save changes</span>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= link_to card.title, edit_collection_card_path(card.collection, card), class: "card__title-link" %>
|
||||
</h1>
|
||||
<div class="card__description markdown-content margin-block-half">
|
||||
<%= sanitize card.description_html %>
|
||||
<%= card.description %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -18,7 +18,9 @@
|
||||
data: { action: "auto-save#change blur->auto-save#submit keydown.enter->auto-save#submit:prevent keydown.ctrl+enter->auto-save#submit:prevent" } %>
|
||||
</h1>
|
||||
<div class="card__description markdown-content margin-block-start-half margin-block-end">
|
||||
<%= form.markdown_area :description, class: "input input--textarea full-width borderless txt-align-start card-field__description",
|
||||
<%= rich_textarea_toolbar "editor-toolbar" %>
|
||||
<%= form.rich_textarea :description, class: "input input--textarea full-width borderless txt-align-start card-field__description",
|
||||
toolbar: "the-toolbar",
|
||||
placeholder: "Add some notes, context, pictures, or video about this…",
|
||||
data: { action: "house-md:change->auto-save#change focusout->auto-save#submit keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop paste->paste#pasteFiles" } %>
|
||||
</div>
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
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 %>
|
||||
</h1>
|
||||
<div class="card__description markdown-content margin-block-start-half margin-block-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" } %>
|
||||
|
||||
<%= rich_textarea_toolbar "editor-toolbar" %>
|
||||
|
||||
<%= form.rich_textarea :description, class: "input input--textarea full-width borderless txt-align-start card-field__description",
|
||||
toolbar: "editor-toolbar",
|
||||
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" } %>
|
||||
</div>
|
||||
<%= 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 %>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%= render "events/event/layout", card: event.eventable.card, event: event do %>
|
||||
<span class="txt-break overflow-line-clamp txt-tight-lines">
|
||||
<%= strip_tags(event&.eventable.body_html).truncate(200) -%>
|
||||
<%= strip_tags(event&.eventable.body.to_s).truncate(200) -%>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="action-text-content">
|
||||
<%= yield -%>
|
||||
</div>
|
||||
@@ -11,3 +11,6 @@ pin_all_from "app/javascript/controllers", under: "controllers"
|
||||
pin_all_from "app/javascript/helpers", under: "helpers"
|
||||
pin_all_from "app/javascript/initializers", under: "initializers"
|
||||
pin "marked" # @15.0.11
|
||||
pin "actiontext-lexical"
|
||||
pin "@rails/activestorage", to: "activestorage.esm.js"
|
||||
pin "@rails/actiontext", to: "actiontext.esm.js"
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
ActiveSupport.on_load :action_text_markdown do
|
||||
require "markdown_renderer"
|
||||
require "redcarpet/render_strip"
|
||||
|
||||
ActionText::Markdown.html_renderer = ->(content) { MarkdownRenderer.build.render(content) }
|
||||
ActionText::Markdown.plain_text_renderer = Redcarpet::Markdown.new(Redcarpet::Render::StripDown)
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
# This migration comes from action_text (originally 20180528164100)
|
||||
class CreateActionTextTables < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
# Use Active Record's configured type for primary and foreign keys
|
||||
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
||||
|
||||
create_table :action_text_rich_texts, id: primary_key_type do |t|
|
||||
t.string :name, null: false
|
||||
t.text :body, size: :long
|
||||
t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
|
||||
|
||||
t.timestamps
|
||||
|
||||
t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def primary_and_foreign_key_types
|
||||
config = Rails.configuration.generators
|
||||
setting = config.options[config.orm][:primary_key_type]
|
||||
primary_key_type = setting || :primary_key
|
||||
foreign_key_type = setting || :bigint
|
||||
[ primary_key_type, foreign_key_type ]
|
||||
end
|
||||
end
|
||||
Generated
+11
-1
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.1].define(version: 2025_05_15_125505) do
|
||||
ActiveRecord::Schema[8.1].define(version: 2025_05_23_084734) do
|
||||
create_table "accesses", force: :cascade do |t|
|
||||
t.integer "collection_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
@@ -39,6 +39,16 @@ ActiveRecord::Schema[8.1].define(version: 2025_05_15_125505) do
|
||||
t.index ["record_type", "record_id"], name: "index_action_text_markdowns_on_record"
|
||||
end
|
||||
|
||||
create_table "action_text_rich_texts", force: :cascade do |t|
|
||||
t.text "body"
|
||||
t.datetime "created_at", null: false
|
||||
t.string "name", null: false
|
||||
t.bigint "record_id", null: false
|
||||
t.string "record_type", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true
|
||||
end
|
||||
|
||||
create_table "active_storage_attachments", force: :cascade do |t|
|
||||
t.bigint "blob_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
|
||||
+116
-78
@@ -1,7 +1,7 @@
|
||||
--- !ruby/object:ActiveRecord::ConnectionAdapters::SchemaCache
|
||||
columns:
|
||||
accesses:
|
||||
- &22 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &23 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: collection_id
|
||||
cast_type: &1 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3Adapter::SQLite3Integer
|
||||
@@ -80,7 +80,7 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- &24 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &25 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: user_id
|
||||
cast_type: *1
|
||||
@@ -118,13 +118,13 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: content
|
||||
cast_type: &14 !ruby/object:ActiveRecord::Type::Text
|
||||
cast_type: &11 !ruby/object:ActiveRecord::Type::Text
|
||||
true: t
|
||||
false: f
|
||||
precision:
|
||||
scale:
|
||||
limit:
|
||||
sql_type_metadata: &15 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type_metadata: &12 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type: TEXT
|
||||
type: :text
|
||||
limit:
|
||||
@@ -159,17 +159,30 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
- *9
|
||||
active_storage_attachments:
|
||||
action_text_rich_texts:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: body
|
||||
cast_type: *11
|
||||
sql_type_metadata: *12
|
||||
'null': true
|
||||
default:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *5
|
||||
- *6
|
||||
- *10
|
||||
- &16 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: blob_id
|
||||
cast_type: &11 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3Adapter::SQLite3Integer
|
||||
name: record_id
|
||||
cast_type: &14 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3Adapter::SQLite3Integer
|
||||
precision:
|
||||
scale:
|
||||
limit:
|
||||
max: 9223372036854775808
|
||||
min: -9223372036854775808
|
||||
sql_type_metadata: &12 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type_metadata: &15 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type: bigint
|
||||
type: :integer
|
||||
limit:
|
||||
@@ -180,19 +193,23 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *5
|
||||
- *6
|
||||
- *10
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- *13
|
||||
- *9
|
||||
active_storage_attachments:
|
||||
- &17 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: record_id
|
||||
cast_type: *11
|
||||
sql_type_metadata: *12
|
||||
name: blob_id
|
||||
cast_type: *14
|
||||
sql_type_metadata: *15
|
||||
'null': false
|
||||
default:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *5
|
||||
- *6
|
||||
- *10
|
||||
- *16
|
||||
- *13
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
@@ -208,8 +225,8 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: byte_size
|
||||
cast_type: *11
|
||||
sql_type_metadata: *12
|
||||
cast_type: *14
|
||||
sql_type_metadata: *15
|
||||
'null': false
|
||||
default:
|
||||
default_function:
|
||||
@@ -247,7 +264,7 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
- *6
|
||||
- &17 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &18 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: key
|
||||
cast_type: *7
|
||||
@@ -260,8 +277,8 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: metadata
|
||||
cast_type: *14
|
||||
sql_type_metadata: *15
|
||||
cast_type: *11
|
||||
sql_type_metadata: *12
|
||||
'null': true
|
||||
default:
|
||||
default_function:
|
||||
@@ -278,7 +295,7 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
active_storage_variant_records:
|
||||
- *16
|
||||
- *17
|
||||
- *6
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
@@ -292,7 +309,7 @@ columns:
|
||||
comment:
|
||||
ar_internal_metadata:
|
||||
- *5
|
||||
- *17
|
||||
- *18
|
||||
- *9
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
@@ -305,7 +322,7 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
assignees_filters:
|
||||
- &19 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &20 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: assignee_id
|
||||
cast_type: *1
|
||||
@@ -315,7 +332,7 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- &18 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &19 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: filter_id
|
||||
cast_type: *1
|
||||
@@ -326,7 +343,7 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
assigners_filters:
|
||||
- &20 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &21 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: assigner_id
|
||||
cast_type: *1
|
||||
@@ -336,11 +353,11 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *18
|
||||
assignments:
|
||||
- *19
|
||||
assignments:
|
||||
- *20
|
||||
- &21 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- *21
|
||||
- &22 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: card_id
|
||||
cast_type: *1
|
||||
@@ -368,14 +385,14 @@ columns:
|
||||
- *6
|
||||
- *9
|
||||
card_goldnesses:
|
||||
- *21
|
||||
- *22
|
||||
- *5
|
||||
- *6
|
||||
- *9
|
||||
cards:
|
||||
- *22
|
||||
- *23
|
||||
- *5
|
||||
- &23 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &24 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: creator_id
|
||||
cast_type: *1
|
||||
@@ -428,14 +445,14 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: status
|
||||
cast_type: *14
|
||||
sql_type_metadata: *15
|
||||
cast_type: *11
|
||||
sql_type_metadata: *12
|
||||
'null': false
|
||||
default: creating
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- &30 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &31 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: title
|
||||
cast_type: *7
|
||||
@@ -461,7 +478,7 @@ columns:
|
||||
comment:
|
||||
- *9
|
||||
closures:
|
||||
- *21
|
||||
- *22
|
||||
- *5
|
||||
- *6
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
@@ -489,11 +506,11 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: all_access
|
||||
cast_type: &31 !ruby/object:ActiveModel::Type::Boolean
|
||||
cast_type: &32 !ruby/object:ActiveModel::Type::Boolean
|
||||
precision:
|
||||
scale:
|
||||
limit:
|
||||
sql_type_metadata: &32 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type_metadata: &33 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type: boolean
|
||||
type: :boolean
|
||||
limit:
|
||||
@@ -507,15 +524,15 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: auto_close_period
|
||||
cast_type: *11
|
||||
sql_type_metadata: *12
|
||||
cast_type: *14
|
||||
sql_type_metadata: *15
|
||||
'null': true
|
||||
default:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *5
|
||||
- *23
|
||||
- *24
|
||||
- *6
|
||||
- *10
|
||||
- *9
|
||||
@@ -530,18 +547,18 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
collections_filters:
|
||||
- *22
|
||||
- *18
|
||||
- *23
|
||||
- *19
|
||||
commands:
|
||||
- *5
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: data
|
||||
cast_type: &25 !ruby/object:ActiveRecord::Type::Json
|
||||
cast_type: &26 !ruby/object:ActiveRecord::Type::Json
|
||||
precision:
|
||||
scale:
|
||||
limit:
|
||||
sql_type_metadata: &26 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type_metadata: &27 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type: json
|
||||
type: :json
|
||||
limit:
|
||||
@@ -556,8 +573,8 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: line
|
||||
cast_type: *14
|
||||
sql_type_metadata: *15
|
||||
cast_type: *11
|
||||
sql_type_metadata: *12
|
||||
'null': true
|
||||
default:
|
||||
default_function:
|
||||
@@ -584,16 +601,16 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
- *9
|
||||
- *24
|
||||
- *25
|
||||
comments:
|
||||
- *21
|
||||
- *22
|
||||
- *5
|
||||
- *23
|
||||
- *24
|
||||
- *6
|
||||
- *9
|
||||
creators_filters:
|
||||
- *23
|
||||
- *18
|
||||
- *24
|
||||
- *19
|
||||
events:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
@@ -605,9 +622,9 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *22
|
||||
- *5
|
||||
- *23
|
||||
- *5
|
||||
- *24
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: eventable_id
|
||||
@@ -632,8 +649,8 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: particulars
|
||||
cast_type: *25
|
||||
sql_type_metadata: *26
|
||||
cast_type: *26
|
||||
sql_type_metadata: *27
|
||||
'null': true
|
||||
default: "{}"
|
||||
default_function:
|
||||
@@ -642,12 +659,12 @@ columns:
|
||||
- *9
|
||||
filters:
|
||||
- *5
|
||||
- *23
|
||||
- *24
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: fields
|
||||
cast_type: *25
|
||||
sql_type_metadata: *26
|
||||
cast_type: *26
|
||||
sql_type_metadata: *27
|
||||
'null': false
|
||||
default: "{}"
|
||||
default_function:
|
||||
@@ -666,7 +683,7 @@ columns:
|
||||
comment:
|
||||
- *9
|
||||
filters_stages:
|
||||
- *18
|
||||
- *19
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: stage_id
|
||||
@@ -678,8 +695,8 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
filters_tags:
|
||||
- *18
|
||||
- &29 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- *19
|
||||
- &30 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: tag_id
|
||||
cast_type: *1
|
||||
@@ -712,7 +729,7 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- &27 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &28 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: source_id
|
||||
cast_type: *1
|
||||
@@ -722,7 +739,7 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- &28 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &29 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: source_type
|
||||
cast_type: *7
|
||||
@@ -756,16 +773,16 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *27
|
||||
- *28
|
||||
- *29
|
||||
- *9
|
||||
- *24
|
||||
- *25
|
||||
pins:
|
||||
- *21
|
||||
- *22
|
||||
- *5
|
||||
- *6
|
||||
- *9
|
||||
- *24
|
||||
- *25
|
||||
reactions:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
@@ -882,24 +899,24 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *24
|
||||
- *25
|
||||
taggings:
|
||||
- *21
|
||||
- *22
|
||||
- *5
|
||||
- *6
|
||||
- *29
|
||||
- *30
|
||||
- *9
|
||||
tags:
|
||||
- *5
|
||||
- *6
|
||||
- *30
|
||||
- *31
|
||||
- *9
|
||||
users:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: active
|
||||
cast_type: *31
|
||||
sql_type_metadata: *32
|
||||
cast_type: *32
|
||||
sql_type_metadata: *33
|
||||
'null': false
|
||||
default: true
|
||||
default_function:
|
||||
@@ -940,16 +957,16 @@ columns:
|
||||
comment:
|
||||
- *9
|
||||
watches:
|
||||
- *21
|
||||
- *22
|
||||
- *5
|
||||
- *6
|
||||
- *9
|
||||
- *24
|
||||
- *25
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: watching
|
||||
cast_type: *31
|
||||
sql_type_metadata: *32
|
||||
cast_type: *32
|
||||
sql_type_metadata: *33
|
||||
'null': false
|
||||
default: true
|
||||
default_function:
|
||||
@@ -989,6 +1006,7 @@ primary_keys:
|
||||
accesses: id
|
||||
accounts: id
|
||||
action_text_markdowns: id
|
||||
action_text_rich_texts: id
|
||||
active_storage_attachments: id
|
||||
active_storage_blobs: id
|
||||
active_storage_variant_records: id
|
||||
@@ -1027,6 +1045,7 @@ data_sources:
|
||||
accesses: true
|
||||
accounts: true
|
||||
action_text_markdowns: true
|
||||
action_text_rich_texts: true
|
||||
active_storage_attachments: true
|
||||
active_storage_blobs: true
|
||||
active_storage_variant_records: true
|
||||
@@ -1131,6 +1150,25 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
action_text_rich_texts:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: action_text_rich_texts
|
||||
name: index_action_text_rich_texts_uniqueness
|
||||
unique: true
|
||||
columns:
|
||||
- record_type
|
||||
- record_id
|
||||
- name
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
active_storage_attachments:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: active_storage_attachments
|
||||
@@ -2161,4 +2199,4 @@ indexes:
|
||||
comment:
|
||||
valid: true
|
||||
workflows: []
|
||||
version: 20250515125505
|
||||
version: 20250523084734
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
require "rouge/plugins/redcarpet"
|
||||
|
||||
class MarkdownRenderer < Redcarpet::Render::HTML
|
||||
include Rouge::Plugins::Redcarpet
|
||||
|
||||
def self.build
|
||||
Redcarpet::Markdown.new MarkdownRenderer.new(filter_html: false),
|
||||
autolink: true, highlight: true, no_intra_emphasis: true,
|
||||
fenced_code_blocks: true, lax_spacing: true, strikethrough: true, tables: true
|
||||
end
|
||||
|
||||
def initialize(...)
|
||||
super
|
||||
@id_counts = Hash.new 0
|
||||
end
|
||||
|
||||
def header(text, header_level)
|
||||
unique_id(text).then do |id|
|
||||
<<~HTML.chomp
|
||||
<h#{header_level} id="#{id}">
|
||||
#{text} <a href="##{id}" class="heading__link" aria-hidden="true">#</a>
|
||||
</h#{header_level}>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
|
||||
def image(url, title, alt_text)
|
||||
<<~HTML.chomp
|
||||
<a title="#{title}" href="#{url}" data-action="lightbox#open:prevent" data-lightbox-target="image" data-lightbox-url-value="#{url}?disposition=attachment">
|
||||
<img src="#{url}" alt="#{alt_text}">
|
||||
</a>
|
||||
HTML
|
||||
end
|
||||
|
||||
def code_block(code, language)
|
||||
block_code(code, language) # call Rouge Redcarpet plugin
|
||||
end
|
||||
|
||||
def link(url, title, content)
|
||||
return video_tag(url, title) if video_url?(url)
|
||||
|
||||
attributes = { href: url }
|
||||
attributes[:title] = title if title
|
||||
attributes["data-turbo-frame"] = "_top"
|
||||
|
||||
"<a #{html_attributes(attributes)}>#{content}</a>"
|
||||
end
|
||||
|
||||
def autolink(url, link_type)
|
||||
attributes = { href: url }
|
||||
attributes["data-turbo-frame"] = "_top"
|
||||
|
||||
"<a #{html_attributes(attributes)}>#{url}</a>"
|
||||
end
|
||||
|
||||
private
|
||||
attr_reader :id_counts
|
||||
|
||||
def html_attributes(attributes)
|
||||
attributes.map { |key, value| %Q(#{key}="#{value}") }.join(" ")
|
||||
end
|
||||
|
||||
def unique_id(text)
|
||||
text.parameterize.then do |base_id|
|
||||
id_counts[base_id] += 1
|
||||
id_counts[base_id] > 1 ? "#{base_id}-#{id_counts[base_id]}" : base_id
|
||||
end
|
||||
end
|
||||
|
||||
def video_url?(url)
|
||||
File.extname(url).downcase.match?(/\.(mp4|webm|ogg|mov|avi|mkv)/)
|
||||
end
|
||||
|
||||
def video_tag(url, title)
|
||||
<<~HTML.chomp
|
||||
<video controls title="#{title}" width="1024">
|
||||
<source src="#{url}" type="video/#{File.extname(url).delete('.')}">
|
||||
</video>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
@@ -1,47 +0,0 @@
|
||||
module ActionText
|
||||
module HasMarkdown
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def has_markdown(name, strict_loading: strict_loading_by_default)
|
||||
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
||||
def #{name}
|
||||
markdown_#{name} || build_markdown_#{name}
|
||||
end
|
||||
|
||||
def #{name}_html
|
||||
#{name}.to_html
|
||||
end
|
||||
|
||||
def #{name}_plain_text
|
||||
#{name}.to_plain_text
|
||||
end
|
||||
|
||||
def #{name}?
|
||||
markdown_#{name}.present?
|
||||
end
|
||||
|
||||
def #{name}=(content)
|
||||
self.#{name}.content = content
|
||||
end
|
||||
CODE
|
||||
|
||||
has_one :"markdown_#{name}", -> { where(name: name) },
|
||||
class_name: "ActionText::Markdown", as: :record, inverse_of: :record, autosave: true, dependent: :destroy,
|
||||
strict_loading: strict_loading
|
||||
|
||||
scope :"with_markdown_#{name}", -> { includes("markdown_#{name}") }
|
||||
end
|
||||
end
|
||||
|
||||
def safe_markdown_attribute(name)
|
||||
if self.class.reflect_on_association("markdown_#{name}")&.klass == ActionText::Markdown
|
||||
public_send(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ActiveSupport.on_load :active_record do
|
||||
include ActionText::HasMarkdown
|
||||
end
|
||||
@@ -1,44 +0,0 @@
|
||||
module ActionText
|
||||
class Markdown < Record
|
||||
mattr_accessor :html_renderer
|
||||
mattr_accessor :plain_text_renderer
|
||||
|
||||
belongs_to :record, polymorphic: true, touch: true
|
||||
|
||||
def to_html
|
||||
to_unsafe_html.html_safe
|
||||
end
|
||||
|
||||
def to_unsafe_html
|
||||
if html_renderer.respond_to? :call
|
||||
html_renderer.call content
|
||||
else
|
||||
html_renderer.render content
|
||||
end
|
||||
end
|
||||
|
||||
def to_plain_text
|
||||
if plain_text_renderer.respond_to? :call
|
||||
plain_text_renderer.call content
|
||||
else
|
||||
plain_text_renderer.render content
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActionText::Markdown::Uploads
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
has_many_attached :uploads, dependent: :destroy
|
||||
end
|
||||
end
|
||||
|
||||
ActiveSupport.on_load :active_storage_attachment do
|
||||
class ActionText::Markdown
|
||||
include ActionText::Markdown::Uploads
|
||||
end
|
||||
end
|
||||
|
||||
ActiveSupport.run_load_hooks :action_text_markdown, ActionText::Markdown
|
||||
@@ -1,36 +0,0 @@
|
||||
module ActionText
|
||||
module TagHelper
|
||||
def markdown_area(record, name, value: nil, data: {}, **options)
|
||||
field_name = "#{record.class.model_name.param_key}[#{name}]"
|
||||
value = record.safe_markdown_attribute(name).content.to_s if value.nil?
|
||||
data = data.reverse_merge! uploads_url: uploads_url(format: "json")
|
||||
|
||||
tag.house_md value, name: field_name, data: data, **options
|
||||
end
|
||||
|
||||
def house_toolbar(**options, &block)
|
||||
tag.house_md_toolbar(**options, &block)
|
||||
end
|
||||
|
||||
def house_toolbar_button(action, **options, &block)
|
||||
tag.button title: action.to_s.humanize, data: { "house-md-action": action }, **options, &block
|
||||
end
|
||||
|
||||
def house_toolbar_file_upload_button(name: "upload", title: "Upload File", **options, &block)
|
||||
tag.label title: title, **options do
|
||||
safe_join [
|
||||
file_field_tag(name, data: { "house-md-toolbar-file-picker": true }, style: "display: none;"),
|
||||
capture(&block)
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActionView::Helpers
|
||||
class FormBuilder
|
||||
def markdown_area(method, **options)
|
||||
@template.markdown_area(@object, method, **options)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,32 +0,0 @@
|
||||
module ActiveStorage::Sluggable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_create :set_slug
|
||||
end
|
||||
|
||||
def slug_url(host: ActiveStorage::Current.url_options[:host], port: ActiveStorage::Current.url_options[:port])
|
||||
Rails.application.routes.url_helpers.upload_url(slug, host: host, port: port)
|
||||
end
|
||||
|
||||
private
|
||||
def set_slug
|
||||
self.slug = "#{slug_basename}-#{SecureRandom.alphanumeric(6)}.#{slug_extension}"
|
||||
end
|
||||
|
||||
def slug_basename
|
||||
File.basename(slug_filename, ".*").parameterize
|
||||
end
|
||||
|
||||
def slug_extension
|
||||
File.extname(slug_filename).delete(".").parameterize
|
||||
end
|
||||
|
||||
def slug_filename
|
||||
slug.presence || filename.to_s
|
||||
end
|
||||
end
|
||||
|
||||
ActiveSupport.on_load :active_storage_attachment do
|
||||
ActiveStorage::Attachment.include ActiveStorage::Sluggable
|
||||
end
|
||||
@@ -214,9 +214,6 @@ class EnactTenanting
|
||||
assert_count Tagging, Tagging.count
|
||||
assert_count Watch, Watch.count
|
||||
|
||||
# we're only copying the markdown records that are still accessible.
|
||||
assert_count ActionText::Markdown, Comment.count
|
||||
|
||||
assert_count Event, Event.count
|
||||
assert_count Notification, Notification.count
|
||||
|
||||
@@ -228,22 +225,7 @@ class EnactTenanting
|
||||
end
|
||||
|
||||
def update_action_text_urls
|
||||
update_counter["ActionText::Markdown"] = 0
|
||||
TENANTS.each do |tenant|
|
||||
tenanted_domain = sprintf(TENANTED_DOMAIN, tenant: tenant)
|
||||
|
||||
ApplicationRecord.with_tenant(tenant) do
|
||||
ActionText::Markdown.all.each do |markdown|
|
||||
content = markdown.content
|
||||
next unless content =~ %r{#{CURRENT_DOMAIN}/u/}
|
||||
|
||||
content.gsub!(%r{#{CURRENT_DOMAIN}/u/}, "#{tenanted_domain}/u/")
|
||||
|
||||
markdown.update_column :content, content
|
||||
update_counter["ActionText::Markdown"] += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
raise "No more markdown"
|
||||
end
|
||||
|
||||
def hardlink_active_storage
|
||||
|
||||
@@ -100,9 +100,9 @@ ApplicationRecord.with_each_tenant do |tenant|
|
||||
end
|
||||
|
||||
# Update action_text_markdowns table (polymorphic relationship)
|
||||
ActionText::Markdown.where(record_type: "Card").find_each do |markdown|
|
||||
if id_mapping[markdown.record_id]
|
||||
markdown.update_column(:record_id, id_mapping[markdown.record_id])
|
||||
ActionText::RichText.where(record_type: "Card").find_each do |rich_text|
|
||||
if id_mapping[rich_text.record_id]
|
||||
rich_text.update_column(:record_id, id_mapping[rich_text.record_id])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -73,9 +73,9 @@ ApplicationRecord.with_each_tenant do |tenant|
|
||||
end
|
||||
|
||||
# Update action_text_markdowns table (polymorphic relationship)
|
||||
ActionText::Markdown.where(record_type: "Collection").find_each do |markdown|
|
||||
if id_mapping[markdown.record_id]
|
||||
markdown.update_column(:record_id, id_mapping[markdown.record_id])
|
||||
ActionText::RichText.where(record_type: "Collection").find_each do |rich_text|
|
||||
if id_mapping[rich_text.record_id]
|
||||
rich_text.update_column(:record_id, id_mapping[rich_text.record_id])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class CardsControllerTest < ActionDispatch::IntegrationTest
|
||||
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.description.to_plain_text.strip
|
||||
end
|
||||
|
||||
test "users can only see cards in collections they have access to" do
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
# one:
|
||||
# record: name_of_fixture (ClassOfFixture)
|
||||
# name: content
|
||||
# body: <p>In a <i>million</i> stars!</p>
|
||||
Reference in New Issue
Block a user