diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj index a11677e4a..60ff1fe5b 100644 --- a/backend/src/app/rpc/commands/comments.clj +++ b/backend/src/app/rpc/commands/comments.clj @@ -38,6 +38,8 @@ (def r-mentions-split #"@\[[^\]]*\]\([^\)]*\)") (def r-mentions #"@\[([^\]]*)\]\(([^\)]*)\)") +(def comment-max-length 750) + (defn- format-comment [{:keys [content]}] (->> (d/interleave-all @@ -442,7 +444,7 @@ [:map {:title "create-comment-thread"} [:file-id ::sm/uuid] [:position ::gpt/point] - [:content [:string {:max 750}]] + [:content [:string {:max comment-max-length}]] [:page-id ::sm/uuid] [:frame-id ::sm/uuid] [:share-id {:optional true} [:maybe ::sm/uuid]] @@ -585,7 +587,7 @@ schema:create-comment [:map {:title "create-comment"} [:thread-id ::sm/uuid] - [:content [:string {:max 250}]] + [:content [:string {:max comment-max-length}]] [:share-id {:optional true} [:maybe ::sm/uuid]] [:mentions {:optional true} [::sm/set ::sm/uuid]]]) @@ -655,7 +657,7 @@ schema:update-comment [:map {:title "update-comment"} [:id ::sm/uuid] - [:content [:string {:max 250}]] + [:content [:string {:max comment-max-length}]] [:share-id {:optional true} [:maybe ::sm/uuid]] [:mentions {:optional true} [::sm/set ::sm/uuid]]]) diff --git a/common/src/app/common/logging.cljc b/common/src/app/common/logging.cljc index 77318c864..7a4df8ebe 100644 --- a/common/src/app/common/logging.cljc +++ b/common/src/app/common/logging.cljc @@ -275,7 +275,7 @@ [_ _ _ {:keys [::logger ::props ::level ::cause ::trace ::message]}] (when (enabled? logger level) (let [hstyles (str/ffmt "font-weight: 600; color: %" (level->color level)) - mstyles (str/ffmt "font-weight: 300; color: %" "#282a2e") + mstyles (str/ffmt "font-weight: 300; color: %" (level->color level)) header (str/concat "%c" (level->name level) " [" logger "] ") message (str/concat header "%c" @message)] diff --git a/docs/img/layers/copy-css.webp b/docs/img/layers/copy-css.webp new file mode 100644 index 000000000..fd9422b47 Binary files /dev/null and b/docs/img/layers/copy-css.webp differ diff --git a/docs/img/objects/board-copy-link.webp b/docs/img/objects/board-copy-link.webp new file mode 100644 index 000000000..324833b3e Binary files /dev/null and b/docs/img/objects/board-copy-link.webp differ diff --git a/docs/img/styling/copy-properties.mp4 b/docs/img/styling/copy-properties.mp4 new file mode 100644 index 000000000..feb21994f Binary files /dev/null and b/docs/img/styling/copy-properties.mp4 differ diff --git a/docs/img/styling/copy-properties.webp b/docs/img/styling/copy-properties.webp new file mode 100644 index 000000000..d2d77f458 Binary files /dev/null and b/docs/img/styling/copy-properties.webp differ diff --git a/docs/user-guide/introduction/shortcuts.njk b/docs/user-guide/introduction/shortcuts.njk index cfc2b5acf..71db0cbb6 100644 --- a/docs/user-guide/introduction/shortcuts.njk +++ b/docs/user-guide/introduction/shortcuts.njk @@ -130,6 +130,21 @@ title: Shortcuts CtrlZ Z + + Copy link to board + ShiftAltC + AltC + + + Copy properties + CtrlAltC + C + + + Paste properties + CtrlAltV + V + diff --git a/docs/user-guide/layer-basics/index.njk b/docs/user-guide/layer-basics/index.njk index e02ee48d9..7888396c3 100644 --- a/docs/user-guide/layer-basics/index.njk +++ b/docs/user-guide/layer-basics/index.njk @@ -103,7 +103,6 @@ title: 04· Layer basics

At the dropdown menu (right click on a layer to show it) there's the option "Select layer" that allows the user to select one layer among the ones that are under the cursor's location.

layers select

-

Group layers

Grouped layers can be moved, transformed or styled at the same time.

+ +

Copy/Paste properties

+

You can copy and apply properties, including fills, strokes, shadows, and others from one layer to another—or multiple layers with just a few clicks. You can do it using the layer's menu or shortcuts.

+ +
+ +
+ +

Using the layer menu

+
    +
  1. Select one layer.
  2. +
  3. Right click to show the layer menu.
  4. +
  5. Press Copy/Paste as... > Copy properties.
  6. +
  7. Select one or more other layers.
  8. +
  9. Right click to show the layer/s menu.
  10. +
  11. Press Copy/Paste as... > Paste properties.
  12. +
+ +

Using Shortcuts

+ diff --git a/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs index ff93524e4..c41e4273f 100644 --- a/frontend/src/app/main/ui/comments.cljs +++ b/frontend/src/app/main/ui/comments.cljs @@ -146,7 +146,7 @@ ;; Input text for comments with mentions (mf/defc comment-input* {::mf/private true} - [{:keys [value placeholder max-length autofocus on-focus on-blur on-change on-esc on-ctrl-enter]}] + [{:keys [value placeholder autofocus on-focus on-blur on-change on-esc on-ctrl-enter]}] (let [value (d/nilv value "") prev-value (h/use-previous value) @@ -196,7 +196,7 @@ (dom/append-child! node (create-text-node))) (let [new-input (parse-nodes node)] - (when (and on-change (<= (count new-input) max-length)) + (when on-change (on-change new-input)))))) handle-select @@ -637,6 +637,10 @@ :disabled is-disabled} (tr "labels.post")]])) +(defn- exceeds-length? + [content] + (> (count content) 750)) + (mf/defc comment-reply-form* {::mf/props :obj ::mf/private true} @@ -644,7 +648,8 @@ (let [show-buttons? (mf/use-state false) content (mf/use-state "") - disabled? (blank-content? @content) + disabled? (or (blank-content? @content) + (exceeds-length? @content)) on-focus (mf/use-fn @@ -678,8 +683,10 @@ :on-blur on-blur :on-focus on-focus :on-ctrl-enter on-submit* - :on-change on-change - :max-length 750}] + :on-change on-change}] + (when (exceeds-length? @content) + [:div {:class (stl/css :error-text)} + (tr "errors.character-limit-exceeded")]) (when (or @show-buttons? (seq @content)) [:> comment-form-buttons* {:on-submit on-submit* :on-cancel on-cancel @@ -690,7 +697,8 @@ [{:keys [content on-submit on-cancel]}] (let [content (mf/use-state content) - disabled? (blank-content? @content) + disabled? (or (blank-content? @content) + (exceeds-length? @content)) on-change (mf/use-fn @@ -706,8 +714,10 @@ {:value @content :autofocus true :on-ctrl-enter on-submit* - :on-change on-change - :max-length 750}] + :on-change on-change}] + (when (exceeds-length? @content) + [:div {:class (stl/css :error-text)} + (tr "errors.character-limit-exceeded")]) [:> comment-form-buttons* {:on-submit on-submit* :on-cancel on-cancel :is-disabled disabled?}]])) @@ -726,7 +736,8 @@ pos-x (* (:x position) zoom) pos-y (* (:y position) zoom) - disabled? (blank-content? content) + disabled? (or (blank-content? content) + (exceeds-length? content)) on-esc (mf/use-fn @@ -769,8 +780,10 @@ :autofocus true :on-esc on-esc :on-change on-change - :on-ctrl-enter on-submit* - :max-length 750}] + :on-ctrl-enter on-submit*}] + (when (exceeds-length? content) + [:div {:class (stl/css :error-text)} + (tr "errors.character-limit-exceeded")]) [:> comment-form-buttons* {:on-submit on-submit* :on-cancel on-esc :is-disabled disabled?}]] diff --git a/frontend/src/app/main/ui/comments.scss b/frontend/src/app/main/ui/comments.scss index 019120b39..70fd5b793 100644 --- a/frontend/src/app/main/ui/comments.scss +++ b/frontend/src/app/main/ui/comments.scss @@ -22,6 +22,11 @@ color: var(--comment-subtitle-color); } +.error-text { + @include bodySmallTypography; + color: var(--color-foreground-error); +} + .location { color: var(--comment-subtitle-color); display: flex; @@ -246,6 +251,7 @@ grid-template-columns: 1fr auto auto; justify-content: flex-end; gap: $s-8; + margin-top: $s-8; } .open-mentions-button { @@ -321,7 +327,6 @@ border: $s-1 solid var(--input-border-color); color: var(--input-foreground-color); height: $s-36; - margin-bottom: $s-8; max-width: $s-260; overflow-y: auto; padding: $s-8; diff --git a/frontend/text-editor/src/editor/content/dom/Content.js b/frontend/text-editor/src/editor/content/dom/Content.js index 1b2ca84ed..9f3ed49ff 100644 --- a/frontend/text-editor/src/editor/content/dom/Content.js +++ b/frontend/text-editor/src/editor/content/dom/Content.js @@ -73,10 +73,11 @@ export function mapContentFragmentFromDocument(document, root, styleDefaults) { currentParagraph = createParagraph(undefined, currentStyle); } } - const inline = createInline(new Text(currentNode.nodeValue), currentStyle); const fontSize = inline.style.getPropertyValue("font-size"); if (!fontSize) console.warn("font-size", fontSize); + const fontFamily = inline.style.getPropertyValue("font-family"); + if (!fontFamily) console.warn("font-family", fontFamily); currentParagraph.appendChild(inline); currentNode = nodeIterator.nextNode(); diff --git a/frontend/text-editor/src/editor/content/dom/Style.js b/frontend/text-editor/src/editor/content/dom/Style.js index b7abe2f8b..d194a1336 100644 --- a/frontend/text-editor/src/editor/content/dom/Style.js +++ b/frontend/text-editor/src/editor/content/dom/Style.js @@ -23,7 +23,8 @@ export function mergeStyleDeclarations(target, source) { // for (const styleName of source) { for (let index = 0; index < source.length; index++) { const styleName = source.item(index); - target.setProperty(styleName, source.getPropertyValue(styleName)); + const styleValue = source.getPropertyValue(styleName); + target.setProperty(styleName, styleValue); } return target } @@ -108,9 +109,10 @@ export function getComputedStyle(element) { inertElement.style.setProperty(styleName, newValue); } } else { + const newValue = currentElement.style.getPropertyValue(styleName); inertElement.style.setProperty( styleName, - currentElement.style.getPropertyValue(styleName) + newValue ); } } @@ -130,9 +132,10 @@ export function getComputedStyle(element) { * @returns {CSSStyleDeclaration} */ export function normalizeStyles(node, styleDefaults = getStyleDefaultsDeclaration()) { + const computedStyle = getComputedStyle(node.parentElement); const styleDeclaration = mergeStyleDeclarations( styleDefaults, - getComputedStyle(node.parentElement) + computedStyle ); // If there's a color property, we should convert it to @@ -149,7 +152,7 @@ export function normalizeStyles(node, styleDefaults = getStyleDefaultsDeclaratio // If there's a font-family property and not a --font-id, then // we remove the font-family because it will not work. const fontFamily = styleDeclaration.getPropertyValue("font-family"); - const fontId = styleDeclaration.getPropertyPriority("--font-id"); + const fontId = styleDeclaration.getPropertyValue("--font-id"); if (fontFamily && !fontId) { styleDeclaration.removeProperty("font-family"); } diff --git a/frontend/translations/en.po b/frontend/translations/en.po index e10f34d0c..27b3c0504 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1152,6 +1152,10 @@ msgstr "The fonts %s could not be loaded" msgid "errors.cannot-upload" msgstr "Cannot upload the media file." +#: src/app/main/ui/comments.cljs:689 +msgid "errors.character-limit-exceeded" +msgstr "Character limit exceeded" + #: src/app/main/data/workspace.cljs:1463, src/app/main/data/workspace.cljs:1660 msgid "errors.clipboard-not-implemented" msgstr "Your browser cannot do this operation" @@ -3528,7 +3532,7 @@ msgstr "Copy" #: src/app/main/ui/workspace/sidebar/shortcuts.cljs:94 msgid "shortcuts.copy-link" -msgstr "Copy link to clipboard" +msgstr "Copy link" #: src/app/main/ui/workspace/sidebar/shortcuts.cljs:106 msgid "shortcuts.copy-props" @@ -6188,7 +6192,7 @@ msgstr "Copy as CSS (nested layers)" #: src/app/main/ui/workspace/context_menu.cljs:188 msgid "workspace.shape.menu.copy-link" -msgstr "Copy link to clipboard" +msgstr "Copy link" #: src/app/main/ui/workspace/context_menu.cljs:201 msgid "workspace.shape.menu.copy-paste-as" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 191984820..642e22aff 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -1160,6 +1160,10 @@ msgstr "No se han podido cargar las fuentes %s" msgid "errors.cannot-upload" msgstr "No se puede cargar el archivo multimedia." +#: src/app/main/ui/comments.cljs:689 +msgid "errors.character-limit-exceeded" +msgstr "Se ha superado el límite de caracteres" + #: src/app/main/data/workspace.cljs:1463, src/app/main/data/workspace.cljs:1660 msgid "errors.clipboard-not-implemented" msgstr "Tu navegador no puede realizar esta operación" @@ -3524,7 +3528,7 @@ msgstr "Copiar" #: src/app/main/ui/workspace/sidebar/shortcuts.cljs:94 msgid "shortcuts.copy-link" -msgstr "Copiar enlace al portapapeles" +msgstr "Copiar enlace" #: src/app/main/ui/workspace/sidebar/shortcuts.cljs:95 msgid "shortcuts.create-component" @@ -6186,7 +6190,7 @@ msgstr "Copiar como CSS (capas anidadas)" #: src/app/main/ui/workspace/context_menu.cljs:188 msgid "workspace.shape.menu.copy-link" -msgstr "Copiar enlace al portapapeles" +msgstr "Copiar enlace" #: src/app/main/ui/workspace/context_menu.cljs:201 msgid "workspace.shape.menu.copy-paste-as"