Revert "Replace House with Lexical"
This commit is contained in:
@@ -177,17 +177,6 @@
|
||||
--color-card-7: oklch(var(--lch-purple-medium));
|
||||
--color-card-8: oklch(var(--lch-pink-medium));
|
||||
|
||||
/* Colors: Syntax highlighting */
|
||||
--color-code-token__att: oklch(var(--lch-blue-dark));
|
||||
--color-code-token__comment: oklch(var(--lch-ink-medium));
|
||||
--color-code-token__function: oklch(var(--lch-purple-dark));
|
||||
--color-code-token__operator: oklch(var(--lch-red-dark));
|
||||
--color-code-token__property: oklch(var(--lch-purple-dark));
|
||||
--color-code-token__punctuation: oklch(var(--lch-ink-dark));
|
||||
--color-code-token__selector: oklch(var(--lch-green-dark));
|
||||
--color-code-token__variable: oklch(var(--lch-red-dark));
|
||||
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
--lch-canvas: 20% 0.0195 232.58;
|
||||
--lch-ink-inverted: var(--lch-black);
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
lexical-editor {
|
||||
.node--selected {
|
||||
&:not(:has(img)) {
|
||||
box-shadow: 0 0 0 var(--hover-size) var(--hover-color);
|
||||
}
|
||||
|
||||
&:has(img) {
|
||||
img {
|
||||
box-shadow: 0 0 0 var(--hover-size) var(--hover-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lexical-dialog-actions {
|
||||
display: flex;
|
||||
font-size: var(--text-x-small);
|
||||
flex: 1 1 0%;
|
||||
gap: var(--inline-space-half);
|
||||
margin-block-start: var(--block-space-half);
|
||||
|
||||
.btn {
|
||||
--radius: 0.3em;
|
||||
|
||||
inline-size: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
span {
|
||||
inline-size: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.lexical-editor__content {
|
||||
--outline-size: max(2px, 0.08em);
|
||||
|
||||
margin: var(--block-space-half) 0;
|
||||
min-block-size: calc(7lh + var(--block-space));
|
||||
outline: 0;
|
||||
padding: var(--block-space-half) var(--inline-space);
|
||||
|
||||
* {
|
||||
&:first-child {
|
||||
margin-block-start: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-block-end: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lexical-editor--drag-over {
|
||||
background-color: var(--color-selected);
|
||||
border-radius: 4px;
|
||||
outline: 2px dashed var(--color-selected-dark);
|
||||
}
|
||||
|
||||
lexical-toolbar {
|
||||
background-color: inherit;
|
||||
border-block-end: 1px solid var(--color-ink-light);
|
||||
color: currentColor;
|
||||
display: flex;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
max-inline-size: 100%;
|
||||
padding: 0.2em 0;
|
||||
position: relative;
|
||||
|
||||
dialog {
|
||||
background-color: var(--color-canvas);
|
||||
border: 1px solid var(--color-ink-lighter);
|
||||
border-radius: 0.5em;
|
||||
box-shadow: var(--shadow);
|
||||
color: var(--color-ink);
|
||||
padding: var(--block-space) calc(var(--inline-space) * 1.5);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
> button {
|
||||
aspect-ratio: 4/3.5;
|
||||
appearance: none;
|
||||
background-color: transparent;
|
||||
block-size: 2em;
|
||||
border: none;
|
||||
border-radius: 0.2em;
|
||||
color: currentColor;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
font-size: inherit;
|
||||
inline-size: auto;
|
||||
place-items: center;
|
||||
transition: background-color 300ms ease;
|
||||
|
||||
svg {
|
||||
-webkit-touch-callout: none;
|
||||
block-size: 0.85em;
|
||||
fill: currentColor;
|
||||
grid-area: 1/1;
|
||||
inline-size: auto;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&:is(:focus, :hover) {
|
||||
background-color: var(--color-ink-lighter);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:is(:active) {
|
||||
background-color: var(--color-selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,13 +150,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.card-field__description {
|
||||
lexical-toolbar {
|
||||
border-block-start: 1px solid var(--color-ink-light);
|
||||
margin-block-start: var(--block-margin) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.card__content {
|
||||
flex: 2 1 auto;
|
||||
max-inline-size: 100%;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@layer components {
|
||||
.comments {
|
||||
--avatar-size: 2.33em;
|
||||
--comment-padding-block: var(--block-space-half);
|
||||
--comment-padding-block: var(--block-space);
|
||||
--comment-padding-inline: var(--inline-space-double);
|
||||
--comment-max: 70ch;
|
||||
--reaction-size: 2rem;
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
|
||||
.comment__avatar {
|
||||
margin: calc(var(--comment-padding-block) * 0.75) calc(var(--comment-padding-inline) * -0.75);
|
||||
margin: calc(var(--comment-padding-block) * 0.5) calc(var(--comment-padding-inline) * -0.75);
|
||||
z-index: 0;
|
||||
|
||||
.comment--mine_ & {
|
||||
@@ -64,7 +64,7 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
* {
|
||||
p {
|
||||
&:first-child {
|
||||
margin-block-start: 0;
|
||||
}
|
||||
@@ -83,8 +83,6 @@
|
||||
border-radius: 0.2em;
|
||||
padding:
|
||||
var(--comment-padding-block)
|
||||
var(--comment-padding-inline)
|
||||
calc(var(--comment-padding-block) * 1.5)
|
||||
var(--comment-padding-inline);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
@@ -115,7 +113,7 @@
|
||||
line-height: 1.2;
|
||||
max-inline-size: var(--comment-max);
|
||||
text-align: center;
|
||||
|
||||
|
||||
|
||||
&::before {
|
||||
/* Make up space for lack of avatar */
|
||||
@@ -135,4 +133,17 @@
|
||||
text-align: center !important;
|
||||
}
|
||||
}
|
||||
|
||||
.comment__input {
|
||||
--input-border-size: 0;
|
||||
--input-padding: 0;
|
||||
|
||||
min-block-size: calc(9lh + (2 * var(--comment-padding-block)));
|
||||
min-inline-size: 100%;
|
||||
|
||||
@supports (field-sizing: content) {
|
||||
field-sizing: content;
|
||||
min-block-size: calc(9lh + (2 * var(--comment-padding-block)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
@layer components {
|
||||
.markdown-content {
|
||||
:where(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6) {
|
||||
font-weight: 800;
|
||||
hyphens: auto;
|
||||
letter-spacing: -0.02ch;
|
||||
line-height: 1.1;
|
||||
margin-block: 0;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
:where(h1, h2, h3, h4, h5, h6) { display: block; }
|
||||
:where(h1, h2, h3, h4, h5, h6) { margin-block: 0.65em; }
|
||||
|
||||
:is(h1, .h1) { font-size: 2em; }
|
||||
:is(h2, .h2) { font-size: 1.5em; }
|
||||
:is(h3, .h3) { font-size: 1.17em; }
|
||||
:is(h4, .h4) { font-size: 1em; }
|
||||
:is(h5, .h5) { font-size: 0.83em; }
|
||||
:is(h6, .h6) { font-size: 0.67em; }
|
||||
|
||||
:where(p, ul, ol, dl, blockquote, pre, figure, table, hr) {
|
||||
margin-block: 0.65lh;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
:where(hr) {
|
||||
border-color: var(--color-ink-medium);
|
||||
border-style: var(--border-style, solid) none none;
|
||||
margin: 2lh auto;
|
||||
}
|
||||
|
||||
:where(strong) {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
:is(pre, code, .pre, .code) {
|
||||
background-color: var(--color-ink-lightest);
|
||||
border: 1px solid var(--color-ink-lighter);
|
||||
border-radius: 0.3em;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
:is(pre) {
|
||||
overflow-x: auto;
|
||||
/* text-wrap: nowrap; */
|
||||
}
|
||||
|
||||
:where(code) {
|
||||
padding: 0.1em 0.3em;
|
||||
}
|
||||
|
||||
:is(pre, .pre) {
|
||||
border-radius: 0.5em;
|
||||
padding: 0.5lh 2ch;
|
||||
|
||||
:is(code, .code) {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
font-size: 1em;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
:where(p) {
|
||||
hyphens: auto;
|
||||
letter-spacing: -0.005ch;
|
||||
}
|
||||
|
||||
:is(blockquote, .quote) {
|
||||
font-style: italic;
|
||||
margin: 0 3ch;
|
||||
|
||||
:is(p) {
|
||||
hyphens: none;
|
||||
}
|
||||
}
|
||||
|
||||
:where(table, th, td) {
|
||||
border: 1px solid var(--color-ink-medium);
|
||||
}
|
||||
|
||||
:where(table) {
|
||||
border-collapse: collapse;
|
||||
margin: 1lh 0;
|
||||
}
|
||||
|
||||
:where(th, td) {
|
||||
padding: 0.2lh 1ch;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
:where(th) {
|
||||
border-block-end-width: 3px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
:where(img, video, embed, object) {
|
||||
max-block-size: 32rem;
|
||||
|
||||
/* Links should hug media contained within */
|
||||
a:has(&) {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,331 +0,0 @@
|
||||
@layer components {
|
||||
.rich-text-content {
|
||||
--block-margin: 0.65lh;
|
||||
|
||||
:where(h1, h2, h3, h4, h5, h6) {
|
||||
display: block;
|
||||
font-weight: 800;
|
||||
hyphens: auto;
|
||||
letter-spacing: -0.02ch;
|
||||
line-height: 1.1;
|
||||
margin-block: var(--block-margin);
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
:where(h1) { font-size: 2em; }
|
||||
:where(h2) { font-size: 1.5em; }
|
||||
:where(h3) { font-size: 1.17em; }
|
||||
:where(h4) { font-size: 1em; }
|
||||
:where(h5) { font-size: 0.83em; }
|
||||
:where(h6) { font-size: 0.67em; }
|
||||
|
||||
:where(p, ul, ol, dl, blockquote, figure, .attachment) {
|
||||
margin-block: var(--block-margin);
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
:where(b, strong) {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
:where(p, blockquote) {
|
||||
hyphens: auto;
|
||||
letter-spacing: -0.005ch;
|
||||
}
|
||||
|
||||
:where(blockquote) {
|
||||
border-inline-start: 0.25em solid var(--color-ink-lighter);
|
||||
font-style: italic;
|
||||
margin: var(--block-margin) 0;
|
||||
padding: 0.5lh 2ch;
|
||||
}
|
||||
|
||||
:where(img, video, embed, object) {
|
||||
margin-inline: auto;
|
||||
max-block-size: 32rem;
|
||||
|
||||
/* Links should hug media contained within */
|
||||
a:has(&) {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attachments */
|
||||
.attachment {
|
||||
block-size: auto;
|
||||
display: inline-block;
|
||||
inline-size: 100%;
|
||||
position: relative;
|
||||
margin-inline: 0;
|
||||
max-inline-size: 100%;
|
||||
|
||||
&:is(figure) img {
|
||||
block-size: auto;
|
||||
display: block;
|
||||
margin-inline: auto;
|
||||
max-inline-size: 100%;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
:where(progress) {
|
||||
inline-size: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.attachment__caption {
|
||||
color: var(--color-ink-dark);
|
||||
display: flex;
|
||||
font-size: var(--text-small);
|
||||
flex-wrap: wrap;
|
||||
line-height: 1.3;
|
||||
column-gap: 0.5ch;
|
||||
justify-content: center;
|
||||
margin: var(--block-space-half) var(--inline-space);
|
||||
text-align: center;
|
||||
|
||||
.input {
|
||||
inline-size: 100%;
|
||||
max-inline-size: 100%;
|
||||
text-align: center;
|
||||
|
||||
@supports (field-sizing: content) {
|
||||
field-sizing: content;
|
||||
inline-size: auto;
|
||||
min-inline-size: 20ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.attachment__figure {
|
||||
--hover-size: 0;
|
||||
}
|
||||
|
||||
.attachment--file {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
|
||||
.attachment__caption {
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
text-align: start;
|
||||
|
||||
strong {
|
||||
color: var(--color-ink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.attachment__icon {
|
||||
aspect-ratio: 4/5;
|
||||
background-color: var(--color-canvas);
|
||||
block-size: calc(2.5lh + 0.5ch);
|
||||
border: 2px solid var(--color-ink-medium);
|
||||
border-radius: 0.3em;
|
||||
color: var(--color-ink-dark);
|
||||
display: inline-grid;
|
||||
font-size: var(--text-small);
|
||||
font-weight: 800;
|
||||
inline-size: auto;
|
||||
overflow: clip;
|
||||
padding-block-start: 0.4lh;
|
||||
place-content: center;
|
||||
position: relative;
|
||||
text-transform: uppercase;
|
||||
|
||||
&::before {
|
||||
background-color: var(--color-ink-medium);
|
||||
block-size: 0.5lh;
|
||||
content: "";
|
||||
display: block;
|
||||
inline-size: 100%;
|
||||
inset: 0 0 auto;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.attachment--psd &,
|
||||
.attachment--key &,
|
||||
.attachment--sketch &,
|
||||
.attachment--ai &,
|
||||
.attachment--eps &,
|
||||
.attachment--indd &,
|
||||
.attachment--svg &,
|
||||
.attachment--ppt &,
|
||||
.attachment--pptx & {
|
||||
color: oklch(var(--lch-red-dark));
|
||||
background-color: oklch(var(--lch-red-lightest));
|
||||
border-color: oklch(var(--lch-red-medium));
|
||||
|
||||
&::before {
|
||||
background-color: oklch(var(--lch-red-medium));
|
||||
}
|
||||
}
|
||||
|
||||
.attachment--css &,
|
||||
.attachment--php &,
|
||||
.attachment--json &,
|
||||
.attachment--htm &,
|
||||
.attachment--html &,
|
||||
.attachment--rb &,
|
||||
.attachment--erb &,
|
||||
.attachment--ts &,
|
||||
.attachment--js & {
|
||||
color: oklch(var(--lch-purple-dark));
|
||||
background-color: oklch(var(--lch-purple-lightest));
|
||||
border-color: oklch(var(--lch-purple-medium));
|
||||
|
||||
&::before {
|
||||
background-color: oklch(var(--lch-purple-medium));
|
||||
}
|
||||
}
|
||||
|
||||
.attachment--txt &,
|
||||
.attachment--pages &,
|
||||
.attachment--rtf &,
|
||||
.attachment--md &,
|
||||
.attachment--doc &,
|
||||
.attachment--docx & {
|
||||
color: oklch(var(--lch-blue-dark));
|
||||
background-color: oklch(var(--lch-blue-lightest));
|
||||
border-color: oklch(var(--lch-blue-medium));
|
||||
|
||||
&::before {
|
||||
background-color: oklch(var(--lch-blue-medium));
|
||||
}
|
||||
}
|
||||
|
||||
.attachment--csv &,
|
||||
.attachment--numbers &,
|
||||
.attachment--xls &,
|
||||
.attachment--xlsx & {
|
||||
color: oklch(var(--lch-green-dark));
|
||||
background-color: oklch(var(--lch-green-lightest));
|
||||
border-color: oklch(var(--lch-green-medium));
|
||||
|
||||
&::before {
|
||||
background-color: oklch(var(--lch-green-medium));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.attachment__link {
|
||||
--hover-size: 0;
|
||||
|
||||
color: var(--color-link);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Attachment junk gets wrapped in a paragraph causing unwanted space */
|
||||
p:has(action-text-attachment) {
|
||||
display: none;
|
||||
|
||||
+ * {
|
||||
margin-block-start: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Avoid extra space due to empty paragraphs */
|
||||
p:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Code */
|
||||
:where(code, pre) {
|
||||
background-color: var(--color-canvas);
|
||||
border: 1px solid var(--color-ink-lighter);
|
||||
border-radius: 0.3em;
|
||||
color: var(--color-ink);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.85em;
|
||||
font-weight: 500;
|
||||
margin-block: var(--block-margin);
|
||||
padding: 0.1em 0.3em;
|
||||
|
||||
&[data-language] {
|
||||
border-radius: 0.5em;
|
||||
display: block;
|
||||
hyphens: none;
|
||||
overflow-x: auto;
|
||||
padding: 0.5lh 2ch;
|
||||
tab-size: 2;
|
||||
text-wrap: nowrap;
|
||||
white-space: pre;
|
||||
word-break: break-word;
|
||||
|
||||
/* Keywords and attributes */
|
||||
.code-token__attr,
|
||||
.token.atrule,
|
||||
.token.attr,
|
||||
.token.keyword {
|
||||
color: var(--color-code-token__att);
|
||||
}
|
||||
|
||||
/* Constants, booleans, numbers, properties, tags */
|
||||
.code-token__property,
|
||||
.token.boolean,
|
||||
.token.constant,
|
||||
.token.deleted,
|
||||
.token.number,
|
||||
.token.property,
|
||||
.token.symbol,
|
||||
.token.tag {
|
||||
color: var(--color-code-token__property);
|
||||
}
|
||||
|
||||
/* Strings, selectors, and built-in constructs */
|
||||
.code-token__selector,
|
||||
.token.builtin,
|
||||
.token.char,
|
||||
.token.inserted,
|
||||
.token.selector,
|
||||
.token.string {
|
||||
color: var(--color-code-token__selector);
|
||||
}
|
||||
|
||||
/* Comments and meta information */
|
||||
.code-token__comment,
|
||||
.token.cdata,
|
||||
.token.comment,
|
||||
.token.doctype,
|
||||
.token.prolog {
|
||||
color: var(--color-code-token__comment);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Operators and symbolic entities */
|
||||
.code-token__operator,
|
||||
.token.entity,
|
||||
.token.operator,
|
||||
.token.url {
|
||||
color: var(--color-code-token__operator);
|
||||
}
|
||||
|
||||
/* Functions and class names */
|
||||
.code-token__function,
|
||||
.token.class,
|
||||
.token.class-name,
|
||||
.token.function {
|
||||
color: var(--color-code-token__function);
|
||||
}
|
||||
|
||||
/* Variables, regex, namespaces, important */
|
||||
.code-token__variable,
|
||||
.token.important,
|
||||
.token.namespace,
|
||||
.token.regex,
|
||||
.token.variable {
|
||||
color: var(--color-code-token__variable);
|
||||
}
|
||||
|
||||
/* Punctuation */
|
||||
.code-token__punctuation,
|
||||
.token.punctuation {
|
||||
color: var(--color-code-token__punctuation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
module ExcerptHelper
|
||||
def format_excerpt(content, length: 200)
|
||||
return "" if content.blank?
|
||||
|
||||
text = content.to_plain_text
|
||||
text = text.gsub(/^>\s*(.*)$/m, '> \1')
|
||||
text = text.gsub(/^[-*]\s*(.*)$/m, '• \1')
|
||||
text = text.gsub(/^\d+\.\s*(.*)$/m) { |m| m }
|
||||
text = text.gsub(/\s+/, " ").strip
|
||||
text.truncate(length)
|
||||
end
|
||||
end
|
||||
@@ -58,7 +58,7 @@ module NotificationsHelper
|
||||
|
||||
def comment_notification_body(event)
|
||||
comment = event.eventable
|
||||
"#{strip_tags(comment.body.to_s).blank? ? "#{event.creator.name} replied" : "#{event.creator.name}:" } #{strip_tags(comment.body.to_s).truncate(200)}"
|
||||
"#{strip_tags(comment.body_html).blank? ? "#{event.creator.name} replied" : "#{event.creator.name}:" } #{strip_tags(comment.body_html).truncate(200)}"
|
||||
end
|
||||
|
||||
def card_notification_title(card)
|
||||
|
||||
@@ -2,6 +2,4 @@
|
||||
import "@hotwired/turbo-rails"
|
||||
import "initializers"
|
||||
import "controllers"
|
||||
|
||||
import "actiontext-lexical"
|
||||
import "@rails/actiontext"
|
||||
import "house"
|
||||
|
||||
@@ -30,10 +30,9 @@ export default class extends Controller {
|
||||
|
||||
async restoreContent() {
|
||||
await nextFrame()
|
||||
let savedContent = localStorage.getItem(this.keyValue)
|
||||
const savedContent = localStorage.getItem(this.keyValue)
|
||||
|
||||
if (savedContent) {
|
||||
savedContent = `<div>${savedContent}</div>` // temporary for old markdown saves
|
||||
this.inputTarget.value = savedContent
|
||||
this.#triggerChangeEvent(savedContent)
|
||||
}
|
||||
@@ -46,8 +45,8 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
#triggerChangeEvent(newValue) {
|
||||
if (this.inputTarget.tagName === "LEXICAL-EDITOR") {
|
||||
this.inputTarget.dispatchEvent(new CustomEvent('actiontext:change', {
|
||||
if (this.inputTarget.tagName === "HOUSE-MD") {
|
||||
this.inputTarget.dispatchEvent(new CustomEvent('house-md:change', {
|
||||
bubbles: true,
|
||||
detail: {
|
||||
previousContent: '',
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
pasteFiles(event) {
|
||||
const editor = event.target.closest("house-md")
|
||||
if (!editor) return
|
||||
|
||||
const files = event.clipboardData?.files
|
||||
if (!files?.length) return
|
||||
|
||||
event.preventDefault()
|
||||
|
||||
for (const file of files) {
|
||||
const uploadEvent = new CustomEvent("house-md:before-upload", {
|
||||
bubbles: true,
|
||||
detail: { file },
|
||||
cancelable: true
|
||||
})
|
||||
|
||||
if (editor.dispatchEvent(uploadEvent)) {
|
||||
const upload = document.createElement("house-md-upload")
|
||||
upload.file = file
|
||||
upload.uploadsURL = editor.dataset.uploadsUrl
|
||||
editor.appendChild(upload)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
import { highlightAll } from "actiontext-lexical"
|
||||
|
||||
export default class extends Controller {
|
||||
connect() {
|
||||
highlightAll()
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -9,7 +9,7 @@ class Card < ApplicationRecord
|
||||
has_many :comments, dependent: :destroy
|
||||
has_one_attached :image, dependent: :purge_later
|
||||
|
||||
has_rich_text :description
|
||||
has_markdown :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_rich_text :body
|
||||
has_markdown :body
|
||||
searchable_by :body_plain_text, using: :comments_search_index, as: :body
|
||||
|
||||
scope :chronologically, -> { order created_at: :asc, id: :desc }
|
||||
@@ -19,10 +19,6 @@ 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
|
||||
rich_text_associations.collect { send(it.name)&.to_plain_text }.compact.join(" ")
|
||||
markdown_associations.collect { send(it.name)&.to_plain_text }.compact.join(" ")
|
||||
end
|
||||
|
||||
private
|
||||
@@ -32,12 +32,12 @@ module Mentions
|
||||
collection.users
|
||||
end
|
||||
|
||||
def rich_text_associations
|
||||
self.class.reflect_on_all_associations(:has_one).filter { it.klass == ActionText::RichText }
|
||||
def markdown_associations
|
||||
self.class.reflect_on_all_associations(:has_one).filter { it.klass == ActionText::Markdown }
|
||||
end
|
||||
|
||||
def mentionable_content_changed?
|
||||
rich_text_associations.any? { send(it.name).body_previously_changed? }
|
||||
markdown_associations.any? { send(it.name).content_previously_changed? }
|
||||
end
|
||||
|
||||
def create_mentions_later
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<% if blob.representable? %>
|
||||
<figure class="attachment attachment--preview attachment--<%= blob.filename.extension %>">
|
||||
<%= render "active_storage/blobs/web/representation", blob: blob %>
|
||||
|
||||
<figcaption class="attachment__caption">
|
||||
<% if caption = blob.try(:caption) %>
|
||||
<span><%= caption %></span>
|
||||
<% else %>
|
||||
<span class="attachment__name"><%= blob.filename %></span>
|
||||
<% end %>
|
||||
<span> · </span>
|
||||
<span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
|
||||
<span> · </span>
|
||||
<%= link_to rails_blob_path(blob, disposition: :attachment), class: "attachment__link", download: blob.filename, title: "Download #{blob.filename}" do %>
|
||||
<span>Download</span>
|
||||
<% end %>
|
||||
</figcaption>
|
||||
</figure>
|
||||
<% else %>
|
||||
<div class="attachment attachment--file attachment--<%= blob.filename.extension -%>">
|
||||
<%= link_to rails_blob_path(blob, disposition: :attachment), class: "attachment__figure", download: blob.filename, title: "Download #{blob.filename}" do %>
|
||||
<%= render "active_storage/blobs/web/representation", blob: blob %>
|
||||
<% end %>
|
||||
|
||||
<div class="attachment__caption">
|
||||
<div>
|
||||
<% if caption = blob.try(:caption) %>
|
||||
<strong><%= caption %></strong>
|
||||
<% else %>
|
||||
<strong class="attachment__name"><%= blob.filename %></strong>
|
||||
<% end %>
|
||||
</div>
|
||||
<div>
|
||||
<span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
|
||||
<span> · </span>
|
||||
<%= link_to rails_blob_path(blob, disposition: :attachment), class: "attachment__link", download: blob.filename, title: "Download #{blob.filename}" do %>
|
||||
<span>Download</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -1,19 +0,0 @@
|
||||
<% size = local_assigns[:in_gallery] ? [800, 600] : [1024, 768] %>
|
||||
|
||||
<% if blob.video? %>
|
||||
<%= tag.video \
|
||||
src: rails_blob_path(blob),
|
||||
controls: true,
|
||||
preload: :none,
|
||||
width: "100%", height: "100%" %>
|
||||
<% elsif blob.audio? %>
|
||||
<audio controls="true" width="100%" preload="metadata">
|
||||
<source src="<%= rails_blob_url(blob) %>" type="<%= blob.content_type %>">
|
||||
</audio>
|
||||
<% elsif blob.variable? %>
|
||||
<%= image_tag url_for(blob.variant(loader: { n: -1 }, resize_to_limit: size)) %>
|
||||
<% elsif blob.previewable? %>
|
||||
<%= image_tag url_for(blob.preview(resize_to_limit: size)) %>
|
||||
<% else %>
|
||||
<span class="attachment__icon"><%= blob.filename.extension&.downcase.presence || "unknown" %></span>
|
||||
<% end %>
|
||||
@@ -28,8 +28,8 @@
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="comment__body rich-text-content txt-align-start" data-controller="syntax-highlight">
|
||||
<%= comment.body %>
|
||||
<div class="comment__body markdown-content txt-align-start">
|
||||
<%= sanitize comment.body_html %>
|
||||
</div>
|
||||
|
||||
<%= render "cards/comments/reactions/reactions", comment: comment %>
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
</figure>
|
||||
|
||||
<div class="comment__content flex-inline flex-column full-width">
|
||||
<div class="comment__body rich-text-content txt-align-start">
|
||||
<div class="comment__body markdown-content txt-align-start">
|
||||
<%= form_with model: Comment.new, url: card_comments_path(card), class: "flex flex-column gap full-width",
|
||||
data: { controller: "form local-save",
|
||||
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" } do |form| %>
|
||||
<%= form.rich_textarea :body, required: true, placeholder: new_comment_placeholder(card),
|
||||
data: { local_save_target: "input", action: "actiontext:change->local-save#save turbo:morph-element->local-save#restoreContent" } %>
|
||||
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),
|
||||
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>
|
||||
<% end %>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
</figure>
|
||||
|
||||
<div class="comment__content flex flex-column flex-item-grow full-width">
|
||||
<div class="comment__body rich-text-content txt-align-start">
|
||||
<div class="comment__body markdown-content txt-align-start">
|
||||
<%= form_with model: [ @card, @comment ], class: "flex flex-column gap full-width",
|
||||
data: { controller: "form", action: "keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop" } do |form| %>
|
||||
<%= form.rich_textarea :body, required: true, autofocus: true, placeholder: new_comment_placeholder(@card) %>
|
||||
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) %>
|
||||
<div class="flex gap-half justify-start">
|
||||
<%= form.button class: "btn btn--reversed", type: :submit do %>
|
||||
<span>Save changes</span>
|
||||
|
||||
@@ -4,23 +4,23 @@
|
||||
<h1 class="card__title flex align-start gap-half">
|
||||
<%= link_to card.title, edit_collection_card_path(card.collection, card), class: "card__title-link" %>
|
||||
</h1>
|
||||
<div class="card__description rich-text-content margin-block-half rich-text-content" data-controller="syntax-highlight">
|
||||
<%= card.description %>
|
||||
<div class="card__description markdown-content margin-block-half">
|
||||
<%= sanitize card.description_html %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= form_with model: card, url: collection_card_path(card.collection, card), id: "card_form", class: "card__content", data: { controller: "auto-save" } do |form| %>
|
||||
<%= form_with model: card, url: collection_card_path(card.collection, card), id: "card_form", class: "card__content", data: { controller: "paste auto-save" } do |form| %>
|
||||
<h1 class="card__title">
|
||||
<%= form.text_area :title, placeholder: "Name it…",
|
||||
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" } %>
|
||||
</h1>
|
||||
<div class="card__description rich-text-content margin-block-start-half margin-block-end">
|
||||
<%= form.rich_textarea :description, class: "card-field__description",
|
||||
<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: "actiontext: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" } %>
|
||||
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>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%= turbo_frame_tag @card, :edit do %>
|
||||
<%= form_with model: @card, url: collection_card_path(@card.collection, @card), class: "card__content", data: { controller: "form" } do |form| %>
|
||||
<%= form_with model: @card, url: collection_card_path(@card.collection, @card), class: "card__content", data: { controller: "form paste" } do |form| %>
|
||||
<h1 class="card__title">
|
||||
<%= 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",
|
||||
@@ -8,10 +8,10 @@
|
||||
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>
|
||||
|
||||
<%= form.rich_textarea :description, class: "card-field__description rich-text-content",
|
||||
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" } %>
|
||||
<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" } %>
|
||||
</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">
|
||||
<%= format_excerpt(event&.eventable.body, length: 200) -%>
|
||||
<%= strip_tags(event&.eventable.body_html).truncate(200) -%>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<div class="action-text-content">
|
||||
<%= yield -%>
|
||||
</div>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<%= page_title_tag %>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, interactive-widget=resizes-content">
|
||||
<meta name="view-transition" content="same-origin">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
|
||||
|
||||
Reference in New Issue
Block a user