Skip to content

Commit f9f0c1d

Browse files
committed
Update docs style
1 parent 64a9b79 commit f9f0c1d

File tree

3 files changed

+120
-45
lines changed

3 files changed

+120
-45
lines changed

components/ExternLink.tsx

Lines changed: 91 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import React, { useEffect, useState } from 'react';
2-
import { IconChevronRight, Icon as TablerIcon } from '@tabler/icons-react';
2+
import { IconChevronRight, IconExternalLink } from '@tabler/icons-react';
3+
import cn from "clsx";
34

45
interface ExternLinkProps {
56
href: string;
67
icon?: React.ReactNode | React.ElementType; // Erlaubt sowohl React-Komponenten als auch Strings
7-
manualTitle?: string; // Neuer Prop für manuellen Titel
8+
manualTitle?: string; // Eigenschaft für manuellen Titel
9+
manualDescript?: string; // Eigenschaft für manuelle Beschreibung
10+
children?: React.ReactNode; // Kinder-Elemente unterstützen
811
}
912

1013
interface LinkMetaData {
@@ -13,103 +16,148 @@ interface LinkMetaData {
1316
icon: string;
1417
}
1518

19+
// Stile im Stil der Nextra Cards
20+
const classes = {
21+
card: cn(
22+
"nx-group nx-flex nx-overflow-hidden nx-rounded-lg nx-border nx-border-gray-200",
23+
"nx-text-current nx-no-underline dark:nx-shadow-none",
24+
"hover:nx-shadow-gray-100 dark:hover:nx-shadow-none nx-shadow-gray-100",
25+
"active:nx-shadow-sm active:nx-shadow-gray-200",
26+
"nx-transition-all nx-duration-200 hover:nx-border-gray-300",
27+
"nx-bg-transparent nx-shadow-sm dark:nx-border-neutral-800 hover:nx-bg-slate-50 hover:nx-shadow-md dark:hover:nx-border-neutral-700 dark:hover:nx-bg-neutral-900",
28+
"my-4"
29+
),
30+
title: cn(
31+
"nx-font-semibold nx-text-gray-700 hover:nx-text-gray-900",
32+
"dark:nx-text-neutral-200 dark:hover:nx-text-neutral-50"
33+
),
34+
description: cn(
35+
"nx-text-sm nx-text-gray-500 dark:nx-text-gray-400"
36+
)
37+
};
38+
1639
const fetchMetaData = async (url: string): Promise<LinkMetaData> => {
1740
try {
1841
const response = await fetch(url);
1942
if (!response.ok) {
20-
throw new Error('Network response was not ok');
43+
throw new Error('Netzwerkantwort war nicht ok');
2144
}
22-
const text = await response.text(); // Hole den HTML-Inhalt
45+
const text = await response.text(); // HTML-Inhalt abrufen
2346
const parser = new DOMParser();
2447
const doc = parser.parseFromString(text, 'text/html');
2548

2649
const title = doc.querySelector('meta[property="og:title"]')?.getAttribute('content') ||
2750
doc.querySelector('title')?.textContent ||
28-
'No title';
51+
'Kein Titel';
2952
const description = doc.querySelector('meta[property="og:description"]')?.getAttribute('content') ||
3053
doc.querySelector('meta[name="description"]')?.getAttribute('content') ||
31-
'No description';
54+
'Keine Beschreibung';
3255
const icon = doc.querySelector('link[rel="icon"]')?.getAttribute('href') ||
3356
doc.querySelector('link[rel="shortcut icon"]')?.getAttribute('href') ||
3457
'https://example.com/default-icon.png';
3558

3659
return { title, description, icon: new URL(icon, url).href };
3760
} catch (error) {
38-
console.error('Error fetching metadata:', error);
61+
console.error('Fehler beim Abrufen der Metadaten:', error);
3962
return {
40-
title: 'Error',
41-
description: 'Unable to fetch metadata.',
63+
title: 'Fehler',
64+
description: 'Metadaten konnten nicht abgerufen werden.',
4265
icon: 'https://example.com/error-icon.png',
4366
};
4467
}
4568
};
4669

47-
const ExternLink: React.FC<ExternLinkProps> = ({ href, icon, manualTitle }) => {
70+
const ExternLink: React.FC<ExternLinkProps> = ({ href, icon, manualTitle, manualDescript, children }) => {
4871
const [metaData, setMetaData] = useState<LinkMetaData | null>(null);
4972
const [loading, setLoading] = useState(true);
5073

5174
useEffect(() => {
52-
if (!manualTitle) {
75+
if (!manualTitle && !manualDescript) {
5376
fetchMetaData(href).then((data) => {
5477
setMetaData(data);
5578
setLoading(false);
5679
});
5780
} else {
5881
setMetaData({
59-
title: manualTitle,
60-
description: 'No description available',
61-
icon: 'https://example.com/web-icon.png', // Web-Icon für manuellen Titel
82+
title: manualTitle || 'Kein Titel verfügbar',
83+
description: manualDescript || 'Keine Beschreibung verfügbar',
84+
icon: 'https://example.com/web-icon.png', // Web-Icon für manuellen Titel/Beschreibung
6285
});
6386
setLoading(false);
6487
}
65-
}, [href, manualTitle]);
66-
67-
if (loading) {
68-
return <div>Loading...</div>; // Display a loading state while fetching metadata
69-
}
88+
}, [href, manualTitle, manualDescript]);
7089

71-
// Funktion zur Kürzung der Beschreibung
90+
// Funktion zum Kürzen der Beschreibung
7291
const truncateDescription = (description: string, maxLength: number) => {
7392
if (description.length <= maxLength) {
7493
return description;
7594
}
7695
return description.substring(0, maxLength) + '...'; // Kürzen und '...' hinzufügen
7796
};
7897

98+
// Wenn Kinder-Elemente vorhanden sind, diese anstelle des automatisch generierten Inhalts anzeigen
99+
if (children) {
100+
return (
101+
<a
102+
href={href}
103+
className="nx-flex nx-items-center nx-no-underline nx-text-current nx-transition-colors hover:nx-text-blue-600 dark:hover:nx-text-blue-400"
104+
target="_blank"
105+
rel="noopener noreferrer"
106+
>
107+
{children}
108+
<IconExternalLink className="nx-ml-1 nx-inline-block nx-h-4 nx-w-4" />
109+
</a>
110+
);
111+
}
112+
113+
if (loading) {
114+
return (
115+
<div className="nx-flex nx-items-center nx-justify-center nx-h-20 nx-bg-zinc-100 dark:nx-bg-zinc-800 nx-rounded-lg nx-animate-pulse">
116+
<span className="nx-text-zinc-500 dark:nx-text-zinc-400">Lädt...</span>
117+
</div>
118+
);
119+
}
120+
79121
return (
80122
<a
81123
href={href}
82-
className="w-full my-5 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"
124+
className={classes.card}
83125
target="_blank"
84126
rel="noopener noreferrer"
85127
>
86-
<div className="flex items-center p-4">
87-
{/* Icon */}
88-
{icon ? (
89-
typeof icon === 'string' ? (
90-
<img src={icon} alt="Favicon" className="w-6 h-6 mr-3" />
91-
) : (
92-
React.isValidElement(icon) ? (
93-
React.cloneElement(icon as React.ReactElement, { className: 'w-6 h-6 mr-3' })
128+
<div className="nx-flex nx-items-center nx-w-full nx-p-4 nx-relative">
129+
{/* Icon - mit größerem Abstand zum Text */}
130+
<div className="nx-flex-shrink-0 nx-mr-12">
131+
{icon ? (
132+
typeof icon === 'string' ? (
133+
<img src={icon} alt="Favicon" className="w-6 h-6 mr-3" />
94134
) : (
95-
React.createElement(icon as React.ElementType, { className: 'w-6 h-6 mr-3' })
135+
React.isValidElement(icon) ? (
136+
React.cloneElement(icon as React.ReactElement, { className: 'w-6 h-6 mr-3' })
137+
) : (
138+
React.createElement(icon as React.ElementType, { className: 'w-6 h-6 mr-3' })
139+
)
96140
)
97-
)
98-
) : (
99-
<img src={metaData?.icon} alt="Favicon" className="w-6 h-6 mr-3" />
100-
)}
101-
{/* Title */}
102-
<div className="flex flex-col">
103-
<span className="font-semibold text-lg text-gray-700 dark:text-gray-100">
141+
) : (
142+
<img src={metaData?.icon} alt="Favicon" className="w-6 h-6 mr-3" />
143+
)}
144+
</div>
145+
146+
{/* Inhalt - mit weniger Padding rechts, da der Pfeil absolut positioniert ist */}
147+
<div className="nx-flex-grow px-4">
148+
<span className={classes.title}>
104149
{metaData?.title}
105150
</span>
106-
<span className="text-sm text-gray-500 dark:text-gray-300">
107-
{metaData?.description && truncateDescription(metaData.description, 100)} {/* Hier wird die Beschreibung gekürzt */}
108-
</span>
151+
<div className="nx-mt-1">
152+
<span className={classes.description}>
153+
{metaData?.description && truncateDescription(metaData.description, 120)}
154+
</span>
155+
</div>
109156
</div>
110-
{/* Arrow Icon */}
111-
<span className="absolute right-4 top-1/2 transform -translate-y-1/2 text-gray-600 dark:text-gray-300">
112-
<IconChevronRight />
157+
158+
{/* Pfeil-Icon - korrekt rechts ausgerichtet mit absoluter Positionierung */}
159+
<span className="absolute right-4 content-end nx-top-1/2 nx-transform nx--translate-y-1/2">
160+
<IconChevronRight className="nx-transition-transform nx-duration-75 group-hover:nx-translate-x-[2px]" />
113161
</span>
114162
</div>
115163
</a>

style.css

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,33 @@ body,
99
height: 100%;
1010
}
1111

12+
body {
13+
position: relative;
14+
background-color: var(--background-color, #ffffff);
15+
}
16+
17+
body::before {
18+
content: '';
19+
position: fixed;
20+
top: 0;
21+
left: 0;
22+
width: 100%;
23+
height: 100%;
24+
z-index: -1;
25+
background-image: radial-gradient(circle, rgba(0, 0, 0, 0.1) 1px, transparent 1px),
26+
radial-gradient(circle, rgba(0, 0, 0, 0.05) 1px, transparent 1px),
27+
radial-gradient(circle, rgba(0, 0, 0, 0.025) 1px, transparent 1px);
28+
background-size: 30px,30px 30px;
29+
background-position: 0 0, 25px 25px, 45px 45px;
30+
pointer-events: none;
31+
}
32+
33+
.dark body::before {
34+
background-image: radial-gradient(circle, rgba(255, 255, 255, 0.15) 1px, transparent 1px),
35+
radial-gradient(circle, rgba(255, 255, 255, 0.1) 1px, transparent 1px),
36+
radial-gradient(circle, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
37+
}
38+
1239
a {
1340
text-decoration: none !important;
1441
}

theme.config.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ function useHead() {
2121
<meta property="og:url" content={url} />
2222
<meta property="og:title" content={title} />
2323
<meta property="og:description" content={description} />
24-
<meta property="og:image" content="https://i.imgur.com/OenvzZz.png" />
24+
<meta property="og:image" content="https://i.imgur.com/vUk4Vif.png" />
2525

2626
<meta property="twitter:card" content="summary_large_image" />
2727
<meta property="twitter:url" content={url} />
2828
<meta property="twitter:title" content={title} />
2929
<meta property="twitter:description" content={description} />
30-
<meta property="twitter:image" content="https://i.imgur.com/OenvzZz.png" />
30+
<meta property="twitter:image" content="https://i.imgur.com/vUk4Vif.png" />
3131
</>
3232
);
3333
}

0 commit comments

Comments
 (0)