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.
- package/LICENSE +21 -0
- package/README.md +220 -0
- package/dist/hooks/useBeautyLink.d.ts +11 -0
- package/dist/hooks/useBeautyLink.d.ts.map +1 -0
- package/dist/hooks/useBeautyLink.js +203 -0
- package/dist/hooks/useBeautyLink.js.map +1 -0
- package/dist/hooks/useLinkify.d.ts +11 -0
- package/dist/hooks/useLinkify.d.ts.map +1 -0
- package/dist/hooks/useLinkify.js +257 -0
- package/dist/hooks/useLinkify.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +237 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/fileIcons.d.ts +7 -0
- package/dist/utils/fileIcons.d.ts.map +1 -0
- package/dist/utils/fileIcons.js +56 -0
- package/dist/utils/fileIcons.js.map +1 -0
- package/dist/vite.svg +1 -0
- package/package.json +75 -0
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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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"}
|