react-beauty-link 1.1.5 → 1.1.6
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/dist/hooks/useBeautyLink.d.ts.map +1 -1
- package/dist/hooks/useBeautyLink.js +18 -6
- package/dist/hooks/useBeautyLink.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +79 -76
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBeautyLink.d.ts","sourceRoot":"","sources":["../../src/hooks/useBeautyLink.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAcvC,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;AAe3D;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,SAAQ,UAAsB,EAAE,cAAc,MAAM,KAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"useBeautyLink.d.ts","sourceRoot":"","sources":["../../src/hooks/useBeautyLink.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAcvC,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;AAe3D;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,SAAQ,UAAsB,EAAE,cAAc,MAAM,KAAG,SAAS,EAsK3G,CAAC"}
|
|
@@ -49,16 +49,20 @@ export const useBeautyLink = (text, target = 'new-tab', customColor) => {
|
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
51
|
try {
|
|
52
|
-
console.log('Fetching metadata for:', url);
|
|
53
52
|
const metadata = await fetchLinkMetadata(url);
|
|
54
|
-
|
|
53
|
+
if (process.env.NODE_ENV === 'development') {
|
|
54
|
+
console.debug('[react-beauty-link] Metadata fetched:', url);
|
|
55
|
+
}
|
|
55
56
|
setLinkMetadata(prev => ({
|
|
56
57
|
...prev,
|
|
57
58
|
[url]: metadata
|
|
58
59
|
}));
|
|
59
60
|
}
|
|
60
61
|
catch (error) {
|
|
61
|
-
|
|
62
|
+
// Silently fall back to URL - this is expected behavior
|
|
63
|
+
if (process.env.NODE_ENV === 'development') {
|
|
64
|
+
console.debug('[react-beauty-link] Using URL fallback for:', url);
|
|
65
|
+
}
|
|
62
66
|
setLinkMetadata(prev => ({
|
|
63
67
|
...prev,
|
|
64
68
|
[url]: {
|
|
@@ -147,13 +151,14 @@ async function fetchLinkMetadata(url) {
|
|
|
147
151
|
const proxies = [
|
|
148
152
|
`https://api.allorigins.win/get?url=${encodeURIComponent(url)}`,
|
|
149
153
|
`https://corsproxy.io/?${encodeURIComponent(url)}`,
|
|
154
|
+
`https://api.codetabs.com/v1/proxy?quest=${encodeURIComponent(url)}`,
|
|
150
155
|
];
|
|
151
156
|
let html = '';
|
|
152
157
|
let success = false;
|
|
153
158
|
for (const proxyUrl of proxies) {
|
|
154
159
|
try {
|
|
155
160
|
const response = await fetch(proxyUrl, {
|
|
156
|
-
signal: AbortSignal.timeout(
|
|
161
|
+
signal: AbortSignal.timeout(5000) // 5 second timeout (faster failover)
|
|
157
162
|
});
|
|
158
163
|
if (!response.ok)
|
|
159
164
|
continue;
|
|
@@ -163,7 +168,11 @@ async function fetchLinkMetadata(url) {
|
|
|
163
168
|
break;
|
|
164
169
|
}
|
|
165
170
|
catch (err) {
|
|
166
|
-
|
|
171
|
+
// Only log in development mode to reduce console noise
|
|
172
|
+
if (process.env.NODE_ENV === 'development') {
|
|
173
|
+
const errorName = err instanceof Error ? err.name : 'Unknown error';
|
|
174
|
+
console.debug('[react-beauty-link] Proxy failed:', proxyUrl.split('?')[0], errorName);
|
|
175
|
+
}
|
|
167
176
|
continue;
|
|
168
177
|
}
|
|
169
178
|
}
|
|
@@ -198,7 +207,10 @@ async function fetchLinkMetadata(url) {
|
|
|
198
207
|
return { title, favicon };
|
|
199
208
|
}
|
|
200
209
|
catch (error) {
|
|
201
|
-
|
|
210
|
+
// Graceful fallback - use hostname and Google favicon service
|
|
211
|
+
if (process.env.NODE_ENV === 'development') {
|
|
212
|
+
console.debug('[react-beauty-link] Metadata fetch failed, using fallback');
|
|
213
|
+
}
|
|
202
214
|
const urlObj = new URL(url);
|
|
203
215
|
return {
|
|
204
216
|
title: urlObj.hostname,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBeautyLink.js","sourceRoot":"","sources":["../../src/hooks/useBeautyLink.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,0EAA0E;AAC1E,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;IAClC,aAAa,EAAE,CAAC;AAClB,CAAC;AAUD,SAAS,gBAAgB,CAAC,GAAW;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACnE,OAAO,QAAQ,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,SAAqB,SAAS,EAAE,WAAoB,EAAe,EAAE;IAC/G,MAAM,QAAQ,GAAG,qBAAqB,CAAC;IACvC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAA+B,EAAE,CAAC,CAAC;IAEnF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAExE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;YAClC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;oBACvB,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;oBAExC,8DAA8D;oBAC9D,IAAI,SAAS,IAAI,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC5C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC;wBAC7C,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BACvB,GAAG,IAAI;4BACP,CAAC,GAAG,CAAC,EAAE;gCACL,KAAK,EAAE,kBAAkB,CAAC,QAAQ,CAAC;gCACnC,OAAO,EAAE,IAAI;6BACd;yBACF,CAAC,CAAC,CAAC;wBACJ,SAAS;oBACX,CAAC;oBAED,IAAI,CAAC;wBACH,
|
|
1
|
+
{"version":3,"file":"useBeautyLink.js","sourceRoot":"","sources":["../../src/hooks/useBeautyLink.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,0EAA0E;AAC1E,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;IAClC,aAAa,EAAE,CAAC;AAClB,CAAC;AAUD,SAAS,gBAAgB,CAAC,GAAW;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACnE,OAAO,QAAQ,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,SAAqB,SAAS,EAAE,WAAoB,EAAe,EAAE;IAC/G,MAAM,QAAQ,GAAG,qBAAqB,CAAC;IACvC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAA+B,EAAE,CAAC,CAAC;IAEnF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAExE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;YAClC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;oBACvB,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;oBAExC,8DAA8D;oBAC9D,IAAI,SAAS,IAAI,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC5C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC;wBAC7C,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BACvB,GAAG,IAAI;4BACP,CAAC,GAAG,CAAC,EAAE;gCACL,KAAK,EAAE,kBAAkB,CAAC,QAAQ,CAAC;gCACnC,OAAO,EAAE,IAAI;6BACd;yBACF,CAAC,CAAC,CAAC;wBACJ,SAAS;oBACX,CAAC;oBAED,IAAI,CAAC;wBACH,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;wBAC9C,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;4BAC3C,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;wBAC9D,CAAC;wBACD,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BACvB,GAAG,IAAI;4BACP,CAAC,GAAG,CAAC,EAAE,QAAQ;yBAChB,CAAC,CAAC,CAAC;oBACN,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,wDAAwD;wBACxD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;4BAC3C,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,GAAG,CAAC,CAAC;wBACpE,CAAC;wBACD,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BACvB,GAAG,IAAI;4BACP,CAAC,GAAG,CAAC,EAAE;gCACL,KAAK,EAAE,GAAG;gCACV,OAAO,EAAE,IAAI;6BACd;yBACF,CAAC,CAAC,CAAC;oBACN,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,gBAAgB,EAAE,CAAC;IACrB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEjC,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,KAAK,CAAC;IAEV,QAAQ,CAAC,SAAS,GAAG,CAAC,CAAC;IACvB,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC;QAE/B,IAAI,UAAU,GAAG,SAAS,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,YAAY,GAAG,QAAQ,EAAE,KAAK;YAClC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;YACzF,CAAC,CAAC,GAAG,CAAC;QAER,MAAM,UAAU,GAAG,QAAQ,EAAE,OAAO,CAAC;QACrC,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE/D,MAAM,mBAAmB,GAAG,GAAG,EAAE;YAC/B,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,YAAY;oBACf,OAAO;wBACL,MAAM,EAAE,QAAQ;wBAChB,GAAG,EAAE,qBAAqB;wBAC1B,OAAO,EAAE,CAAC,CAAmB,EAAE,EAAE;4BAC/B,CAAC,CAAC,cAAc,EAAE,CAAC;4BACnB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,0CAA0C,CAAC,CAAC;wBACzE,CAAC;qBACF,CAAC;gBACJ,KAAK,MAAM;oBACT,OAAO;wBACL,MAAM,EAAE,OAAO;qBAChB,CAAC;gBACJ,KAAK,SAAS,CAAC;gBACf;oBACE,OAAO;wBACL,MAAM,EAAE,QAAQ;wBAChB,GAAG,EAAE,qBAAqB;qBAC3B,CAAC;YACN,CAAC;QACH,CAAC,CAAC;QAEF,KAAK,CAAC,IAAI,CACR,aAEE,IAAI,EAAE,GAAG,KACL,mBAAmB,EAAE,EACzB,KAAK,EAAE;gBACL,KAAK,EAAE,WAAW,IAAI,SAAS;gBAC/B,cAAc,EAAE,WAAW;gBAC3B,OAAO,EAAE,aAAa;gBACtB,UAAU,EAAE,QAAQ;gBACpB,GAAG,EAAE,KAAK;aACX,aAEA,QAAQ,CAAC,CAAC,CAAC,CACV,eACE,KAAK,EAAE;wBACL,UAAU,EAAE,6FAA6F;wBACzG,QAAQ,EAAE,MAAM;wBAChB,KAAK,EAAE,QAAQ,CAAC,KAAK;wBACrB,UAAU,EAAE,CAAC;wBACb,OAAO,EAAE,cAAc;wBACvB,KAAK,EAAE,MAAM;wBACb,SAAS,EAAE,QAAQ;wBACnB,UAAU,EAAE,QAAQ;qBACrB,iBACW,MAAM,YAEjB,QAAQ,CAAC,IAAI,GACT,CACR,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CACf,cACE,GAAG,EAAE,UAAU,EACf,GAAG,EAAC,EAAE,EACN,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EACxC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;wBACZ,CAAC,CAAC,MAA2B,CAAC,GAAG,GAAG,+WAA+W,CAAC;oBACvZ,CAAC,GACD,CACH,CAAC,CAAC,CAAC,CACF,eACE,KAAK,EAAC,4BAA4B,EAClC,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,aAEtB,eAAM,CAAC,EAAC,6DAA6D,GAAE,EACvE,eAAM,CAAC,EAAC,8DAA8D,GAAE,IACpE,CACP,EACD,yBAAO,YAAY,GAAQ,KApDtB,QAAQ,UAAU,EAAE,CAqDvB,CACL,CAAC;QAEF,SAAS,GAAG,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC;IACtC,CAAC;IAED,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF;;GAEG;AACH,KAAK,UAAU,iBAAiB,CAAC,GAAW;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAE7B,MAAM,OAAO,GAAG;YACd,sCAAsC,kBAAkB,CAAC,GAAG,CAAC,EAAE;YAC/D,yBAAyB,kBAAkB,CAAC,GAAG,CAAC,EAAE;YAClD,2CAA2C,kBAAkB,CAAC,GAAG,CAAC,EAAE;SACrE,CAAC;QAEF,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;oBACrC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,qCAAqC;iBACxE,CAAC,CAAC;gBAEH,IAAI,CAAC,QAAQ,CAAC,EAAE;oBAAE,SAAS;gBAE3B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;gBAC7B,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM;YACR,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,uDAAuD;gBACvD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;oBAC3C,MAAM,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC;oBACpE,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;gBACxF,CAAC;gBACD,SAAS;YACX,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAEtD,IAAI,KAAK,GACP,GAAG,CAAC,aAAa,CAAC,2BAA2B,CAAC,EAAE,YAAY,CAAC,SAAS,CAAC;YACvE,GAAG,CAAC,aAAa,CAAC,4BAA4B,CAAC,EAAE,YAAY,CAAC,SAAS,CAAC;YACxE,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,WAAW;YACvC,GAAG,CAAC;QAEN,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAErB,IAAI,OAAO,GAAG,6CAA6C,MAAM,CAAC,QAAQ,QAAQ,CAAC;QAEnF,MAAM,WAAW,GACf,GAAG,CAAC,aAAa,CAAC,kBAAkB,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC;YAC3D,GAAG,CAAC,aAAa,CAAC,2BAA2B,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC;YACpE,GAAG,CAAC,aAAa,CAAC,8BAA8B,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;QAE1E,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnC,OAAO,GAAG,WAAW,CAAC;YACxB,CAAC;iBAAM,IAAI,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxC,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;YACnC,CAAC;iBAAM,IAAI,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvC,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,MAAM,GAAG,GAAG,GAAG,WAAW,CAAC;YACvC,CAAC;QACH,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,8DAA8D;QAC9D,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YAC3C,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,QAAQ;YACtB,OAAO,EAAE,6CAA6C,MAAM,CAAC,QAAQ,QAAQ;SAC9E,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react/jsx-runtime"),x=require("react"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react/jsx-runtime"),x=require("react"),v={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"}};let b=!1;function N(){if(typeof window>"u"||typeof document>"u"||b)return;const o="react-beauty-link-nerd-fonts";if(document.getElementById(o)){b=!0;return}try{const r=document.createElement("style");r.id=o,r.textContent=`
|
|
2
2
|
/* react-beauty-link: Nerd Font Symbols */
|
|
3
3
|
@font-face {
|
|
4
4
|
font-family: 'Symbols Nerd Font';
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
font-style: normal;
|
|
16
16
|
font-display: swap;
|
|
17
17
|
}
|
|
18
|
-
`,document.head.appendChild(
|
|
18
|
+
`,document.head.appendChild(r),b=!0,typeof console<"u"&&console.debug&&console.debug("[react-beauty-link] Nerd Fonts loaded successfully")}catch(r){console.error("[react-beauty-link] Failed to load Nerd Fonts:",r)}}typeof window<"u"&&N();function k(o){try{const l=new URL(o).pathname,s=l.lastIndexOf(".");return s===-1||s===l.length-1?null:l.substring(s+1).toLowerCase()}catch{return null}}const S=(o,r="new-tab",l)=>{const s=/(https:\/\/[^\s]+)/g,[p,h]=x.useState({}),g=Array.from(o.matchAll(s)).map(t=>t[0]);x.useEffect(()=>{(async()=>{for(const e of g)if(!p[e]){const n=k(e);if(n&&v[n]){const i=e.split("/").pop()||e;h(f=>({...f,[e]:{title:decodeURIComponent(i),favicon:null}}));continue}try{const i=await E(e);process.env.NODE_ENV==="development"&&console.debug("[react-beauty-link] Metadata fetched:",e),h(f=>({...f,[e]:i}))}catch{process.env.NODE_ENV==="development"&&console.debug("[react-beauty-link] Using URL fallback for:",e),h(f=>({...f,[e]:{title:e,favicon:null}}))}}})()},[o,JSON.stringify(g)]);const c=[];let a=0,d;for(s.lastIndex=0;(d=s.exec(o))!==null;){const t=d[0],e=d.index;e>a&&c.push(o.substring(a,e));const n=p[t],i=n?.title?n.title.length>60?n.title.substring(0,60)+"...":n.title:t,f=n?.favicon,w=k(t),m=w?v[w]:null,j=()=>{switch(r){case"new-window":return{target:"_blank",rel:"noopener noreferrer",onClick:y=>{y.preventDefault(),window.open(t,"_blank","noopener,noreferrer,width=800,height=600")}};case"self":return{target:"_self"};default:return{target:"_blank",rel:"noopener noreferrer"}}};c.push(u.jsxs("a",{href:t,...j(),style:{color:l||"#646cff",textDecoration:"underline",display:"inline-flex",alignItems:"center",gap:"6px"},children:[m?u.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?u.jsx("img",{src:f,alt:"",style:{width:"16px",height:"16px"},onError:y=>{y.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'}}):u.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:[u.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"}),u.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"})]}),u.jsx("span",{children:i})]},`link-${e}`)),a=e+t.length}return a<o.length&&c.push(o.substring(a)),c.length>0?c:[o]};async function E(o){try{const r=new URL(o),l=r.origin,s=[`https://api.allorigins.win/get?url=${encodeURIComponent(o)}`,`https://corsproxy.io/?${encodeURIComponent(o)}`,`https://api.codetabs.com/v1/proxy?quest=${encodeURIComponent(o)}`];let p="",h=!1;for(const e of s)try{const n=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!n.ok)continue;const i=await n.json();p=i.contents||i,h=!0;break}catch(n){if(process.env.NODE_ENV==="development"){const i=n instanceof Error?n.name:"Unknown error";console.debug("[react-beauty-link] Proxy failed:",e.split("?")[0],i)}continue}if(!h||!p)throw new Error("All proxies failed");const c=new DOMParser().parseFromString(p,"text/html");let a=c.querySelector('meta[property="og:title"]')?.getAttribute("content")||c.querySelector('meta[name="twitter:title"]')?.getAttribute("content")||c.querySelector("title")?.textContent||o;a=a.trim();let d=`https://www.google.com/s2/favicons?domain=${r.hostname}&sz=32`;const t=c.querySelector('link[rel="icon"]')?.getAttribute("href")||c.querySelector('link[rel="shortcut icon"]')?.getAttribute("href")||c.querySelector('link[rel="apple-touch-icon"]')?.getAttribute("href");return t&&(t.startsWith("http")?d=t:t.startsWith("//")?d="https:"+t:t.startsWith("/")?d=l+t:d=l+"/"+t),{title:a,favicon:d}}catch{process.env.NODE_ENV==="development"&&console.debug("[react-beauty-link] Metadata fetch failed, using fallback");const l=new URL(o);return{title:l.hostname,favicon:`https://www.google.com/s2/favicons?domain=${l.hostname}&sz=32`}}}exports.loadNerdFonts=N;exports.useBeautyLink=S;
|
|
19
19
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/utils/fileIcons.ts","../src/utils/loadNerdFonts.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 };","// Load Nerd Fonts dynamically for file type icons\nlet fontsLoaded = false;\n\nexport function loadNerdFonts() {\n // SSR check\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n // Only inject once\n if (fontsLoaded) {\n return;\n }\n\n const styleId = 'react-beauty-link-nerd-fonts';\n \n // Check if already injected\n if (document.getElementById(styleId)) {\n fontsLoaded = true;\n return;\n }\n\n try {\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n /* react-beauty-link: Nerd Font Symbols */\n @font-face {\n font-family: 'Symbols Nerd Font';\n src: url('https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@v3.1.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFont-Regular.ttf') format('truetype');\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n }\n\n @font-face {\n font-family: 'Symbols Nerd Font Mono';\n src: url('https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@v3.1.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFontMono-Regular.ttf') format('truetype');\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n }\n `;\n\n document.head.appendChild(style);\n fontsLoaded = true;\n \n // Debug log (can be removed in production)\n if (typeof console !== 'undefined' && console.debug) {\n console.debug('[react-beauty-link] Nerd Fonts loaded successfully');\n }\n } catch (error) {\n console.error('[react-beauty-link] Failed to load Nerd Fonts:', error);\n }\n}\n","import { useState, useEffect } from 'react';\nimport type { ReactNode } from 'react';\nimport { FILE_TYPE_ICONS } from '../utils/fileIcons';\nimport { loadNerdFonts } from '../utils/loadNerdFonts';\n\n// Load fonts immediately when module is imported (browser only, one-time)\nif (typeof window !== 'undefined') {\n loadNerdFonts();\n}\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 * @param customColor - Custom color for links (optional)\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","fontsLoaded","loadNerdFonts","styleId","style","error","getFileExtension","url","pathname","lastDot","useBeautyLink","text","target","customColor","urlRegex","linkMetadata","setLinkMetadata","useState","urls","match","useEffect","extension","filename","prev","metadata","fetchLinkMetadata","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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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/utils/fileIcons.ts","../src/utils/loadNerdFonts.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 };","// Load Nerd Fonts dynamically for file type icons\nlet fontsLoaded = false;\n\nexport function loadNerdFonts() {\n // SSR check\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n // Only inject once\n if (fontsLoaded) {\n return;\n }\n\n const styleId = 'react-beauty-link-nerd-fonts';\n \n // Check if already injected\n if (document.getElementById(styleId)) {\n fontsLoaded = true;\n return;\n }\n\n try {\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n /* react-beauty-link: Nerd Font Symbols */\n @font-face {\n font-family: 'Symbols Nerd Font';\n src: url('https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@v3.1.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFont-Regular.ttf') format('truetype');\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n }\n\n @font-face {\n font-family: 'Symbols Nerd Font Mono';\n src: url('https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@v3.1.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFontMono-Regular.ttf') format('truetype');\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n }\n `;\n\n document.head.appendChild(style);\n fontsLoaded = true;\n \n // Debug log (can be removed in production)\n if (typeof console !== 'undefined' && console.debug) {\n console.debug('[react-beauty-link] Nerd Fonts loaded successfully');\n }\n } catch (error) {\n console.error('[react-beauty-link] Failed to load Nerd Fonts:', error);\n }\n}\n","import { useState, useEffect } from 'react';\nimport type { ReactNode } from 'react';\nimport { FILE_TYPE_ICONS } from '../utils/fileIcons';\nimport { loadNerdFonts } from '../utils/loadNerdFonts';\n\n// Load fonts immediately when module is imported (browser only, one-time)\nif (typeof window !== 'undefined') {\n loadNerdFonts();\n}\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 * @param customColor - Custom color for links (optional)\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 const metadata = await fetchLinkMetadata(url);\n if (process.env.NODE_ENV === 'development') {\n console.debug('[react-beauty-link] Metadata fetched:', url);\n }\n setLinkMetadata(prev => ({\n ...prev,\n [url]: metadata\n }));\n } catch (error) {\n // Silently fall back to URL - this is expected behavior\n if (process.env.NODE_ENV === 'development') {\n console.debug('[react-beauty-link] Using URL fallback for:', url);\n }\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 `https://api.codetabs.com/v1/proxy?quest=${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(5000) // 5 second timeout (faster failover)\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 // Only log in development mode to reduce console noise\n if (process.env.NODE_ENV === 'development') {\n const errorName = err instanceof Error ? err.name : 'Unknown error';\n console.debug('[react-beauty-link] Proxy failed:', proxyUrl.split('?')[0], errorName);\n }\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 // Graceful fallback - use hostname and Google favicon service\n if (process.env.NODE_ENV === 'development') {\n console.debug('[react-beauty-link] Metadata fetch failed, using fallback');\n }\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","fontsLoaded","loadNerdFonts","styleId","style","error","getFileExtension","url","pathname","lastDot","useBeautyLink","text","target","customColor","urlRegex","linkMetadata","setLinkMetadata","useState","urls","match","useEffect","extension","filename","prev","metadata","fetchLinkMetadata","parts","lastIndex","startIndex","displayTitle","faviconUrl","fileIcon","getTargetAttributes","e","jsxs","jsx","urlObj","origin","proxies","html","success","proxyUrl","response","data","err","errorName","doc","title","favicon","faviconLink"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs as x, jsx as h } from "react/jsx-runtime";
|
|
2
|
-
import { useState as
|
|
3
|
-
const
|
|
2
|
+
import { useState as E, useEffect as S } from "react";
|
|
3
|
+
const v = {
|
|
4
4
|
// Documents
|
|
5
5
|
pdf: { icon: "", color: "#e74856" },
|
|
6
6
|
doc: { icon: "", color: "#2b579a" },
|
|
@@ -55,18 +55,18 @@ const k = {
|
|
|
55
55
|
sql: { icon: "", color: "#00758f" },
|
|
56
56
|
sh: { icon: "", color: "#89e051" }
|
|
57
57
|
};
|
|
58
|
-
let
|
|
59
|
-
function
|
|
60
|
-
if (typeof window > "u" || typeof document > "u" ||
|
|
58
|
+
let b = !1;
|
|
59
|
+
function F() {
|
|
60
|
+
if (typeof window > "u" || typeof document > "u" || b)
|
|
61
61
|
return;
|
|
62
|
-
const
|
|
63
|
-
if (document.getElementById(
|
|
64
|
-
|
|
62
|
+
const o = "react-beauty-link-nerd-fonts";
|
|
63
|
+
if (document.getElementById(o)) {
|
|
64
|
+
b = !0;
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
67
|
try {
|
|
68
|
-
const
|
|
69
|
-
|
|
68
|
+
const r = document.createElement("style");
|
|
69
|
+
r.id = o, r.textContent = `
|
|
70
70
|
/* react-beauty-link: Nerd Font Symbols */
|
|
71
71
|
@font-face {
|
|
72
72
|
font-family: 'Symbols Nerd Font';
|
|
@@ -83,32 +83,32 @@ function C() {
|
|
|
83
83
|
font-style: normal;
|
|
84
84
|
font-display: swap;
|
|
85
85
|
}
|
|
86
|
-
`, document.head.appendChild(
|
|
87
|
-
} catch (
|
|
88
|
-
console.error("[react-beauty-link] Failed to load Nerd Fonts:",
|
|
86
|
+
`, document.head.appendChild(r), b = !0, typeof console < "u" && console.debug && console.debug("[react-beauty-link] Nerd Fonts loaded successfully");
|
|
87
|
+
} catch (r) {
|
|
88
|
+
console.error("[react-beauty-link] Failed to load Nerd Fonts:", r);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
typeof window < "u" &&
|
|
92
|
-
function
|
|
91
|
+
typeof window < "u" && F();
|
|
92
|
+
function k(o) {
|
|
93
93
|
try {
|
|
94
|
-
const l = new URL(
|
|
94
|
+
const l = new URL(o).pathname, s = l.lastIndexOf(".");
|
|
95
95
|
return s === -1 || s === l.length - 1 ? null : l.substring(s + 1).toLowerCase();
|
|
96
96
|
} catch {
|
|
97
97
|
return null;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
const
|
|
101
|
-
const s = /(https:\/\/[^\s]+)/g, [p, u] =
|
|
102
|
-
|
|
100
|
+
const I = (o, r = "new-tab", l) => {
|
|
101
|
+
const s = /(https:\/\/[^\s]+)/g, [p, u] = E({}), m = Array.from(o.matchAll(s)).map((t) => t[0]);
|
|
102
|
+
S(() => {
|
|
103
103
|
(async () => {
|
|
104
|
-
for (const
|
|
105
|
-
if (!p[
|
|
106
|
-
const
|
|
107
|
-
if (
|
|
108
|
-
const i =
|
|
109
|
-
u((
|
|
110
|
-
...
|
|
111
|
-
[
|
|
104
|
+
for (const e of m)
|
|
105
|
+
if (!p[e]) {
|
|
106
|
+
const n = k(e);
|
|
107
|
+
if (n && v[n]) {
|
|
108
|
+
const i = e.split("/").pop() || e;
|
|
109
|
+
u((f) => ({
|
|
110
|
+
...f,
|
|
111
|
+
[e]: {
|
|
112
112
|
title: decodeURIComponent(i),
|
|
113
113
|
favicon: null
|
|
114
114
|
}
|
|
@@ -116,37 +116,36 @@ const E = (t, n = "new-tab", l) => {
|
|
|
116
116
|
continue;
|
|
117
117
|
}
|
|
118
118
|
try {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
[o]: i
|
|
119
|
+
const i = await j(e);
|
|
120
|
+
process.env.NODE_ENV === "development" && console.debug("[react-beauty-link] Metadata fetched:", e), u((f) => ({
|
|
121
|
+
...f,
|
|
122
|
+
[e]: i
|
|
124
123
|
}));
|
|
125
|
-
} catch
|
|
126
|
-
console.
|
|
127
|
-
...
|
|
128
|
-
[
|
|
129
|
-
title:
|
|
124
|
+
} catch {
|
|
125
|
+
process.env.NODE_ENV === "development" && console.debug("[react-beauty-link] Using URL fallback for:", e), u((f) => ({
|
|
126
|
+
...f,
|
|
127
|
+
[e]: {
|
|
128
|
+
title: e,
|
|
130
129
|
favicon: null
|
|
131
130
|
}
|
|
132
131
|
}));
|
|
133
132
|
}
|
|
134
133
|
}
|
|
135
134
|
})();
|
|
136
|
-
}, [
|
|
135
|
+
}, [o, JSON.stringify(m)]);
|
|
137
136
|
const c = [];
|
|
138
|
-
let a = 0,
|
|
139
|
-
for (s.lastIndex = 0; (
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
switch (
|
|
137
|
+
let a = 0, d;
|
|
138
|
+
for (s.lastIndex = 0; (d = s.exec(o)) !== null; ) {
|
|
139
|
+
const t = d[0], e = d.index;
|
|
140
|
+
e > a && c.push(o.substring(a, e));
|
|
141
|
+
const n = p[t], i = n?.title ? n.title.length > 60 ? n.title.substring(0, 60) + "..." : n.title : t, f = n?.favicon, w = k(t), g = w ? v[w] : null, N = () => {
|
|
142
|
+
switch (r) {
|
|
144
143
|
case "new-window":
|
|
145
144
|
return {
|
|
146
145
|
target: "_blank",
|
|
147
146
|
rel: "noopener noreferrer",
|
|
148
147
|
onClick: (y) => {
|
|
149
|
-
y.preventDefault(), window.open(
|
|
148
|
+
y.preventDefault(), window.open(t, "_blank", "noopener,noreferrer,width=800,height=600");
|
|
150
149
|
}
|
|
151
150
|
};
|
|
152
151
|
case "self":
|
|
@@ -164,8 +163,8 @@ const E = (t, n = "new-tab", l) => {
|
|
|
164
163
|
/* @__PURE__ */ x(
|
|
165
164
|
"a",
|
|
166
165
|
{
|
|
167
|
-
href:
|
|
168
|
-
...
|
|
166
|
+
href: t,
|
|
167
|
+
...N(),
|
|
169
168
|
style: {
|
|
170
169
|
color: l || "#646cff",
|
|
171
170
|
textDecoration: "underline",
|
|
@@ -174,13 +173,13 @@ const E = (t, n = "new-tab", l) => {
|
|
|
174
173
|
gap: "6px"
|
|
175
174
|
},
|
|
176
175
|
children: [
|
|
177
|
-
|
|
176
|
+
g ? /* @__PURE__ */ h(
|
|
178
177
|
"span",
|
|
179
178
|
{
|
|
180
179
|
style: {
|
|
181
180
|
fontFamily: '"Symbols Nerd Font Mono", "Symbols Nerd Font", "Nerd Font", "FiraCode Nerd Font", monospace',
|
|
182
181
|
fontSize: "16px",
|
|
183
|
-
color:
|
|
182
|
+
color: g.color,
|
|
184
183
|
lineHeight: 1,
|
|
185
184
|
display: "inline-block",
|
|
186
185
|
width: "16px",
|
|
@@ -188,12 +187,12 @@ const E = (t, n = "new-tab", l) => {
|
|
|
188
187
|
fontWeight: "normal"
|
|
189
188
|
},
|
|
190
189
|
"aria-hidden": "true",
|
|
191
|
-
children:
|
|
190
|
+
children: g.icon
|
|
192
191
|
}
|
|
193
|
-
) :
|
|
192
|
+
) : f ? /* @__PURE__ */ h(
|
|
194
193
|
"img",
|
|
195
194
|
{
|
|
196
|
-
src:
|
|
195
|
+
src: f,
|
|
197
196
|
alt: "",
|
|
198
197
|
style: { width: "16px", height: "16px" },
|
|
199
198
|
onError: (y) => {
|
|
@@ -221,44 +220,48 @@ const E = (t, n = "new-tab", l) => {
|
|
|
221
220
|
/* @__PURE__ */ h("span", { children: i })
|
|
222
221
|
]
|
|
223
222
|
},
|
|
224
|
-
`link-${
|
|
223
|
+
`link-${e}`
|
|
225
224
|
)
|
|
226
|
-
), a =
|
|
225
|
+
), a = e + t.length;
|
|
227
226
|
}
|
|
228
|
-
return a <
|
|
227
|
+
return a < o.length && c.push(o.substring(a)), c.length > 0 ? c : [o];
|
|
229
228
|
};
|
|
230
|
-
async function
|
|
229
|
+
async function j(o) {
|
|
231
230
|
try {
|
|
232
|
-
const
|
|
233
|
-
`https://api.allorigins.win/get?url=${encodeURIComponent(
|
|
234
|
-
`https://corsproxy.io/?${encodeURIComponent(
|
|
231
|
+
const r = new URL(o), l = r.origin, s = [
|
|
232
|
+
`https://api.allorigins.win/get?url=${encodeURIComponent(o)}`,
|
|
233
|
+
`https://corsproxy.io/?${encodeURIComponent(o)}`,
|
|
234
|
+
`https://api.codetabs.com/v1/proxy?quest=${encodeURIComponent(o)}`
|
|
235
235
|
];
|
|
236
236
|
let p = "", u = !1;
|
|
237
|
-
for (const
|
|
237
|
+
for (const e of s)
|
|
238
238
|
try {
|
|
239
|
-
const
|
|
240
|
-
signal: AbortSignal.timeout(
|
|
241
|
-
//
|
|
239
|
+
const n = await fetch(e, {
|
|
240
|
+
signal: AbortSignal.timeout(5e3)
|
|
241
|
+
// 5 second timeout (faster failover)
|
|
242
242
|
});
|
|
243
|
-
if (!
|
|
244
|
-
const i = await
|
|
243
|
+
if (!n.ok) continue;
|
|
244
|
+
const i = await n.json();
|
|
245
245
|
p = i.contents || i, u = !0;
|
|
246
246
|
break;
|
|
247
|
-
} catch (
|
|
248
|
-
|
|
247
|
+
} catch (n) {
|
|
248
|
+
if (process.env.NODE_ENV === "development") {
|
|
249
|
+
const i = n instanceof Error ? n.name : "Unknown error";
|
|
250
|
+
console.debug("[react-beauty-link] Proxy failed:", e.split("?")[0], i);
|
|
251
|
+
}
|
|
249
252
|
continue;
|
|
250
253
|
}
|
|
251
254
|
if (!u || !p)
|
|
252
255
|
throw new Error("All proxies failed");
|
|
253
256
|
const c = new DOMParser().parseFromString(p, "text/html");
|
|
254
|
-
let a = c.querySelector('meta[property="og:title"]')?.getAttribute("content") || c.querySelector('meta[name="twitter:title"]')?.getAttribute("content") || c.querySelector("title")?.textContent ||
|
|
257
|
+
let a = c.querySelector('meta[property="og:title"]')?.getAttribute("content") || c.querySelector('meta[name="twitter:title"]')?.getAttribute("content") || c.querySelector("title")?.textContent || o;
|
|
255
258
|
a = a.trim();
|
|
256
|
-
let
|
|
257
|
-
const
|
|
258
|
-
return
|
|
259
|
-
} catch
|
|
260
|
-
console.
|
|
261
|
-
const l = new URL(
|
|
259
|
+
let d = `https://www.google.com/s2/favicons?domain=${r.hostname}&sz=32`;
|
|
260
|
+
const t = c.querySelector('link[rel="icon"]')?.getAttribute("href") || c.querySelector('link[rel="shortcut icon"]')?.getAttribute("href") || c.querySelector('link[rel="apple-touch-icon"]')?.getAttribute("href");
|
|
261
|
+
return t && (t.startsWith("http") ? d = t : t.startsWith("//") ? d = "https:" + t : t.startsWith("/") ? d = l + t : d = l + "/" + t), { title: a, favicon: d };
|
|
262
|
+
} catch {
|
|
263
|
+
process.env.NODE_ENV === "development" && console.debug("[react-beauty-link] Metadata fetch failed, using fallback");
|
|
264
|
+
const l = new URL(o);
|
|
262
265
|
return {
|
|
263
266
|
title: l.hostname,
|
|
264
267
|
favicon: `https://www.google.com/s2/favicons?domain=${l.hostname}&sz=32`
|
|
@@ -266,7 +269,7 @@ async function N(t) {
|
|
|
266
269
|
}
|
|
267
270
|
}
|
|
268
271
|
export {
|
|
269
|
-
|
|
270
|
-
|
|
272
|
+
F as loadNerdFonts,
|
|
273
|
+
I as useBeautyLink
|
|
271
274
|
};
|
|
272
275
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/utils/fileIcons.ts","../src/utils/loadNerdFonts.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 };","// Load Nerd Fonts dynamically for file type icons\nlet fontsLoaded = false;\n\nexport function loadNerdFonts() {\n // SSR check\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n // Only inject once\n if (fontsLoaded) {\n return;\n }\n\n const styleId = 'react-beauty-link-nerd-fonts';\n \n // Check if already injected\n if (document.getElementById(styleId)) {\n fontsLoaded = true;\n return;\n }\n\n try {\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n /* react-beauty-link: Nerd Font Symbols */\n @font-face {\n font-family: 'Symbols Nerd Font';\n src: url('https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@v3.1.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFont-Regular.ttf') format('truetype');\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n }\n\n @font-face {\n font-family: 'Symbols Nerd Font Mono';\n src: url('https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@v3.1.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFontMono-Regular.ttf') format('truetype');\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n }\n `;\n\n document.head.appendChild(style);\n fontsLoaded = true;\n \n // Debug log (can be removed in production)\n if (typeof console !== 'undefined' && console.debug) {\n console.debug('[react-beauty-link] Nerd Fonts loaded successfully');\n }\n } catch (error) {\n console.error('[react-beauty-link] Failed to load Nerd Fonts:', error);\n }\n}\n","import { useState, useEffect } from 'react';\nimport type { ReactNode } from 'react';\nimport { FILE_TYPE_ICONS } from '../utils/fileIcons';\nimport { loadNerdFonts } from '../utils/loadNerdFonts';\n\n// Load fonts immediately when module is imported (browser only, one-time)\nif (typeof window !== 'undefined') {\n loadNerdFonts();\n}\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 * @param customColor - Custom color for links (optional)\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","fontsLoaded","loadNerdFonts","styleId","style","error","getFileExtension","url","pathname","lastDot","useBeautyLink","text","target","customColor","urlRegex","linkMetadata","setLinkMetadata","useState","urls","match","useEffect","extension","filename","prev","metadata","fetchLinkMetadata","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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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/utils/fileIcons.ts","../src/utils/loadNerdFonts.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 };","// Load Nerd Fonts dynamically for file type icons\nlet fontsLoaded = false;\n\nexport function loadNerdFonts() {\n // SSR check\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n // Only inject once\n if (fontsLoaded) {\n return;\n }\n\n const styleId = 'react-beauty-link-nerd-fonts';\n \n // Check if already injected\n if (document.getElementById(styleId)) {\n fontsLoaded = true;\n return;\n }\n\n try {\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n /* react-beauty-link: Nerd Font Symbols */\n @font-face {\n font-family: 'Symbols Nerd Font';\n src: url('https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@v3.1.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFont-Regular.ttf') format('truetype');\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n }\n\n @font-face {\n font-family: 'Symbols Nerd Font Mono';\n src: url('https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@v3.1.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFontMono-Regular.ttf') format('truetype');\n font-weight: normal;\n font-style: normal;\n font-display: swap;\n }\n `;\n\n document.head.appendChild(style);\n fontsLoaded = true;\n \n // Debug log (can be removed in production)\n if (typeof console !== 'undefined' && console.debug) {\n console.debug('[react-beauty-link] Nerd Fonts loaded successfully');\n }\n } catch (error) {\n console.error('[react-beauty-link] Failed to load Nerd Fonts:', error);\n }\n}\n","import { useState, useEffect } from 'react';\nimport type { ReactNode } from 'react';\nimport { FILE_TYPE_ICONS } from '../utils/fileIcons';\nimport { loadNerdFonts } from '../utils/loadNerdFonts';\n\n// Load fonts immediately when module is imported (browser only, one-time)\nif (typeof window !== 'undefined') {\n loadNerdFonts();\n}\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 * @param customColor - Custom color for links (optional)\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 const metadata = await fetchLinkMetadata(url);\n if (process.env.NODE_ENV === 'development') {\n console.debug('[react-beauty-link] Metadata fetched:', url);\n }\n setLinkMetadata(prev => ({\n ...prev,\n [url]: metadata\n }));\n } catch (error) {\n // Silently fall back to URL - this is expected behavior\n if (process.env.NODE_ENV === 'development') {\n console.debug('[react-beauty-link] Using URL fallback for:', url);\n }\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 `https://api.codetabs.com/v1/proxy?quest=${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(5000) // 5 second timeout (faster failover)\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 // Only log in development mode to reduce console noise\n if (process.env.NODE_ENV === 'development') {\n const errorName = err instanceof Error ? err.name : 'Unknown error';\n console.debug('[react-beauty-link] Proxy failed:', proxyUrl.split('?')[0], errorName);\n }\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 // Graceful fallback - use hostname and Google favicon service\n if (process.env.NODE_ENV === 'development') {\n console.debug('[react-beauty-link] Metadata fetch failed, using fallback');\n }\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","fontsLoaded","loadNerdFonts","styleId","style","error","getFileExtension","url","pathname","lastDot","useBeautyLink","text","target","customColor","urlRegex","linkMetadata","setLinkMetadata","useState","urls","match","useEffect","extension","filename","prev","metadata","fetchLinkMetadata","parts","lastIndex","startIndex","displayTitle","faviconUrl","fileIcon","getTargetAttributes","e","jsxs","jsx","urlObj","origin","proxies","html","success","proxyUrl","response","data","err","errorName","doc","title","favicon","faviconLink"],"mappings":"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"}
|
package/package.json
CHANGED