From 014fdbb7d800d3bc84d20fdc81f87a247fba5993 Mon Sep 17 00:00:00 2001 From: Henry <30578846+hjball@users.noreply.github.com> Date: Sat, 21 Jun 2025 23:15:07 +0100 Subject: [PATCH] feat: render URLs as links in card description (#93) --- apps/web/package.json | 1 + apps/web/src/components/Editor.tsx | 11 +++++++++++ pnpm-lock.yaml | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/apps/web/package.json b/apps/web/package.json index 6f5f494b..5b241a3a 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -25,6 +25,7 @@ "@t3-oss/env-nextjs": "^0.11.1", "@tailwindcss/typography": "^0.5.16", "@tanstack/react-query": "catalog:", + "@tiptap/extension-link": "^2.22.2", "@tiptap/extension-placeholder": "^2.14.0", "@tiptap/pm": "^2.14.0", "@tiptap/react": "^2.14.0", diff --git a/apps/web/src/components/Editor.tsx b/apps/web/src/components/Editor.tsx index 9a07a55d..82814ba4 100644 --- a/apps/web/src/components/Editor.tsx +++ b/apps/web/src/components/Editor.tsx @@ -5,6 +5,7 @@ import type { } from "@tiptap/suggestion"; import type { Instance as TippyInstance } from "tippy.js"; import { Button } from "@headlessui/react"; +import Link from "@tiptap/extension-link"; import Placeholder from "@tiptap/extension-placeholder"; import { BubbleMenu, @@ -299,6 +300,16 @@ export default function Editor({ ? "" : "Add description... (type '/' to open commands)", }), + Link.configure({ + openOnClick: true, + HTMLAttributes: { + class: "text-blue-600 hover:text-blue-800 underline cursor-pointer", + target: "_blank", + rel: "noopener noreferrer", + }, + validate: (href) => /^https?:\/\//.test(href), + autolink: true, + }), SlashCommands.configure({ commandItems: CommandItems, suggestion: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0bd8d77..0374c5f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,6 +108,9 @@ importers: '@tanstack/react-query': specifier: 'catalog:' version: 5.62.7(react@18.3.1) + '@tiptap/extension-link': + specifier: ^2.22.2 + version: 2.22.2(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0) '@tiptap/extension-placeholder': specifier: ^2.14.0 version: 2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0) @@ -2343,6 +2346,12 @@ packages: peerDependencies: '@tiptap/core': ^2.7.0 + '@tiptap/extension-link@2.22.2': + resolution: {integrity: sha512-nL4tp6Q6ppjP53HS4E8InBYO2kwXx16SgqlS1mc51OiiQgdXPNKZAzBluuiMMi6+wvVWvD4QCbHhQjQy11cZNA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + '@tiptap/extension-list-item@2.14.0': resolution: {integrity: sha512-t1jXDPEd82sC6vZVE/12/CB52uuiydCIcRfwdh21xNgBMckToKO9S0K6XEp4ROtrKQdlIH2JDVPfpUBvVrYN8Q==} peerDependencies: @@ -4335,6 +4344,9 @@ packages: linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + linkifyjs@4.3.1: + resolution: {integrity: sha512-DRSlB9DKVW04c4SUdGvKK5FR6be45lTU9M76JnngqPeeGDqPwYc0zdUErtsNVMtxPXgUWV4HbXbnC4sNyBxkYg==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -8527,6 +8539,12 @@ snapshots: dependencies: '@tiptap/core': 2.14.0(@tiptap/pm@2.14.0) + '@tiptap/extension-link@2.22.2(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)': + dependencies: + '@tiptap/core': 2.14.0(@tiptap/pm@2.14.0) + '@tiptap/pm': 2.14.0 + linkifyjs: 4.3.1 + '@tiptap/extension-list-item@2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))': dependencies: '@tiptap/core': 2.14.0(@tiptap/pm@2.14.0) @@ -10828,6 +10846,8 @@ snapshots: dependencies: uc.micro: 2.1.0 + linkifyjs@4.3.1: {} + locate-path@6.0.0: dependencies: p-locate: 5.0.0