mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
✨ Make links in comments clickable (#8894)
* ✨ Make links in comments clickable Detect URLs in comment text and render them as clickable links that open in a new tab. Extends the existing mention parsing to also split text elements by URL patterns, handling trailing punctuation and mixed mention+URL content. Closes #1602 * 📚 Add changelog entry for clickable links in comments * 🐛 Fix URL elements dropped in comment input initialization * 🐛 Keep empty text elements in parse-urls to preserve cursor anchors The remove filter in parse-urls was stripping empty text elements produced by str/split at URL boundaries. These elements are needed as cursor anchor spans in the contenteditable input, without them ESC keydown and visual layout broke. Signed-off-by: eureka928 <meobius123@gmail.com>
This commit is contained in:
parent
e7e5a19db7
commit
8dccb2a427
@ -27,6 +27,7 @@
|
||||
- Fix warnings for unsupported token $type (by @Dexterity104) [Github #8790](https://github.com/penpot/penpot/issues/8790)
|
||||
- Add per-group add button for typographies (by @eureka928) [Github #5275](https://github.com/penpot/penpot/issues/5275)
|
||||
- Use page name for multi-export ZIP/PDF downloads (by @Dexterity104) [Github #8773](https://github.com/penpot/penpot/issues/8773)
|
||||
- Make links in comments clickable (by @eureka928) [Github #1602](https://github.com/penpot/penpot/issues/1602)
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
|
||||
@ -45,20 +45,34 @@
|
||||
(def mentions-context (mf/create-context nil))
|
||||
(def r-mentions-split #"@\[[^\]]*\]\([^\)]*\)")
|
||||
(def r-mentions #"@\[([^\]]*)\]\(([^\)]*)\)")
|
||||
(def r-url-split #"https?://[^\s\)\]]+[^\s\)\]\.,;:!?]")
|
||||
(def zero-width-space \u200B)
|
||||
|
||||
(defn- parse-comment
|
||||
"Parse a comment into its elements (texts and mentions)"
|
||||
[comment]
|
||||
(d/interleave-all
|
||||
(->> (str/split comment r-mentions-split)
|
||||
(map #(hash-map :type :text :content %)))
|
||||
(defn- parse-urls
|
||||
"Split a text element into text and url sub-elements"
|
||||
[element]
|
||||
(if (= (:type element) :text)
|
||||
(let [text (:content element)
|
||||
parts (str/split text r-url-split)
|
||||
urls (re-seq r-url-split text)]
|
||||
(d/interleave-all
|
||||
(map #(hash-map :type :text :content %) parts)
|
||||
(map #(hash-map :type :url :content %) urls)))
|
||||
[element]))
|
||||
|
||||
(->> (re-seq r-mentions comment)
|
||||
(map (fn [[_ user id]]
|
||||
{:type :mention
|
||||
:content user
|
||||
:data {:id id}})))))
|
||||
(defn- parse-comment
|
||||
"Parse a comment into its elements (texts, mentions and urls)"
|
||||
[comment]
|
||||
(->> (d/interleave-all
|
||||
(->> (str/split comment r-mentions-split)
|
||||
(map #(hash-map :type :text :content %)))
|
||||
|
||||
(->> (re-seq r-mentions comment)
|
||||
(map (fn [[_ user id]]
|
||||
{:type :mention
|
||||
:content user
|
||||
:data {:id id}}))))
|
||||
(mapcat parse-urls)))
|
||||
|
||||
(defn- parse-nodes
|
||||
"Parse the nodes to format a comment"
|
||||
@ -146,7 +160,13 @@
|
||||
[{:keys [content]}]
|
||||
(let [comment-elements (mf/use-memo (mf/deps content) #(parse-comment content))]
|
||||
(for [[idx {:keys [type content]}] (d/enumerate comment-elements)]
|
||||
(case type
|
||||
(if (= type :url)
|
||||
[:a {:key idx
|
||||
:href content
|
||||
:target "_blank"
|
||||
:rel "noopener noreferrer"
|
||||
:class (stl/css :comment-link)}
|
||||
content]
|
||||
[:span
|
||||
{:key idx
|
||||
:class (stl/css-case
|
||||
@ -177,6 +197,7 @@
|
||||
(doseq [{:keys [type content data]} (parse-comment value)]
|
||||
(case type
|
||||
:text (dom/append-child! node (create-text-node content))
|
||||
:url (dom/append-child! node (create-text-node content))
|
||||
:mention (dom/append-child! node (create-mention-node (:id data) content))
|
||||
nil)))))
|
||||
|
||||
|
||||
@ -418,6 +418,12 @@
|
||||
color: var(--color-accent-primary);
|
||||
}
|
||||
|
||||
.comment-link {
|
||||
color: var(--color-accent-primary);
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.comments-mentions-empty {
|
||||
font-size: deprecated.$fs-12;
|
||||
color: var(--color-foreground-secondary);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user