react-beauty-link 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,257 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ // Nerd Font icons for file types (Unicode characters)
4
+ const FILE_TYPE_ICONS = {
5
+ // Documents
6
+ 'pdf': { icon: '󰈦', color: '#e74856' },
7
+ 'doc': { icon: '󰈬', color: '#2b579a' },
8
+ 'docx': { icon: '󰈬', color: '#2b579a' },
9
+ 'xls': { icon: '󰈛', color: '#207245' },
10
+ 'xlsx': { icon: '󰈛', color: '#207245' },
11
+ 'ppt': { icon: '󰈧', color: '#d24726' },
12
+ 'pptx': { icon: '󰈧', color: '#d24726' },
13
+ 'txt': { icon: '󰈙', color: '#6c757d' },
14
+ // Archives
15
+ 'zip': { icon: '󰗄', color: '#e89f1c' },
16
+ 'rar': { icon: '󰗄', color: '#e89f1c' },
17
+ '7z': { icon: '󰗄', color: '#e89f1c' },
18
+ 'tar': { icon: '󰗄', color: '#e89f1c' },
19
+ 'gz': { icon: '󰗄', color: '#e89f1c' },
20
+ // Images
21
+ 'jpg': { icon: '󰈟', color: '#a855f7' },
22
+ 'jpeg': { icon: '󰈟', color: '#a855f7' },
23
+ 'png': { icon: '󰈟', color: '#a855f7' },
24
+ 'gif': { icon: '󰈟', color: '#a855f7' },
25
+ 'svg': { icon: '󰜡', color: '#f97316' },
26
+ 'webp': { icon: '󰈟', color: '#a855f7' },
27
+ // Videos
28
+ 'mp4': { icon: '󰕧', color: '#ec4899' },
29
+ 'avi': { icon: '󰕧', color: '#ec4899' },
30
+ 'mov': { icon: '󰕧', color: '#ec4899' },
31
+ 'mkv': { icon: '󰕧', color: '#ec4899' },
32
+ 'webm': { icon: '󰕧', color: '#ec4899' },
33
+ // Audio
34
+ 'mp3': { icon: '󰈣', color: '#10b981' },
35
+ 'wav': { icon: '󰈣', color: '#10b981' },
36
+ 'flac': { icon: '󰈣', color: '#10b981' },
37
+ 'ogg': { icon: '󰈣', color: '#10b981' },
38
+ // Code
39
+ 'js': { icon: '󰌞', color: '#f0db4f' },
40
+ 'ts': { icon: '󰛦', color: '#3178c6' },
41
+ 'jsx': { icon: '󰜈', color: '#61dafb' },
42
+ 'tsx': { icon: '󰜈', color: '#61dafb' },
43
+ 'py': { icon: '󰌠', color: '#3776ab' },
44
+ 'java': { icon: '󰬷', color: '#007396' },
45
+ 'php': { icon: '󰌟', color: '#777bb4' },
46
+ 'rb': { icon: '󰴭', color: '#cc342d' },
47
+ 'go': { icon: '󰟓', color: '#00add8' },
48
+ 'rs': { icon: '󱘗', color: '#dea584' },
49
+ 'html': { icon: '󰌝', color: '#e34c26' },
50
+ 'css': { icon: '󰌜', color: '#264de4' },
51
+ 'json': { icon: '󰘦', color: '#f7df1e' },
52
+ 'xml': { icon: '󰗀', color: '#ff6600' },
53
+ 'yaml': { icon: '󰈙', color: '#cb171e' },
54
+ 'yml': { icon: '󰈙', color: '#cb171e' },
55
+ 'md': { icon: '󰍔', color: '#083fa1' },
56
+ 'sql': { icon: '󰆼', color: '#00758f' },
57
+ 'sh': { icon: '󰆍', color: '#89e051' },
58
+ };
59
+ function getFileExtension(url) {
60
+ try {
61
+ const urlObj = new URL(url);
62
+ const pathname = urlObj.pathname;
63
+ const lastDot = pathname.lastIndexOf('.');
64
+ if (lastDot === -1 || lastDot === pathname.length - 1)
65
+ return null;
66
+ return pathname.substring(lastDot + 1).toLowerCase();
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ /**
73
+ * Custom hook that converts HTTPS URLs in a string into clickable links
74
+ * with page titles and favicons
75
+ * @param text - The input string containing potential URLs
76
+ * @param target - How to open links: 'new-tab' (default), 'new-window', or 'self'
77
+ * @returns An array of React nodes with text and links
78
+ */
79
+ export const useLinkify = (text, target = 'new-tab') => {
80
+ const urlRegex = /(https:\/\/[^\s]+)/g;
81
+ const [linkMetadata, setLinkMetadata] = useState({});
82
+ const urls = Array.from(text.matchAll(urlRegex)).map(match => match[0]);
83
+ useEffect(() => {
84
+ const fetchAllMetadata = async () => {
85
+ for (const url of urls) {
86
+ if (!linkMetadata[url]) {
87
+ const extension = getFileExtension(url);
88
+ // If it's a file URL, skip metadata fetching and use filename
89
+ if (extension && FILE_TYPE_ICONS[extension]) {
90
+ const filename = url.split('/').pop() || url;
91
+ setLinkMetadata(prev => ({
92
+ ...prev,
93
+ [url]: {
94
+ title: decodeURIComponent(filename),
95
+ favicon: null
96
+ }
97
+ }));
98
+ continue;
99
+ }
100
+ try {
101
+ console.log('Fetching metadata for:', url);
102
+ const metadata = await fetchLinkMetadata(url);
103
+ console.log('Metadata received:', metadata);
104
+ setLinkMetadata(prev => ({
105
+ ...prev,
106
+ [url]: metadata
107
+ }));
108
+ }
109
+ catch (error) {
110
+ console.error('Failed to fetch metadata for', url, error);
111
+ setLinkMetadata(prev => ({
112
+ ...prev,
113
+ [url]: {
114
+ title: url,
115
+ favicon: null
116
+ }
117
+ }));
118
+ }
119
+ }
120
+ }
121
+ };
122
+ fetchAllMetadata();
123
+ }, [text, JSON.stringify(urls)]);
124
+ const parts = [];
125
+ let lastIndex = 0;
126
+ let match;
127
+ urlRegex.lastIndex = 0;
128
+ while ((match = urlRegex.exec(text)) !== null) {
129
+ const url = match[0];
130
+ const startIndex = match.index;
131
+ if (startIndex > lastIndex) {
132
+ parts.push(text.substring(lastIndex, startIndex));
133
+ }
134
+ const metadata = linkMetadata[url];
135
+ const displayTitle = metadata?.title
136
+ ? (metadata.title.length > 60 ? metadata.title.substring(0, 60) + '...' : metadata.title)
137
+ : url;
138
+ const faviconUrl = metadata?.favicon;
139
+ const extension = getFileExtension(url);
140
+ const fileIcon = extension ? FILE_TYPE_ICONS[extension] : null;
141
+ const getTargetAttributes = () => {
142
+ switch (target) {
143
+ case 'new-window':
144
+ return {
145
+ target: '_blank',
146
+ rel: 'noopener noreferrer',
147
+ onClick: (e) => {
148
+ e.preventDefault();
149
+ window.open(url, '_blank', 'noopener,noreferrer,width=800,height=600');
150
+ }
151
+ };
152
+ case 'self':
153
+ return {
154
+ target: '_self'
155
+ };
156
+ case 'new-tab':
157
+ default:
158
+ return {
159
+ target: '_blank',
160
+ rel: 'noopener noreferrer'
161
+ };
162
+ }
163
+ };
164
+ parts.push(_jsxs("a", { href: url, ...getTargetAttributes(), style: {
165
+ color: '#646cff',
166
+ textDecoration: 'underline',
167
+ display: 'inline-flex',
168
+ alignItems: 'center',
169
+ gap: '6px'
170
+ }, children: [fileIcon ? (_jsx("span", { style: {
171
+ fontFamily: '"Symbols Nerd Font", "FiraCode Nerd Font", monospace',
172
+ fontSize: '16px',
173
+ color: fileIcon.color,
174
+ lineHeight: 1,
175
+ display: 'inline-block',
176
+ width: '16px',
177
+ textAlign: 'center'
178
+ }, children: fileIcon.icon })) : faviconUrl ? (_jsx("img", { src: faviconUrl, alt: "", style: { width: '16px', height: '16px' }, onError: (e) => {
179
+ e.target.src = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/%3E%3Cpath d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/%3E%3C/svg%3E';
180
+ } })) : (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }), _jsx("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })] })), _jsx("span", { children: displayTitle })] }, `link-${startIndex}`));
181
+ lastIndex = startIndex + url.length;
182
+ }
183
+ if (lastIndex < text.length) {
184
+ parts.push(text.substring(lastIndex));
185
+ }
186
+ return parts.length > 0 ? parts : [text];
187
+ };
188
+ /**
189
+ * Fetches metadata (title and favicon) for a given URL
190
+ */
191
+ async function fetchLinkMetadata(url) {
192
+ try {
193
+ const urlObj = new URL(url);
194
+ const origin = urlObj.origin;
195
+ const proxies = [
196
+ `https://api.allorigins.win/get?url=${encodeURIComponent(url)}`,
197
+ `https://corsproxy.io/?${encodeURIComponent(url)}`,
198
+ ];
199
+ let html = '';
200
+ let success = false;
201
+ for (const proxyUrl of proxies) {
202
+ try {
203
+ const response = await fetch(proxyUrl, {
204
+ signal: AbortSignal.timeout(10000) // 10 second timeout
205
+ });
206
+ if (!response.ok)
207
+ continue;
208
+ const data = await response.json();
209
+ html = data.contents || data;
210
+ success = true;
211
+ break;
212
+ }
213
+ catch (err) {
214
+ console.warn('Proxy failed:', proxyUrl, err);
215
+ continue;
216
+ }
217
+ }
218
+ if (!success || !html) {
219
+ throw new Error('All proxies failed');
220
+ }
221
+ const parser = new DOMParser();
222
+ const doc = parser.parseFromString(html, 'text/html');
223
+ let title = doc.querySelector('meta[property="og:title"]')?.getAttribute('content') ||
224
+ doc.querySelector('meta[name="twitter:title"]')?.getAttribute('content') ||
225
+ doc.querySelector('title')?.textContent ||
226
+ url;
227
+ title = title.trim();
228
+ let favicon = `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=32`;
229
+ const faviconLink = doc.querySelector('link[rel="icon"]')?.getAttribute('href') ||
230
+ doc.querySelector('link[rel="shortcut icon"]')?.getAttribute('href') ||
231
+ doc.querySelector('link[rel="apple-touch-icon"]')?.getAttribute('href');
232
+ if (faviconLink) {
233
+ if (faviconLink.startsWith('http')) {
234
+ favicon = faviconLink;
235
+ }
236
+ else if (faviconLink.startsWith('//')) {
237
+ favicon = 'https:' + faviconLink;
238
+ }
239
+ else if (faviconLink.startsWith('/')) {
240
+ favicon = origin + faviconLink;
241
+ }
242
+ else {
243
+ favicon = origin + '/' + faviconLink;
244
+ }
245
+ }
246
+ return { title, favicon };
247
+ }
248
+ catch (error) {
249
+ console.error('Error fetching metadata:', error);
250
+ const urlObj = new URL(url);
251
+ return {
252
+ title: urlObj.hostname,
253
+ favicon: `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=32`
254
+ };
255
+ }
256
+ }
257
+ //# sourceMappingURL=useLinkify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLinkify.js","sourceRoot":"","sources":["../../src/hooks/useLinkify.tsx"],"names":[],"mappings":"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"}
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("react/jsx-runtime"),x=require("react"),y={pdf:{icon:"󰈦",color:"#e74856"},doc:{icon:"󰈬",color:"#2b579a"},docx:{icon:"󰈬",color:"#2b579a"},xls:{icon:"󰈛",color:"#207245"},xlsx:{icon:"󰈛",color:"#207245"},ppt:{icon:"󰈧",color:"#d24726"},pptx:{icon:"󰈧",color:"#d24726"},txt:{icon:"󰈙",color:"#6c757d"},zip:{icon:"󰗄",color:"#e89f1c"},rar:{icon:"󰗄",color:"#e89f1c"},"7z":{icon:"󰗄",color:"#e89f1c"},tar:{icon:"󰗄",color:"#e89f1c"},gz:{icon:"󰗄",color:"#e89f1c"},jpg:{icon:"󰈟",color:"#a855f7"},jpeg:{icon:"󰈟",color:"#a855f7"},png:{icon:"󰈟",color:"#a855f7"},gif:{icon:"󰈟",color:"#a855f7"},svg:{icon:"󰜡",color:"#f97316"},webp:{icon:"󰈟",color:"#a855f7"},mp4:{icon:"󰕧",color:"#ec4899"},avi:{icon:"󰕧",color:"#ec4899"},mov:{icon:"󰕧",color:"#ec4899"},mkv:{icon:"󰕧",color:"#ec4899"},webm:{icon:"󰕧",color:"#ec4899"},mp3:{icon:"󰈣",color:"#10b981"},wav:{icon:"󰈣",color:"#10b981"},flac:{icon:"󰈣",color:"#10b981"},ogg:{icon:"󰈣",color:"#10b981"},js:{icon:"󰌞",color:"#f0db4f"},ts:{icon:"󰛦",color:"#3178c6"},jsx:{icon:"󰜈",color:"#61dafb"},tsx:{icon:"󰜈",color:"#61dafb"},py:{icon:"󰌠",color:"#3776ab"},java:{icon:"󰬷",color:"#007396"},php:{icon:"󰌟",color:"#777bb4"},rb:{icon:"󰴭",color:"#cc342d"},go:{icon:"󰟓",color:"#00add8"},rs:{icon:"󱘗",color:"#dea584"},html:{icon:"󰌝",color:"#e34c26"},css:{icon:"󰌜",color:"#264de4"},json:{icon:"󰘦",color:"#f7df1e"},xml:{icon:"󰗀",color:"#ff6600"},yaml:{icon:"󰈙",color:"#cb171e"},yml:{icon:"󰈙",color:"#cb171e"},md:{icon:"󰍔",color:"#083fa1"},sql:{icon:"󰆼",color:"#00758f"},sh:{icon:"󰆍",color:"#89e051"}};function k(e){try{const c=new URL(e).pathname,l=c.lastIndexOf(".");return l===-1||l===c.length-1?null:c.substring(l+1).toLowerCase()}catch{return null}}const j=(e,d="new-tab",c)=>{const l=/(https:\/\/[^\s]+)/g,[p,u]=x.useState({}),g=Array.from(e.matchAll(l)).map(t=>t[0]);x.useEffect(()=>{(async()=>{for(const o of g)if(!p[o]){const n=k(o);if(n&&y[n]){const i=o.split("/").pop()||o;u(f=>({...f,[o]:{title:decodeURIComponent(i),favicon:null}}));continue}try{console.log("Fetching metadata for:",o);const i=await S(o);console.log("Metadata received:",i),u(f=>({...f,[o]:i}))}catch(i){console.error("Failed to fetch metadata for",o,i),u(f=>({...f,[o]:{title:o,favicon:null}}))}}})()},[e,JSON.stringify(g)]);const r=[];let s=0,a;for(l.lastIndex=0;(a=l.exec(e))!==null;){const t=a[0],o=a.index;o>s&&r.push(e.substring(s,o));const n=p[t],i=n?.title?n.title.length>60?n.title.substring(0,60)+"...":n.title:t,f=n?.favicon,b=k(t),m=b?y[b]:null,v=()=>{switch(d){case"new-window":return{target:"_blank",rel:"noopener noreferrer",onClick:w=>{w.preventDefault(),window.open(t,"_blank","noopener,noreferrer,width=800,height=600")}};case"self":return{target:"_self"};default:return{target:"_blank",rel:"noopener noreferrer"}}};r.push(h.jsxs("a",{href:t,...v(),style:{color:c||"#646cff",textDecoration:"underline",display:"inline-flex",alignItems:"center",gap:"6px"},children:[m?h.jsx("span",{style:{fontFamily:'"Symbols Nerd Font Mono", "Symbols Nerd Font", "Nerd Font", "FiraCode Nerd Font", monospace',fontSize:"16px",color:m.color,lineHeight:1,display:"inline-block",width:"16px",textAlign:"center",fontWeight:"normal"},"aria-hidden":"true",children:m.icon}):f?h.jsx("img",{src:f,alt:"",style:{width:"16px",height:"16px"},onError:w=>{w.target.src='data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/%3E%3Cpath d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/%3E%3C/svg%3E'}}):h.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[h.jsx("path",{d:"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"}),h.jsx("path",{d:"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"})]}),h.jsx("span",{children:i})]},`link-${o}`)),s=o+t.length}return s<e.length&&r.push(e.substring(s)),r.length>0?r:[e]};async function S(e){try{const d=new URL(e),c=d.origin,l=[`https://api.allorigins.win/get?url=${encodeURIComponent(e)}`,`https://corsproxy.io/?${encodeURIComponent(e)}`];let p="",u=!1;for(const o of l)try{const n=await fetch(o,{signal:AbortSignal.timeout(1e4)});if(!n.ok)continue;const i=await n.json();p=i.contents||i,u=!0;break}catch(n){console.warn("Proxy failed:",o,n);continue}if(!u||!p)throw new Error("All proxies failed");const r=new DOMParser().parseFromString(p,"text/html");let s=r.querySelector('meta[property="og:title"]')?.getAttribute("content")||r.querySelector('meta[name="twitter:title"]')?.getAttribute("content")||r.querySelector("title")?.textContent||e;s=s.trim();let a=`https://www.google.com/s2/favicons?domain=${d.hostname}&sz=32`;const t=r.querySelector('link[rel="icon"]')?.getAttribute("href")||r.querySelector('link[rel="shortcut icon"]')?.getAttribute("href")||r.querySelector('link[rel="apple-touch-icon"]')?.getAttribute("href");return t&&(t.startsWith("http")?a=t:t.startsWith("//")?a="https:"+t:t.startsWith("/")?a=c+t:a=c+"/"+t),{title:s,favicon:a}}catch(d){console.error("Error fetching metadata:",d);const c=new URL(e);return{title:c.hostname,favicon:`https://www.google.com/s2/favicons?domain=${c.hostname}&sz=32`}}}exports.useBeautyLink=j;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils/fileIcons.ts","../src/hooks/useBeautyLink.tsx"],"sourcesContent":["interface FileTypeIcon {\n icon: string;\n color: string;\n }\n\nexport const FILE_TYPE_ICONS: Record<string, FileTypeIcon> = {\n // Documents\n 'pdf': { icon: '󰈦', color: '#e74856' },\n 'doc': { icon: '󰈬', color: '#2b579a' },\n 'docx': { icon: '󰈬', color: '#2b579a' },\n 'xls': { icon: '󰈛', color: '#207245' },\n 'xlsx': { icon: '󰈛', color: '#207245' },\n 'ppt': { icon: '󰈧', color: '#d24726' },\n 'pptx': { icon: '󰈧', color: '#d24726' },\n 'txt': { icon: '󰈙', color: '#6c757d' },\n \n // Archives\n 'zip': { icon: '󰗄', color: '#e89f1c' },\n 'rar': { icon: '󰗄', color: '#e89f1c' },\n '7z': { icon: '󰗄', color: '#e89f1c' },\n 'tar': { icon: '󰗄', color: '#e89f1c' },\n 'gz': { icon: '󰗄', color: '#e89f1c' },\n \n // Images\n 'jpg': { icon: '󰈟', color: '#a855f7' },\n 'jpeg': { icon: '󰈟', color: '#a855f7' },\n 'png': { icon: '󰈟', color: '#a855f7' },\n 'gif': { icon: '󰈟', color: '#a855f7' },\n 'svg': { icon: '󰜡', color: '#f97316' },\n 'webp': { icon: '󰈟', color: '#a855f7' },\n \n // Videos\n 'mp4': { icon: '󰕧', color: '#ec4899' },\n 'avi': { icon: '󰕧', color: '#ec4899' },\n 'mov': { icon: '󰕧', color: '#ec4899' },\n 'mkv': { icon: '󰕧', color: '#ec4899' },\n 'webm': { icon: '󰕧', color: '#ec4899' },\n \n // Audio\n 'mp3': { icon: '󰈣', color: '#10b981' },\n 'wav': { icon: '󰈣', color: '#10b981' },\n 'flac': { icon: '󰈣', color: '#10b981' },\n 'ogg': { icon: '󰈣', color: '#10b981' },\n \n // Code\n 'js': { icon: '󰌞', color: '#f0db4f' },\n 'ts': { icon: '󰛦', color: '#3178c6' },\n 'jsx': { icon: '󰜈', color: '#61dafb' },\n 'tsx': { icon: '󰜈', color: '#61dafb' },\n 'py': { icon: '󰌠', color: '#3776ab' },\n 'java': { icon: '󰬷', color: '#007396' },\n 'php': { icon: '󰌟', color: '#777bb4' },\n 'rb': { icon: '󰴭', color: '#cc342d' },\n 'go': { icon: '󰟓', color: '#00add8' },\n 'rs': { icon: '󱘗', color: '#dea584' },\n 'html': { icon: '󰌝', color: '#e34c26' },\n 'css': { icon: '󰌜', color: '#264de4' },\n 'json': { icon: '󰘦', color: '#f7df1e' },\n 'xml': { icon: '󰗀', color: '#ff6600' },\n 'yaml': { icon: '󰈙', color: '#cb171e' },\n 'yml': { icon: '󰈙', color: '#cb171e' },\n 'md': { icon: '󰍔', color: '#083fa1' },\n 'sql': { icon: '󰆼', color: '#00758f' },\n 'sh': { icon: '󰆍', color: '#89e051' },\n };","import { useState, useEffect } from 'react';\nimport type { ReactNode } from 'react';\nimport { FILE_TYPE_ICONS } from '../utils/fileIcons';\n\ninterface LinkMetadata {\n title: string;\n favicon: string | null;\n}\n\nexport type LinkTarget = 'new-tab' | 'new-window' | 'self';\n\n\nfunction getFileExtension(url: string): string | null {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const lastDot = pathname.lastIndexOf('.');\n if (lastDot === -1 || lastDot === pathname.length - 1) return null;\n return pathname.substring(lastDot + 1).toLowerCase();\n } catch {\n return null;\n }\n}\n\n/**\n * Custom hook that converts HTTPS URLs in a string into clickable links\n * with page titles and favicons\n * @param text - The input string containing potential URLs\n * @param target - How to open links: 'new-tab' (default), 'new-window', or 'self'\n * @returns An array of React nodes with text and links\n */\nexport const useBeautyLink = (text: string, target: LinkTarget = 'new-tab', customColor?: string): ReactNode[] => {\n const urlRegex = /(https:\\/\\/[^\\s]+)/g;\n const [linkMetadata, setLinkMetadata] = useState<Record<string, LinkMetadata>>({});\n \n const urls = Array.from(text.matchAll(urlRegex)).map(match => match[0]);\n\n useEffect(() => {\n const fetchAllMetadata = async () => {\n for (const url of urls) {\n if (!linkMetadata[url]) {\n const extension = getFileExtension(url);\n \n // If it's a file URL, skip metadata fetching and use filename\n if (extension && FILE_TYPE_ICONS[extension]) {\n const filename = url.split('/').pop() || url;\n setLinkMetadata(prev => ({\n ...prev,\n [url]: {\n title: decodeURIComponent(filename),\n favicon: null\n }\n }));\n continue;\n }\n \n try {\n console.log('Fetching metadata for:', url);\n const metadata = await fetchLinkMetadata(url);\n console.log('Metadata received:', metadata);\n setLinkMetadata(prev => ({\n ...prev,\n [url]: metadata\n }));\n } catch (error) {\n console.error('Failed to fetch metadata for', url, error);\n setLinkMetadata(prev => ({\n ...prev,\n [url]: {\n title: url,\n favicon: null\n }\n }));\n }\n }\n }\n };\n\n fetchAllMetadata();\n }, [text, JSON.stringify(urls)]);\n\n const parts: ReactNode[] = [];\n let lastIndex = 0;\n let match;\n\n urlRegex.lastIndex = 0;\n while ((match = urlRegex.exec(text)) !== null) {\n const url = match[0];\n const startIndex = match.index;\n\n if (startIndex > lastIndex) {\n parts.push(text.substring(lastIndex, startIndex));\n }\n\n const metadata = linkMetadata[url];\n const displayTitle = metadata?.title \n ? (metadata.title.length > 60 ? metadata.title.substring(0, 60) + '...' : metadata.title)\n : url;\n \n const faviconUrl = metadata?.favicon;\n const extension = getFileExtension(url);\n const fileIcon = extension ? FILE_TYPE_ICONS[extension] : null;\n\n const getTargetAttributes = () => {\n switch (target) {\n case 'new-window':\n return {\n target: '_blank',\n rel: 'noopener noreferrer',\n onClick: (e: React.MouseEvent) => {\n e.preventDefault();\n window.open(url, '_blank', 'noopener,noreferrer,width=800,height=600');\n }\n };\n case 'self':\n return {\n target: '_self'\n };\n case 'new-tab':\n default:\n return {\n target: '_blank',\n rel: 'noopener noreferrer'\n };\n }\n };\n\n parts.push(\n <a\n key={`link-${startIndex}`}\n href={url}\n {...getTargetAttributes()}\n style={{ \n color: customColor || '#646cff', \n textDecoration: 'underline',\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px'\n }}\n >\n {fileIcon ? (\n <span \n style={{ \n fontFamily: '\"Symbols Nerd Font Mono\", \"Symbols Nerd Font\", \"Nerd Font\", \"FiraCode Nerd Font\", monospace',\n fontSize: '16px',\n color: fileIcon.color,\n lineHeight: 1,\n display: 'inline-block',\n width: '16px',\n textAlign: 'center',\n fontWeight: 'normal'\n }}\n aria-hidden=\"true\"\n >\n {fileIcon.icon}\n </span>\n ) : faviconUrl ? (\n <img \n src={faviconUrl} \n alt=\"\" \n style={{ width: '16px', height: '16px' }}\n onError={(e) => {\n (e.target as HTMLImageElement).src = 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"%3E%3Cpath d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/%3E%3Cpath d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/%3E%3C/svg%3E';\n }}\n />\n ) : (\n <svg \n xmlns=\"http://www.w3.org/2000/svg\" \n width=\"16\" \n height=\"16\" \n viewBox=\"0 0 24 24\" \n fill=\"none\" \n stroke=\"currentColor\" \n strokeWidth=\"2\" \n strokeLinecap=\"round\" \n strokeLinejoin=\"round\"\n >\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/>\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/>\n </svg>\n )}\n <span>{displayTitle}</span>\n </a>\n );\n\n lastIndex = startIndex + url.length;\n }\n\n if (lastIndex < text.length) {\n parts.push(text.substring(lastIndex));\n }\n\n return parts.length > 0 ? parts : [text];\n};\n\n/**\n * Fetches metadata (title and favicon) for a given URL\n */\nasync function fetchLinkMetadata(url: string): Promise<LinkMetadata> {\n try {\n const urlObj = new URL(url);\n const origin = urlObj.origin;\n \n const proxies = [\n `https://api.allorigins.win/get?url=${encodeURIComponent(url)}`,\n `https://corsproxy.io/?${encodeURIComponent(url)}`,\n ];\n \n let html = '';\n let success = false;\n \n for (const proxyUrl of proxies) {\n try {\n const response = await fetch(proxyUrl, { \n signal: AbortSignal.timeout(10000) // 10 second timeout\n });\n \n if (!response.ok) continue;\n \n const data = await response.json();\n html = data.contents || data;\n success = true;\n break;\n } catch (err) {\n console.warn('Proxy failed:', proxyUrl, err);\n continue;\n }\n }\n \n if (!success || !html) {\n throw new Error('All proxies failed');\n }\n \n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n \n let title = \n doc.querySelector('meta[property=\"og:title\"]')?.getAttribute('content') ||\n doc.querySelector('meta[name=\"twitter:title\"]')?.getAttribute('content') ||\n doc.querySelector('title')?.textContent ||\n url;\n \n title = title.trim();\n \n let favicon = `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=32`;\n \n const faviconLink = \n doc.querySelector('link[rel=\"icon\"]')?.getAttribute('href') ||\n doc.querySelector('link[rel=\"shortcut icon\"]')?.getAttribute('href') ||\n doc.querySelector('link[rel=\"apple-touch-icon\"]')?.getAttribute('href');\n \n if (faviconLink) {\n if (faviconLink.startsWith('http')) {\n favicon = faviconLink;\n } else if (faviconLink.startsWith('//')) {\n favicon = 'https:' + faviconLink;\n } else if (faviconLink.startsWith('/')) {\n favicon = origin + faviconLink;\n } else {\n favicon = origin + '/' + faviconLink;\n }\n }\n \n return { title, favicon };\n } catch (error) {\n console.error('Error fetching metadata:', error);\n const urlObj = new URL(url);\n return {\n title: urlObj.hostname,\n favicon: `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=32`\n };\n }\n}\n"],"names":["FILE_TYPE_ICONS","getFileExtension","url","pathname","lastDot","useBeautyLink","text","target","customColor","urlRegex","linkMetadata","setLinkMetadata","useState","urls","match","useEffect","extension","filename","prev","metadata","fetchLinkMetadata","error","parts","lastIndex","startIndex","displayTitle","faviconUrl","fileIcon","getTargetAttributes","e","jsxs","jsx","urlObj","origin","proxies","html","success","proxyUrl","response","data","err","doc","title","favicon","faviconLink"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { useBeautyLink, type LinkTarget } from './hooks/useBeautyLink';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,237 @@
1
+ import { jsxs as x, jsx as g } from "react/jsx-runtime";
2
+ import { useState as j, useEffect as C } from "react";
3
+ const y = {
4
+ // Documents
5
+ pdf: { icon: "󰈦", color: "#e74856" },
6
+ doc: { icon: "󰈬", color: "#2b579a" },
7
+ docx: { icon: "󰈬", color: "#2b579a" },
8
+ xls: { icon: "󰈛", color: "#207245" },
9
+ xlsx: { icon: "󰈛", color: "#207245" },
10
+ ppt: { icon: "󰈧", color: "#d24726" },
11
+ pptx: { icon: "󰈧", color: "#d24726" },
12
+ txt: { icon: "󰈙", color: "#6c757d" },
13
+ // Archives
14
+ zip: { icon: "󰗄", color: "#e89f1c" },
15
+ rar: { icon: "󰗄", color: "#e89f1c" },
16
+ "7z": { icon: "󰗄", color: "#e89f1c" },
17
+ tar: { icon: "󰗄", color: "#e89f1c" },
18
+ gz: { icon: "󰗄", color: "#e89f1c" },
19
+ // Images
20
+ jpg: { icon: "󰈟", color: "#a855f7" },
21
+ jpeg: { icon: "󰈟", color: "#a855f7" },
22
+ png: { icon: "󰈟", color: "#a855f7" },
23
+ gif: { icon: "󰈟", color: "#a855f7" },
24
+ svg: { icon: "󰜡", color: "#f97316" },
25
+ webp: { icon: "󰈟", color: "#a855f7" },
26
+ // Videos
27
+ mp4: { icon: "󰕧", color: "#ec4899" },
28
+ avi: { icon: "󰕧", color: "#ec4899" },
29
+ mov: { icon: "󰕧", color: "#ec4899" },
30
+ mkv: { icon: "󰕧", color: "#ec4899" },
31
+ webm: { icon: "󰕧", color: "#ec4899" },
32
+ // Audio
33
+ mp3: { icon: "󰈣", color: "#10b981" },
34
+ wav: { icon: "󰈣", color: "#10b981" },
35
+ flac: { icon: "󰈣", color: "#10b981" },
36
+ ogg: { icon: "󰈣", color: "#10b981" },
37
+ // Code
38
+ js: { icon: "󰌞", color: "#f0db4f" },
39
+ ts: { icon: "󰛦", color: "#3178c6" },
40
+ jsx: { icon: "󰜈", color: "#61dafb" },
41
+ tsx: { icon: "󰜈", color: "#61dafb" },
42
+ py: { icon: "󰌠", color: "#3776ab" },
43
+ java: { icon: "󰬷", color: "#007396" },
44
+ php: { icon: "󰌟", color: "#777bb4" },
45
+ rb: { icon: "󰴭", color: "#cc342d" },
46
+ go: { icon: "󰟓", color: "#00add8" },
47
+ rs: { icon: "󱘗", color: "#dea584" },
48
+ html: { icon: "󰌝", color: "#e34c26" },
49
+ css: { icon: "󰌜", color: "#264de4" },
50
+ json: { icon: "󰘦", color: "#f7df1e" },
51
+ xml: { icon: "󰗀", color: "#ff6600" },
52
+ yaml: { icon: "󰈙", color: "#cb171e" },
53
+ yml: { icon: "󰈙", color: "#cb171e" },
54
+ md: { icon: "󰍔", color: "#083fa1" },
55
+ sql: { icon: "󰆼", color: "#00758f" },
56
+ sh: { icon: "󰆍", color: "#89e051" }
57
+ };
58
+ function k(e) {
59
+ try {
60
+ const c = new URL(e).pathname, i = c.lastIndexOf(".");
61
+ return i === -1 || i === c.length - 1 ? null : c.substring(i + 1).toLowerCase();
62
+ } catch {
63
+ return null;
64
+ }
65
+ }
66
+ const E = (e, d = "new-tab", c) => {
67
+ const i = /(https:\/\/[^\s]+)/g, [h, p] = j({}), u = Array.from(e.matchAll(i)).map((t) => t[0]);
68
+ C(() => {
69
+ (async () => {
70
+ for (const o of u)
71
+ if (!h[o]) {
72
+ const n = k(o);
73
+ if (n && y[n]) {
74
+ const l = o.split("/").pop() || o;
75
+ p((f) => ({
76
+ ...f,
77
+ [o]: {
78
+ title: decodeURIComponent(l),
79
+ favicon: null
80
+ }
81
+ }));
82
+ continue;
83
+ }
84
+ try {
85
+ console.log("Fetching metadata for:", o);
86
+ const l = await S(o);
87
+ console.log("Metadata received:", l), p((f) => ({
88
+ ...f,
89
+ [o]: l
90
+ }));
91
+ } catch (l) {
92
+ console.error("Failed to fetch metadata for", o, l), p((f) => ({
93
+ ...f,
94
+ [o]: {
95
+ title: o,
96
+ favicon: null
97
+ }
98
+ }));
99
+ }
100
+ }
101
+ })();
102
+ }, [e, JSON.stringify(u)]);
103
+ const r = [];
104
+ let a = 0, s;
105
+ for (i.lastIndex = 0; (s = i.exec(e)) !== null; ) {
106
+ const t = s[0], o = s.index;
107
+ o > a && r.push(e.substring(a, o));
108
+ const n = h[t], l = n?.title ? n.title.length > 60 ? n.title.substring(0, 60) + "..." : n.title : t, f = n?.favicon, b = k(t), m = b ? y[b] : null, v = () => {
109
+ switch (d) {
110
+ case "new-window":
111
+ return {
112
+ target: "_blank",
113
+ rel: "noopener noreferrer",
114
+ onClick: (w) => {
115
+ w.preventDefault(), window.open(t, "_blank", "noopener,noreferrer,width=800,height=600");
116
+ }
117
+ };
118
+ case "self":
119
+ return {
120
+ target: "_self"
121
+ };
122
+ default:
123
+ return {
124
+ target: "_blank",
125
+ rel: "noopener noreferrer"
126
+ };
127
+ }
128
+ };
129
+ r.push(
130
+ /* @__PURE__ */ x(
131
+ "a",
132
+ {
133
+ href: t,
134
+ ...v(),
135
+ style: {
136
+ color: c || "#646cff",
137
+ textDecoration: "underline",
138
+ display: "inline-flex",
139
+ alignItems: "center",
140
+ gap: "6px"
141
+ },
142
+ children: [
143
+ m ? /* @__PURE__ */ g(
144
+ "span",
145
+ {
146
+ style: {
147
+ fontFamily: '"Symbols Nerd Font Mono", "Symbols Nerd Font", "Nerd Font", "FiraCode Nerd Font", monospace',
148
+ fontSize: "16px",
149
+ color: m.color,
150
+ lineHeight: 1,
151
+ display: "inline-block",
152
+ width: "16px",
153
+ textAlign: "center",
154
+ fontWeight: "normal"
155
+ },
156
+ "aria-hidden": "true",
157
+ children: m.icon
158
+ }
159
+ ) : f ? /* @__PURE__ */ g(
160
+ "img",
161
+ {
162
+ src: f,
163
+ alt: "",
164
+ style: { width: "16px", height: "16px" },
165
+ onError: (w) => {
166
+ w.target.src = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/%3E%3Cpath d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/%3E%3C/svg%3E';
167
+ }
168
+ }
169
+ ) : /* @__PURE__ */ x(
170
+ "svg",
171
+ {
172
+ xmlns: "http://www.w3.org/2000/svg",
173
+ width: "16",
174
+ height: "16",
175
+ viewBox: "0 0 24 24",
176
+ fill: "none",
177
+ stroke: "currentColor",
178
+ strokeWidth: "2",
179
+ strokeLinecap: "round",
180
+ strokeLinejoin: "round",
181
+ children: [
182
+ /* @__PURE__ */ g("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
183
+ /* @__PURE__ */ g("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
184
+ ]
185
+ }
186
+ ),
187
+ /* @__PURE__ */ g("span", { children: l })
188
+ ]
189
+ },
190
+ `link-${o}`
191
+ )
192
+ ), a = o + t.length;
193
+ }
194
+ return a < e.length && r.push(e.substring(a)), r.length > 0 ? r : [e];
195
+ };
196
+ async function S(e) {
197
+ try {
198
+ const d = new URL(e), c = d.origin, i = [
199
+ `https://api.allorigins.win/get?url=${encodeURIComponent(e)}`,
200
+ `https://corsproxy.io/?${encodeURIComponent(e)}`
201
+ ];
202
+ let h = "", p = !1;
203
+ for (const o of i)
204
+ try {
205
+ const n = await fetch(o, {
206
+ signal: AbortSignal.timeout(1e4)
207
+ // 10 second timeout
208
+ });
209
+ if (!n.ok) continue;
210
+ const l = await n.json();
211
+ h = l.contents || l, p = !0;
212
+ break;
213
+ } catch (n) {
214
+ console.warn("Proxy failed:", o, n);
215
+ continue;
216
+ }
217
+ if (!p || !h)
218
+ throw new Error("All proxies failed");
219
+ const r = new DOMParser().parseFromString(h, "text/html");
220
+ let a = r.querySelector('meta[property="og:title"]')?.getAttribute("content") || r.querySelector('meta[name="twitter:title"]')?.getAttribute("content") || r.querySelector("title")?.textContent || e;
221
+ a = a.trim();
222
+ let s = `https://www.google.com/s2/favicons?domain=${d.hostname}&sz=32`;
223
+ const t = r.querySelector('link[rel="icon"]')?.getAttribute("href") || r.querySelector('link[rel="shortcut icon"]')?.getAttribute("href") || r.querySelector('link[rel="apple-touch-icon"]')?.getAttribute("href");
224
+ return t && (t.startsWith("http") ? s = t : t.startsWith("//") ? s = "https:" + t : t.startsWith("/") ? s = c + t : s = c + "/" + t), { title: a, favicon: s };
225
+ } catch (d) {
226
+ console.error("Error fetching metadata:", d);
227
+ const c = new URL(e);
228
+ return {
229
+ title: c.hostname,
230
+ favicon: `https://www.google.com/s2/favicons?domain=${c.hostname}&sz=32`
231
+ };
232
+ }
233
+ }
234
+ export {
235
+ E as useBeautyLink
236
+ };
237
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/utils/fileIcons.ts","../src/hooks/useBeautyLink.tsx"],"sourcesContent":["interface FileTypeIcon {\n icon: string;\n color: string;\n }\n\nexport const FILE_TYPE_ICONS: Record<string, FileTypeIcon> = {\n // Documents\n 'pdf': { icon: '󰈦', color: '#e74856' },\n 'doc': { icon: '󰈬', color: '#2b579a' },\n 'docx': { icon: '󰈬', color: '#2b579a' },\n 'xls': { icon: '󰈛', color: '#207245' },\n 'xlsx': { icon: '󰈛', color: '#207245' },\n 'ppt': { icon: '󰈧', color: '#d24726' },\n 'pptx': { icon: '󰈧', color: '#d24726' },\n 'txt': { icon: '󰈙', color: '#6c757d' },\n \n // Archives\n 'zip': { icon: '󰗄', color: '#e89f1c' },\n 'rar': { icon: '󰗄', color: '#e89f1c' },\n '7z': { icon: '󰗄', color: '#e89f1c' },\n 'tar': { icon: '󰗄', color: '#e89f1c' },\n 'gz': { icon: '󰗄', color: '#e89f1c' },\n \n // Images\n 'jpg': { icon: '󰈟', color: '#a855f7' },\n 'jpeg': { icon: '󰈟', color: '#a855f7' },\n 'png': { icon: '󰈟', color: '#a855f7' },\n 'gif': { icon: '󰈟', color: '#a855f7' },\n 'svg': { icon: '󰜡', color: '#f97316' },\n 'webp': { icon: '󰈟', color: '#a855f7' },\n \n // Videos\n 'mp4': { icon: '󰕧', color: '#ec4899' },\n 'avi': { icon: '󰕧', color: '#ec4899' },\n 'mov': { icon: '󰕧', color: '#ec4899' },\n 'mkv': { icon: '󰕧', color: '#ec4899' },\n 'webm': { icon: '󰕧', color: '#ec4899' },\n \n // Audio\n 'mp3': { icon: '󰈣', color: '#10b981' },\n 'wav': { icon: '󰈣', color: '#10b981' },\n 'flac': { icon: '󰈣', color: '#10b981' },\n 'ogg': { icon: '󰈣', color: '#10b981' },\n \n // Code\n 'js': { icon: '󰌞', color: '#f0db4f' },\n 'ts': { icon: '󰛦', color: '#3178c6' },\n 'jsx': { icon: '󰜈', color: '#61dafb' },\n 'tsx': { icon: '󰜈', color: '#61dafb' },\n 'py': { icon: '󰌠', color: '#3776ab' },\n 'java': { icon: '󰬷', color: '#007396' },\n 'php': { icon: '󰌟', color: '#777bb4' },\n 'rb': { icon: '󰴭', color: '#cc342d' },\n 'go': { icon: '󰟓', color: '#00add8' },\n 'rs': { icon: '󱘗', color: '#dea584' },\n 'html': { icon: '󰌝', color: '#e34c26' },\n 'css': { icon: '󰌜', color: '#264de4' },\n 'json': { icon: '󰘦', color: '#f7df1e' },\n 'xml': { icon: '󰗀', color: '#ff6600' },\n 'yaml': { icon: '󰈙', color: '#cb171e' },\n 'yml': { icon: '󰈙', color: '#cb171e' },\n 'md': { icon: '󰍔', color: '#083fa1' },\n 'sql': { icon: '󰆼', color: '#00758f' },\n 'sh': { icon: '󰆍', color: '#89e051' },\n };","import { useState, useEffect } from 'react';\nimport type { ReactNode } from 'react';\nimport { FILE_TYPE_ICONS } from '../utils/fileIcons';\n\ninterface LinkMetadata {\n title: string;\n favicon: string | null;\n}\n\nexport type LinkTarget = 'new-tab' | 'new-window' | 'self';\n\n\nfunction getFileExtension(url: string): string | null {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const lastDot = pathname.lastIndexOf('.');\n if (lastDot === -1 || lastDot === pathname.length - 1) return null;\n return pathname.substring(lastDot + 1).toLowerCase();\n } catch {\n return null;\n }\n}\n\n/**\n * Custom hook that converts HTTPS URLs in a string into clickable links\n * with page titles and favicons\n * @param text - The input string containing potential URLs\n * @param target - How to open links: 'new-tab' (default), 'new-window', or 'self'\n * @returns An array of React nodes with text and links\n */\nexport const useBeautyLink = (text: string, target: LinkTarget = 'new-tab', customColor?: string): ReactNode[] => {\n const urlRegex = /(https:\\/\\/[^\\s]+)/g;\n const [linkMetadata, setLinkMetadata] = useState<Record<string, LinkMetadata>>({});\n \n const urls = Array.from(text.matchAll(urlRegex)).map(match => match[0]);\n\n useEffect(() => {\n const fetchAllMetadata = async () => {\n for (const url of urls) {\n if (!linkMetadata[url]) {\n const extension = getFileExtension(url);\n \n // If it's a file URL, skip metadata fetching and use filename\n if (extension && FILE_TYPE_ICONS[extension]) {\n const filename = url.split('/').pop() || url;\n setLinkMetadata(prev => ({\n ...prev,\n [url]: {\n title: decodeURIComponent(filename),\n favicon: null\n }\n }));\n continue;\n }\n \n try {\n console.log('Fetching metadata for:', url);\n const metadata = await fetchLinkMetadata(url);\n console.log('Metadata received:', metadata);\n setLinkMetadata(prev => ({\n ...prev,\n [url]: metadata\n }));\n } catch (error) {\n console.error('Failed to fetch metadata for', url, error);\n setLinkMetadata(prev => ({\n ...prev,\n [url]: {\n title: url,\n favicon: null\n }\n }));\n }\n }\n }\n };\n\n fetchAllMetadata();\n }, [text, JSON.stringify(urls)]);\n\n const parts: ReactNode[] = [];\n let lastIndex = 0;\n let match;\n\n urlRegex.lastIndex = 0;\n while ((match = urlRegex.exec(text)) !== null) {\n const url = match[0];\n const startIndex = match.index;\n\n if (startIndex > lastIndex) {\n parts.push(text.substring(lastIndex, startIndex));\n }\n\n const metadata = linkMetadata[url];\n const displayTitle = metadata?.title \n ? (metadata.title.length > 60 ? metadata.title.substring(0, 60) + '...' : metadata.title)\n : url;\n \n const faviconUrl = metadata?.favicon;\n const extension = getFileExtension(url);\n const fileIcon = extension ? FILE_TYPE_ICONS[extension] : null;\n\n const getTargetAttributes = () => {\n switch (target) {\n case 'new-window':\n return {\n target: '_blank',\n rel: 'noopener noreferrer',\n onClick: (e: React.MouseEvent) => {\n e.preventDefault();\n window.open(url, '_blank', 'noopener,noreferrer,width=800,height=600');\n }\n };\n case 'self':\n return {\n target: '_self'\n };\n case 'new-tab':\n default:\n return {\n target: '_blank',\n rel: 'noopener noreferrer'\n };\n }\n };\n\n parts.push(\n <a\n key={`link-${startIndex}`}\n href={url}\n {...getTargetAttributes()}\n style={{ \n color: customColor || '#646cff', \n textDecoration: 'underline',\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px'\n }}\n >\n {fileIcon ? (\n <span \n style={{ \n fontFamily: '\"Symbols Nerd Font Mono\", \"Symbols Nerd Font\", \"Nerd Font\", \"FiraCode Nerd Font\", monospace',\n fontSize: '16px',\n color: fileIcon.color,\n lineHeight: 1,\n display: 'inline-block',\n width: '16px',\n textAlign: 'center',\n fontWeight: 'normal'\n }}\n aria-hidden=\"true\"\n >\n {fileIcon.icon}\n </span>\n ) : faviconUrl ? (\n <img \n src={faviconUrl} \n alt=\"\" \n style={{ width: '16px', height: '16px' }}\n onError={(e) => {\n (e.target as HTMLImageElement).src = 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"%3E%3Cpath d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/%3E%3Cpath d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/%3E%3C/svg%3E';\n }}\n />\n ) : (\n <svg \n xmlns=\"http://www.w3.org/2000/svg\" \n width=\"16\" \n height=\"16\" \n viewBox=\"0 0 24 24\" \n fill=\"none\" \n stroke=\"currentColor\" \n strokeWidth=\"2\" \n strokeLinecap=\"round\" \n strokeLinejoin=\"round\"\n >\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/>\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/>\n </svg>\n )}\n <span>{displayTitle}</span>\n </a>\n );\n\n lastIndex = startIndex + url.length;\n }\n\n if (lastIndex < text.length) {\n parts.push(text.substring(lastIndex));\n }\n\n return parts.length > 0 ? parts : [text];\n};\n\n/**\n * Fetches metadata (title and favicon) for a given URL\n */\nasync function fetchLinkMetadata(url: string): Promise<LinkMetadata> {\n try {\n const urlObj = new URL(url);\n const origin = urlObj.origin;\n \n const proxies = [\n `https://api.allorigins.win/get?url=${encodeURIComponent(url)}`,\n `https://corsproxy.io/?${encodeURIComponent(url)}`,\n ];\n \n let html = '';\n let success = false;\n \n for (const proxyUrl of proxies) {\n try {\n const response = await fetch(proxyUrl, { \n signal: AbortSignal.timeout(10000) // 10 second timeout\n });\n \n if (!response.ok) continue;\n \n const data = await response.json();\n html = data.contents || data;\n success = true;\n break;\n } catch (err) {\n console.warn('Proxy failed:', proxyUrl, err);\n continue;\n }\n }\n \n if (!success || !html) {\n throw new Error('All proxies failed');\n }\n \n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n \n let title = \n doc.querySelector('meta[property=\"og:title\"]')?.getAttribute('content') ||\n doc.querySelector('meta[name=\"twitter:title\"]')?.getAttribute('content') ||\n doc.querySelector('title')?.textContent ||\n url;\n \n title = title.trim();\n \n let favicon = `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=32`;\n \n const faviconLink = \n doc.querySelector('link[rel=\"icon\"]')?.getAttribute('href') ||\n doc.querySelector('link[rel=\"shortcut icon\"]')?.getAttribute('href') ||\n doc.querySelector('link[rel=\"apple-touch-icon\"]')?.getAttribute('href');\n \n if (faviconLink) {\n if (faviconLink.startsWith('http')) {\n favicon = faviconLink;\n } else if (faviconLink.startsWith('//')) {\n favicon = 'https:' + faviconLink;\n } else if (faviconLink.startsWith('/')) {\n favicon = origin + faviconLink;\n } else {\n favicon = origin + '/' + faviconLink;\n }\n }\n \n return { title, favicon };\n } catch (error) {\n console.error('Error fetching metadata:', error);\n const urlObj = new URL(url);\n return {\n title: urlObj.hostname,\n favicon: `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=32`\n };\n }\n}\n"],"names":["FILE_TYPE_ICONS","getFileExtension","url","pathname","lastDot","useBeautyLink","text","target","customColor","urlRegex","linkMetadata","setLinkMetadata","useState","urls","match","useEffect","extension","filename","prev","metadata","fetchLinkMetadata","error","parts","lastIndex","startIndex","displayTitle","faviconUrl","fileIcon","getTargetAttributes","e","jsxs","jsx","urlObj","origin","proxies","html","success","proxyUrl","response","data","err","doc","title","favicon","faviconLink"],"mappings":"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"}