1
1
import React , { useEffect , useState } from 'react' ;
2
- import { IconWebhook , IconChevronRight , Icon } from '@tabler/icons-react'
2
+ import { IconChevronRight , Icon as TablerIcon } from '@tabler/icons-react'
3
3
4
4
interface ExternLinkProps {
5
5
href : string ;
6
- icon ?: React . ReactNode | React . ElementType ;
6
+ icon ?: React . ReactNode | React . ElementType ; // Erlaubt sowohl React-Komponenten als auch Strings
7
7
manualTitle ?: string ; // Neuer Prop für manuellen Titel
8
8
}
9
9
@@ -14,64 +14,64 @@ interface LinkMetaData {
14
14
}
15
15
16
16
const fetchMetaData = async ( url : string ) : Promise < LinkMetaData > => {
17
- try {
18
- const response = await fetch ( url ) ;
19
- if ( ! response . ok ) {
20
- throw new Error ( 'Network response was not ok' ) ;
21
- }
22
- const text = await response . text ( ) ; // Hole den HTML-Inhalt
23
- const parser = new DOMParser ( ) ;
24
- const doc = parser . parseFromString ( text , 'text/html' ) ;
25
-
26
- const title = doc . querySelector ( 'meta[property="og:title"]' ) ?. getAttribute ( 'content' ) ||
27
- doc . querySelector ( 'title' ) ?. textContent ||
28
- 'No title' ;
29
- const description = doc . querySelector ( 'meta[property="og:description"]' ) ?. getAttribute ( 'content' ) ||
30
- doc . querySelector ( 'meta[name="description"]' ) ?. getAttribute ( 'content' ) ||
31
- 'No description' ;
32
- const icon = doc . querySelector ( 'link[rel="icon"]' ) ?. getAttribute ( 'href' ) ||
33
- doc . querySelector ( 'link[rel="shortcut icon"]' ) ?. getAttribute ( 'href' ) ||
34
- 'https://example.com/default-icon.png' ;
35
-
36
- return { title, description, icon : new URL ( icon , url ) . href } ;
37
- } catch ( error ) {
38
- console . error ( 'Error fetching metadata:' , error ) ;
39
- return {
40
- title : 'Error' ,
41
- description : 'Unable to fetch metadata.' ,
42
- icon : 'https://example.com/error-icon.png' ,
43
- } ;
17
+ try {
18
+ const response = await fetch ( url ) ;
19
+ if ( ! response . ok ) {
20
+ throw new Error ( 'Network response was not ok' ) ;
44
21
}
45
- } ;
46
-
47
- const ExternLink : React . FC < ExternLinkProps > = ( { href, icon, manualTitle } ) => {
48
- const [ metaData , setMetaData ] = useState < LinkMetaData | null > ( null ) ;
49
- const [ loading , setLoading ] = useState ( true ) ;
22
+ const text = await response . text ( ) ; // Hole den HTML-Inhalt
23
+ const parser = new DOMParser ( ) ;
24
+ const doc = parser . parseFromString ( text , 'text/html' ) ;
25
+
26
+ const title = doc . querySelector ( 'meta[property="og:title"]' ) ?. getAttribute ( 'content' ) ||
27
+ doc . querySelector ( 'title' ) ?. textContent ||
28
+ 'No title' ;
29
+ const description = doc . querySelector ( 'meta[property="og:description"]' ) ?. getAttribute ( 'content' ) ||
30
+ doc . querySelector ( 'meta[name="description"]' ) ?. getAttribute ( 'content' ) ||
31
+ 'No description' ;
32
+ const icon = doc . querySelector ( 'link[rel="icon"]' ) ?. getAttribute ( 'href' ) ||
33
+ doc . querySelector ( 'link[rel="shortcut icon"]' ) ?. getAttribute ( 'href' ) ||
34
+ 'https://example.com/default-icon.png' ;
35
+
36
+ return { title, description, icon : new URL ( icon , url ) . href } ;
37
+ } catch ( error ) {
38
+ console . error ( 'Error fetching metadata:' , error ) ;
39
+ return {
40
+ title : 'Error' ,
41
+ description : 'Unable to fetch metadata.' ,
42
+ icon : 'https://example.com/error-icon.png' ,
43
+ } ;
44
+ }
45
+ } ;
50
46
51
- useEffect ( ( ) => {
52
- if ( ! manualTitle ) {
53
- fetchMetaData ( href ) . then ( ( data ) => {
54
- setMetaData ( data ) ;
55
- setLoading ( false ) ;
56
- } ) ;
57
- } else {
58
- setMetaData ( {
59
- title : manualTitle ,
60
- description : 'No description available' ,
61
- icon : 'https://example.com/web-icon.png' , // Web-Icon für manuellen Titel
62
- } ) ;
47
+ const ExternLink : React . FC < ExternLinkProps > = ( { href, icon, manualTitle } ) => {
48
+ const [ metaData , setMetaData ] = useState < LinkMetaData | null > ( null ) ;
49
+ const [ loading , setLoading ] = useState ( true ) ;
50
+
51
+ useEffect ( ( ) => {
52
+ if ( ! manualTitle ) {
53
+ fetchMetaData ( href ) . then ( ( data ) => {
54
+ setMetaData ( data ) ;
63
55
setLoading ( false ) ;
64
- }
65
- } , [ href , manualTitle ] ) ;
66
-
67
- if ( loading ) {
68
- return < div > Loading...</ div > ; // Display a loading state while fetching metadata
56
+ } ) ;
57
+ } else {
58
+ setMetaData ( {
59
+ title : manualTitle ,
60
+ description : 'No description available' ,
61
+ icon : 'https://example.com/web-icon.png' , // Web-Icon für manuellen Titel
62
+ } ) ;
63
+ setLoading ( false ) ;
69
64
}
65
+ } , [ href , manualTitle ] ) ;
66
+
67
+ if ( loading ) {
68
+ return < div > Loading...</ div > ; // Display a loading state while fetching metadata
69
+ }
70
70
71
71
return (
72
72
< a
73
73
href = { href }
74
- className = "w-full border border-gray-200 shadow-sm hover:shadow-md dark:border-neutral-700 dark:hover:border-neutral-600 transition-all duration-200 dark:bg-neutral-900 bg-white rounded-lg overflow-hidden flex flex-col justify-start relative my-4 "
74
+ className = "w-full border border-gray-200 shadow-sm hover:shadow-md dark:border-neutral-700 dark:hover:border-neutral-600 transition-all duration-200 dark:bg-neutral-900 bg-white rounded-lg overflow-hidden flex flex-col justify-start relative"
75
75
target = "_blank"
76
76
rel = "noopener noreferrer"
77
77
>
@@ -81,7 +81,11 @@ const fetchMetaData = async (url: string): Promise<LinkMetaData> => {
81
81
typeof icon === 'string' ? (
82
82
< img src = { icon } alt = "Favicon" className = "w-6 h-6 mr-3" />
83
83
) : (
84
- React . createElement ( icon , { className : 'w-6 h-6 mr-3' } )
84
+ React . isValidElement ( icon ) ? (
85
+ React . cloneElement ( icon as React . ReactElement , { className : 'w-6 h-6 mr-3' } )
86
+ ) : (
87
+ React . createElement ( icon as React . ElementType , { className : 'w-6 h-6 mr-3' } )
88
+ )
85
89
)
86
90
) : (
87
91
< img src = { metaData ?. icon } alt = "Favicon" className = "w-6 h-6 mr-3" />
0 commit comments