Rich Text implementirert
This commit is contained in:
parent
e5c238f88c
commit
5e66f4bdda
@ -12,6 +12,11 @@
|
||||
],
|
||||
"rootMainFiles": [],
|
||||
"pages": {
|
||||
"/": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/index.js"
|
||||
],
|
||||
"/_app": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
@ -22,20 +27,15 @@
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/_error.js"
|
||||
],
|
||||
"/admin": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/admin.js"
|
||||
],
|
||||
"/admin/login": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/admin/login.js"
|
||||
],
|
||||
"/blog/[slug]": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/blog/[slug].js"
|
||||
],
|
||||
"/devlog": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/devlog.js"
|
||||
]
|
||||
},
|
||||
"ampFirstPages": []
|
||||
|
||||
BIN
.next/cache/webpack/client-development/1.pack.gz
vendored
BIN
.next/cache/webpack/client-development/1.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/10.pack.gz
vendored
BIN
.next/cache/webpack/client-development/10.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/12.pack.gz
vendored
BIN
.next/cache/webpack/client-development/12.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/13.pack.gz
vendored
BIN
.next/cache/webpack/client-development/13.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/14.pack.gz
vendored
BIN
.next/cache/webpack/client-development/14.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/2.pack.gz
vendored
BIN
.next/cache/webpack/client-development/2.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/6.pack.gz
vendored
BIN
.next/cache/webpack/client-development/6.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/8.pack.gz
vendored
BIN
.next/cache/webpack/client-development/8.pack.gz
vendored
Binary file not shown.
Binary file not shown.
BIN
.next/cache/webpack/server-development/1.pack.gz
vendored
BIN
.next/cache/webpack/server-development/1.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/11.pack.gz
vendored
BIN
.next/cache/webpack/server-development/11.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/12.pack.gz
vendored
BIN
.next/cache/webpack/server-development/12.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/13.pack.gz
vendored
BIN
.next/cache/webpack/server-development/13.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/14.pack.gz
vendored
BIN
.next/cache/webpack/server-development/14.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/15.pack.gz
vendored
BIN
.next/cache/webpack/server-development/15.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/16.pack.gz
vendored
BIN
.next/cache/webpack/server-development/16.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/3.pack.gz
vendored
BIN
.next/cache/webpack/server-development/3.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/4.pack.gz
vendored
BIN
.next/cache/webpack/server-development/4.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/6.pack.gz
vendored
BIN
.next/cache/webpack/server-development/6.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/7.pack.gz
vendored
BIN
.next/cache/webpack/server-development/7.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/index.pack.gz
vendored
BIN
.next/cache/webpack/server-development/index.pack.gz
vendored
Binary file not shown.
Binary file not shown.
@ -1,18 +1 @@
|
||||
{
|
||||
"..\\node_modules\\@supabase\\auth-js\\dist\\module\\lib\\helpers.js -> @supabase/node-fetch": {
|
||||
"id": "..\\node_modules\\@supabase\\auth-js\\dist\\module\\lib\\helpers.js -> @supabase/node-fetch",
|
||||
"files": []
|
||||
},
|
||||
"..\\node_modules\\@supabase\\functions-js\\dist\\module\\helper.js -> @supabase/node-fetch": {
|
||||
"id": "..\\node_modules\\@supabase\\functions-js\\dist\\module\\helper.js -> @supabase/node-fetch",
|
||||
"files": []
|
||||
},
|
||||
"..\\node_modules\\@supabase\\realtime-js\\dist\\module\\RealtimeClient.js -> @supabase/node-fetch": {
|
||||
"id": "..\\node_modules\\@supabase\\realtime-js\\dist\\module\\RealtimeClient.js -> @supabase/node-fetch",
|
||||
"files": []
|
||||
},
|
||||
"..\\node_modules\\@supabase\\storage-js\\dist\\module\\lib\\helpers.js -> @supabase/node-fetch": {
|
||||
"id": "..\\node_modules\\@supabase\\storage-js\\dist\\module\\lib\\helpers.js -> @supabase/node-fetch",
|
||||
"files": []
|
||||
}
|
||||
}
|
||||
{}
|
||||
@ -1 +1 @@
|
||||
self.__BUILD_MANIFEST={"polyfillFiles":["static/chunks/polyfills.js"],"devFiles":["static/chunks/react-refresh.js"],"ampDevFiles":[],"lowPriorityFiles":["static/development/_buildManifest.js","static/development/_ssgManifest.js"],"rootMainFiles":[],"pages":{"/_app":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/_app.js"],"/_error":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/_error.js"],"/admin":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/admin.js"],"/admin/login":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/admin/login.js"],"/blog/[slug]":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/blog/[slug].js"]},"ampFirstPages":[]}
|
||||
self.__BUILD_MANIFEST={"polyfillFiles":["static/chunks/polyfills.js"],"devFiles":["static/chunks/react-refresh.js"],"ampDevFiles":[],"lowPriorityFiles":["static/development/_buildManifest.js","static/development/_ssgManifest.js"],"rootMainFiles":[],"pages":{"/":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/index.js"],"/_app":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/_app.js"],"/_error":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/_error.js"],"/blog/[slug]":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/blog/[slug].js"],"/devlog":["static/chunks/webpack.js","static/chunks/main.js","static/chunks/pages/devlog.js"]},"ampFirstPages":[]}
|
||||
@ -5,6 +5,7 @@
|
||||
"middleware": {
|
||||
"/": {
|
||||
"files": [
|
||||
"prerender-manifest.js",
|
||||
"server/edge-runtime-webpack.js",
|
||||
"server/middleware.js"
|
||||
],
|
||||
@ -12,8 +13,8 @@
|
||||
"page": "/",
|
||||
"matchers": [
|
||||
{
|
||||
"regexp": "^/.*$",
|
||||
"originalSource": "/:path*"
|
||||
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/admin(?:\\/((?:[^\\/#\\?]+?)(?:\\/(?:[^\\/#\\?]+?))*))?(.json)?[\\/#\\?]?$",
|
||||
"originalSource": "/admin/:path*"
|
||||
}
|
||||
],
|
||||
"wasm": [],
|
||||
|
||||
@ -1 +1 @@
|
||||
self.__REACT_LOADABLE_MANIFEST="{\"..\\\\node_modules\\\\@supabase\\\\auth-js\\\\dist\\\\module\\\\lib\\\\helpers.js -> @supabase/node-fetch\":{\"id\":\"..\\\\node_modules\\\\@supabase\\\\auth-js\\\\dist\\\\module\\\\lib\\\\helpers.js -> @supabase/node-fetch\",\"files\":[]},\"..\\\\node_modules\\\\@supabase\\\\functions-js\\\\dist\\\\module\\\\helper.js -> @supabase/node-fetch\":{\"id\":\"..\\\\node_modules\\\\@supabase\\\\functions-js\\\\dist\\\\module\\\\helper.js -> @supabase/node-fetch\",\"files\":[]},\"..\\\\node_modules\\\\@supabase\\\\realtime-js\\\\dist\\\\module\\\\RealtimeClient.js -> @supabase/node-fetch\":{\"id\":\"..\\\\node_modules\\\\@supabase\\\\realtime-js\\\\dist\\\\module\\\\RealtimeClient.js -> @supabase/node-fetch\",\"files\":[]},\"..\\\\node_modules\\\\@supabase\\\\storage-js\\\\dist\\\\module\\\\lib\\\\helpers.js -> @supabase/node-fetch\":{\"id\":\"..\\\\node_modules\\\\@supabase\\\\storage-js\\\\dist\\\\module\\\\lib\\\\helpers.js -> @supabase/node-fetch\",\"files\":[]}}"
|
||||
self.__REACT_LOADABLE_MANIFEST="{}"
|
||||
@ -2,8 +2,8 @@
|
||||
"/_app": "pages/_app.js",
|
||||
"/_error": "pages/_error.js",
|
||||
"/_document": "pages/_document.js",
|
||||
"/admin": "pages/admin.js",
|
||||
"/devlog": "pages/devlog.js",
|
||||
"/blog/[slug]": "pages/blog/[slug].js",
|
||||
"/admin/login": "pages/admin/login.js",
|
||||
"/blog/[slug]": "pages/blog/[slug].js"
|
||||
"/devlog": "pages/devlog.js",
|
||||
"/": "pages/index.js"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
self.__BUILD_MANIFEST = {__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/_error":["static\u002Fchunks\u002Fpages\u002F_error.js"],"/admin":["static\u002Fchunks\u002Fpages\u002Fadmin.js"],"/admin/login":["static\u002Fchunks\u002Fpages\u002Fadmin\u002Flogin.js"],"/blog/[slug]":["static\u002Fchunks\u002Fpages\u002Fblog\u002F[slug].js"],sortedPages:["\u002F_app","\u002F_error","\u002Fadmin","\u002Fadmin\u002Flogin","\u002Fblog\u002F[slug]"]};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()
|
||||
self.__BUILD_MANIFEST = {__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":["static\u002Fchunks\u002Fpages\u002Findex.js"],"/_error":["static\u002Fchunks\u002Fpages\u002F_error.js"],"/blog/[slug]":["static\u002Fchunks\u002Fpages\u002Fblog\u002F[slug].js"],"/devlog":["static\u002Fchunks\u002Fpages\u002Fdevlog.js"],sortedPages:["\u002F","\u002F_app","\u002F_error","\u002Fblog\u002F[slug]","\u002Fdevlog"]};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()
|
||||
98
.next/trace
98
.next/trace
File diff suppressed because one or more lines are too long
1502
package-lock.json
generated
1502
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,7 +18,9 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-leaflet": "^4.2.1"
|
||||
"react-leaflet": "^4.2.1",
|
||||
"react-markdown": "^10.1.0",
|
||||
"remark-gfm": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.15.30",
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { supabase } from '../../lib/supabase';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
|
||||
export default function AdminPanel() {
|
||||
const [entries, setEntries] = useState([]);
|
||||
@ -103,6 +105,8 @@ export default function AdminPanel() {
|
||||
const EntryForm = ({ entry, onSave }) => {
|
||||
const [formData, setFormData] = useState(entry);
|
||||
const [contentList, setContentList] = useState(entry.content || []);
|
||||
const [showPreview, setShowPreview] = useState(false);
|
||||
const [activeContentIndex, setActiveContentIndex] = useState(null);
|
||||
|
||||
const handleContentAdd = (type) => {
|
||||
setContentList([...contentList, { type, value: '' }]);
|
||||
@ -123,6 +127,94 @@ export default function AdminPanel() {
|
||||
});
|
||||
};
|
||||
|
||||
const insertMarkdown = (index, markdownSyntax) => {
|
||||
const textarea = document.getElementById(`content-${index}`);
|
||||
if (textarea) {
|
||||
const start = textarea.selectionStart;
|
||||
const end = textarea.selectionEnd;
|
||||
const selectedText = textarea.value.substring(start, end);
|
||||
const beforeText = textarea.value.substring(0, start);
|
||||
const afterText = textarea.value.substring(end);
|
||||
|
||||
let newText;
|
||||
if (markdownSyntax.includes('{}')) {
|
||||
newText = beforeText + markdownSyntax.replace('{}', selectedText || 'Text hier') + afterText;
|
||||
} else {
|
||||
newText = beforeText + markdownSyntax + afterText;
|
||||
}
|
||||
|
||||
handleContentChange(index, newText);
|
||||
|
||||
// Focus back to textarea
|
||||
setTimeout(() => {
|
||||
textarea.focus();
|
||||
const newCursorPos = start + markdownSyntax.length;
|
||||
textarea.setSelectionRange(newCursorPos, newCursorPos);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const MarkdownToolbar = ({ contentIndex }) => (
|
||||
<div className="flex flex-wrap gap-2 mb-2 p-2 bg-gray-100 rounded">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => insertMarkdown(contentIndex, '**{}**')}
|
||||
className="px-2 py-1 text-xs bg-white border rounded hover:bg-gray-50"
|
||||
title="Fett"
|
||||
>
|
||||
<strong>B</strong>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => insertMarkdown(contentIndex, '*{}*')}
|
||||
className="px-2 py-1 text-xs bg-white border rounded hover:bg-gray-50"
|
||||
title="Kursiv"
|
||||
>
|
||||
<em>I</em>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => insertMarkdown(contentIndex, '# {}')}
|
||||
className="px-2 py-1 text-xs bg-white border rounded hover:bg-gray-50"
|
||||
title="Überschrift 1"
|
||||
>
|
||||
H1
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => insertMarkdown(contentIndex, '## {}')}
|
||||
className="px-2 py-1 text-xs bg-white border rounded hover:bg-gray-50"
|
||||
title="Überschrift 2"
|
||||
>
|
||||
H2
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => insertMarkdown(contentIndex, '### {}')}
|
||||
className="px-2 py-1 text-xs bg-white border rounded hover:bg-gray-50"
|
||||
title="Überschrift 3"
|
||||
>
|
||||
H3
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => insertMarkdown(contentIndex, '- {}')}
|
||||
className="px-2 py-1 text-xs bg-white border rounded hover:bg-gray-50"
|
||||
title="Liste"
|
||||
>
|
||||
•
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => insertMarkdown(contentIndex, '[{}](URL)')}
|
||||
className="px-2 py-1 text-xs bg-white border rounded hover:bg-gray-50"
|
||||
title="Link"
|
||||
>
|
||||
🔗
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="space-y-4 bg-white p-6 rounded-lg shadow">
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
@ -156,21 +248,81 @@ export default function AdminPanel() {
|
||||
/>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h3 className="font-bold">Inhalt</h3>
|
||||
<div className="flex justify-between items-center">
|
||||
<h3 className="font-bold">Inhalt</h3>
|
||||
<div className="text-sm text-gray-600 mb-4 p-3 bg-gray-50 rounded border">
|
||||
<strong className="block mb-2">📝 Markdown-Formatierung:</strong>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-xs">
|
||||
<div><code>**fett**</code> → <strong>fett</strong></div>
|
||||
<div><code>*kursiv*</code> → <em>kursiv</em></div>
|
||||
<div><code># Überschrift</code> → <span className="font-bold text-lg">Überschrift</span></div>
|
||||
<div><code>## Unterüberschrift</code> → <span className="font-bold">Unterüberschrift</span></div>
|
||||
<div><code>[Link](URL)</code> → <span className="text-pb-turquoise underline">Link</span></div>
|
||||
<div><code>- Listenpunkt</code> → • Listenpunkt</div>
|
||||
<div><code>1. Nummeriert</code> → 1. Nummeriert</div>
|
||||
<div><code>`Code`</code> → <code className="bg-gray-200 px-1 rounded">Code</code></div>
|
||||
<div><code>> Zitat</code> → <span className="italic border-l-2 border-pb-turquoise pl-2">Zitat</span></div>
|
||||
<div><code>---</code> → Trennlinie</div>
|
||||
</div>
|
||||
<div className="mt-2 pt-2 border-t border-gray-200">
|
||||
<strong className="text-xs">💡 Tipp:</strong> <span className="text-xs">Nutze die Buttons oben oder schreibe Markdown direkt. Die Vorschau zeigt das Ergebnis.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{contentList.map((content, index) => (
|
||||
<div key={index} className="flex space-x-2">
|
||||
<textarea
|
||||
value={content.value}
|
||||
onChange={(e) => handleContentChange(index, e.target.value)}
|
||||
className="w-full p-2 border rounded"
|
||||
rows="3"
|
||||
/>
|
||||
<button
|
||||
onClick={() => handleContentRemove(index)}
|
||||
className="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<div key={index} className="border rounded-lg p-4 space-y-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-sm font-medium text-gray-700">
|
||||
{content.type === 'text' ? '📝 Text-Inhalt' : '🖼️ Bild-Inhalt'}
|
||||
</span>
|
||||
<div className="flex space-x-2">
|
||||
{content.type === 'text' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveContentIndex(activeContentIndex === index ? null : index)}
|
||||
className={`px-3 py-1 text-xs rounded ${
|
||||
activeContentIndex === index
|
||||
? 'bg-blue-500 text-white'
|
||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||
}`}
|
||||
>
|
||||
{activeContentIndex === index ? 'Vorschau ausblenden' : 'Vorschau anzeigen'}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => handleContentRemove(index)}
|
||||
className="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600 text-xs"
|
||||
>
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{content.type === 'text' && <MarkdownToolbar contentIndex={index} />}
|
||||
|
||||
<div className={activeContentIndex === index ? 'grid grid-cols-2 gap-4' : ''}>
|
||||
<div>
|
||||
<textarea
|
||||
id={`content-${index}`}
|
||||
value={content.value}
|
||||
onChange={(e) => handleContentChange(index, e.target.value)}
|
||||
className="w-full p-3 border rounded-lg font-mono text-sm"
|
||||
rows={content.type === 'text' ? "8" : "3"}
|
||||
placeholder={content.type === 'text' ? 'Hier können Sie **Markdown** verwenden...' : 'Bild-URL eingeben...'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{content.type === 'text' && activeContentIndex === index && (
|
||||
<div className="border rounded-lg p-3 bg-gray-50">
|
||||
<div className="text-xs font-medium text-gray-600 mb-2">Vorschau:</div>
|
||||
<div className="prose prose-sm max-w-none">
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>
|
||||
{content.value || '*Keine Inhalte zum Anzeigen*'}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="flex space-x-2">
|
||||
|
||||
@ -2,6 +2,8 @@ import { motion } from 'framer-motion';
|
||||
import devlogData from '../../data/devlog.json';
|
||||
import Image from 'next/image';
|
||||
import { supabase } from '../../lib/supabase';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
|
||||
export default function BlogPost({ blog }) {
|
||||
|
||||
@ -41,20 +43,60 @@ export default function BlogPost({ blog }) {
|
||||
// Handle both old format (type/value) and new format (direct content)
|
||||
if (typeof item === 'string') {
|
||||
return (
|
||||
<p key={index} className="text-gray-600 text-lg">
|
||||
{item}
|
||||
</p>
|
||||
<div key={index} className="prose prose-lg max-w-none">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
className="text-gray-700 text-base sm:text-lg leading-relaxed px-2 sm:px-0"
|
||||
components={{
|
||||
h1: ({children}) => <h1 className="text-3xl font-bold mb-4 text-gray-900">{children}</h1>,
|
||||
h2: ({children}) => <h2 className="text-2xl font-bold mb-3 text-gray-900">{children}</h2>,
|
||||
h3: ({children}) => <h3 className="text-xl font-bold mb-2 text-gray-900">{children}</h3>,
|
||||
p: ({children}) => <p className="mb-4 sm:mb-6">{children}</p>,
|
||||
strong: ({children}) => <strong className="font-bold text-gray-900">{children}</strong>,
|
||||
em: ({children}) => <em className="italic">{children}</em>,
|
||||
ul: ({children}) => <ul className="list-disc list-inside mb-4 space-y-2">{children}</ul>,
|
||||
ol: ({children}) => <ol className="list-decimal list-inside mb-4 space-y-2">{children}</ol>,
|
||||
li: ({children}) => <li className="ml-4">{children}</li>,
|
||||
a: ({href, children}) => <a href={href} className="text-pb-turquoise hover:underline">{children}</a>,
|
||||
blockquote: ({children}) => <blockquote className="border-l-4 border-pb-turquoise pl-4 italic my-4">{children}</blockquote>,
|
||||
code: ({children}) => <code className="bg-gray-100 px-2 py-1 rounded text-sm font-mono">{children}</code>,
|
||||
pre: ({children}) => <pre className="bg-gray-100 p-4 rounded overflow-x-auto mb-4">{children}</pre>
|
||||
}}
|
||||
>
|
||||
{item}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return item.type === 'text' ? (
|
||||
<p key={index} className="text-gray-600 text-lg">
|
||||
{item.value}
|
||||
</p>
|
||||
<div key={index} className="prose prose-lg max-w-none">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
className="text-gray-700 text-base sm:text-lg leading-relaxed px-2 sm:px-0"
|
||||
components={{
|
||||
h1: ({children}) => <h1 className="text-3xl font-bold mb-4 text-gray-900">{children}</h1>,
|
||||
h2: ({children}) => <h2 className="text-2xl font-bold mb-3 text-gray-900">{children}</h2>,
|
||||
h3: ({children}) => <h3 className="text-xl font-bold mb-2 text-gray-900">{children}</h3>,
|
||||
p: ({children}) => <p className="mb-4 sm:mb-6">{children}</p>,
|
||||
strong: ({children}) => <strong className="font-bold text-gray-900">{children}</strong>,
|
||||
em: ({children}) => <em className="italic">{children}</em>,
|
||||
ul: ({children}) => <ul className="list-disc list-inside mb-4 space-y-2">{children}</ul>,
|
||||
ol: ({children}) => <ol className="list-decimal list-inside mb-4 space-y-2">{children}</ol>,
|
||||
li: ({children}) => <li className="ml-4">{children}</li>,
|
||||
a: ({href, children}) => <a href={href} className="text-pb-turquoise hover:underline">{children}</a>,
|
||||
blockquote: ({children}) => <blockquote className="border-l-4 border-pb-turquoise pl-4 italic my-4">{children}</blockquote>,
|
||||
code: ({children}) => <code className="bg-gray-100 px-2 py-1 rounded text-sm font-mono">{children}</code>,
|
||||
pre: ({children}) => <pre className="bg-gray-100 p-4 rounded overflow-x-auto mb-4">{children}</pre>
|
||||
}}
|
||||
>
|
||||
{item.value}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
key={index}
|
||||
className="relative w-full h-64 rounded-lg overflow-hidden"
|
||||
className="relative w-full h-64 rounded-lg overflow-hidden shadow-lg mb-8"
|
||||
>
|
||||
{/* Only render image if src is valid */}
|
||||
{item.value && (item.value.startsWith('/') || item.value.startsWith('http')) && (
|
||||
@ -72,9 +114,29 @@ export default function BlogPost({ blog }) {
|
||||
|
||||
{/* If no structured content, show description */}
|
||||
{(!blog.content || blog.content.length === 0) && blog.description && (
|
||||
<p className="text-gray-600 text-lg">
|
||||
{blog.description}
|
||||
</p>
|
||||
<div className="prose prose-lg max-w-none">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
className="text-gray-700 text-base sm:text-lg leading-relaxed px-2 sm:px-0"
|
||||
components={{
|
||||
h1: ({children}) => <h1 className="text-3xl font-bold mb-4 text-gray-900">{children}</h1>,
|
||||
h2: ({children}) => <h2 className="text-2xl font-bold mb-3 text-gray-900">{children}</h2>,
|
||||
h3: ({children}) => <h3 className="text-xl font-bold mb-2 text-gray-900">{children}</h3>,
|
||||
p: ({children}) => <p className="mb-4 sm:mb-6">{children}</p>,
|
||||
strong: ({children}) => <strong className="font-bold text-gray-900">{children}</strong>,
|
||||
em: ({children}) => <em className="italic">{children}</em>,
|
||||
ul: ({children}) => <ul className="list-disc list-inside mb-4 space-y-2">{children}</ul>,
|
||||
ol: ({children}) => <ol className="list-decimal list-inside mb-4 space-y-2">{children}</ol>,
|
||||
li: ({children}) => <li className="ml-4">{children}</li>,
|
||||
a: ({href, children}) => <a href={href} className="text-pb-turquoise hover:underline">{children}</a>,
|
||||
blockquote: ({children}) => <blockquote className="border-l-4 border-pb-turquoise pl-4 italic my-4">{children}</blockquote>,
|
||||
code: ({children}) => <code className="bg-gray-100 px-2 py-1 rounded text-sm font-mono">{children}</code>,
|
||||
pre: ({children}) => <pre className="bg-gray-100 p-4 rounded overflow-x-auto mb-4">{children}</pre>
|
||||
}}
|
||||
>
|
||||
{blog.description}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user