💂♂️ fixed lint and prittier
This commit is contained in:
@@ -17,7 +17,8 @@ export function BlogCard({ post, variant }: BlogCardProps) {
|
||||
<article className="border border-slate-700 bg-slate-900 p-6 h-full cyber-glitch-hover">
|
||||
<div className="border-l-2 pl-4 mb-4" style={{ borderColor: 'var(--neon-pink)' }}>
|
||||
<span className="font-mono text-xs text-zinc-100 uppercase tracking-wider">
|
||||
{post.frontmatter.category} <span style={{ color: 'var(--neon-cyan)' }}>//</span> {formatDate(post.frontmatter.date)}
|
||||
{post.frontmatter.category} <span style={{ color: 'var(--neon-cyan)' }}>//</span>{' '}
|
||||
{formatDate(post.frontmatter.date)}
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-mono text-xl font-bold text-zinc-100 uppercase mb-3">
|
||||
@@ -27,8 +28,11 @@ export function BlogCard({ post, variant }: BlogCardProps) {
|
||||
{post.frontmatter.description}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2 mb-4">
|
||||
{post.frontmatter.tags.map((tag) => (
|
||||
<span key={tag} className="px-3 py-1 bg-zinc-800 border border-slate-700 text-cyan-400 font-mono text-xs uppercase">
|
||||
{post.frontmatter.tags.map(tag => (
|
||||
<span
|
||||
key={tag}
|
||||
className="px-3 py-1 bg-zinc-800 border border-slate-700 text-cyan-400 font-mono text-xs uppercase"
|
||||
>
|
||||
#{tag}
|
||||
</span>
|
||||
))}
|
||||
@@ -68,8 +72,11 @@ export function BlogCard({ post, variant }: BlogCardProps) {
|
||||
{post.frontmatter.description}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2 mb-4">
|
||||
{post.frontmatter.tags.map((tag) => (
|
||||
<span key={tag} className="px-3 py-1 bg-zinc-800 border border-slate-700 text-cyan-400 font-mono text-xs uppercase">
|
||||
{post.frontmatter.tags.map(tag => (
|
||||
<span
|
||||
key={tag}
|
||||
className="px-3 py-1 bg-zinc-800 border border-slate-700 text-cyan-400 font-mono text-xs uppercase"
|
||||
>
|
||||
#{tag}
|
||||
</span>
|
||||
))}
|
||||
@@ -99,7 +106,8 @@ export function BlogCard({ post, variant }: BlogCardProps) {
|
||||
<div className="p-6">
|
||||
<div className="border-l-2 pl-4 mb-4" style={{ borderColor: 'var(--neon-pink)' }}>
|
||||
<span className="font-mono text-xs text-zinc-100 uppercase tracking-wider">
|
||||
{post.frontmatter.category} <span style={{ color: 'var(--neon-cyan)' }}>//</span> {formatDate(post.frontmatter.date)}
|
||||
{post.frontmatter.category} <span style={{ color: 'var(--neon-cyan)' }}>//</span>{' '}
|
||||
{formatDate(post.frontmatter.date)}
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-mono text-xl font-bold text-zinc-100 uppercase mb-3">
|
||||
@@ -109,8 +117,11 @@ export function BlogCard({ post, variant }: BlogCardProps) {
|
||||
{post.frontmatter.description}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2 mb-4">
|
||||
{post.frontmatter.tags.map((tag) => (
|
||||
<span key={tag} className="px-3 py-1 bg-zinc-800 border border-slate-700 text-cyan-400 font-mono text-xs uppercase">
|
||||
{post.frontmatter.tags.map(tag => (
|
||||
<span
|
||||
key={tag}
|
||||
className="px-3 py-1 bg-zinc-800 border border-slate-700 text-cyan-400 font-mono text-xs uppercase"
|
||||
>
|
||||
#{tag}
|
||||
</span>
|
||||
))}
|
||||
|
||||
@@ -23,7 +23,9 @@ export function CodeBlock({ code, language, filename, showLineNumbers = true }:
|
||||
<div className="flex items-center justify-between px-4 py-2 bg-[rgb(var(--bg-secondary))] dark:bg-zinc-950 border-b-2 border-[var(--neon-purple)] relative">
|
||||
<div className="flex items-center gap-3">
|
||||
{filename && (
|
||||
<span className="text-[var(--neon-cyan)] font-mono text-sm uppercase">>> {filename}</span>
|
||||
<span className="text-[var(--neon-cyan)] font-mono text-sm uppercase">
|
||||
>> {filename}
|
||||
</span>
|
||||
)}
|
||||
<span className="px-2 py-1 border border-[var(--neon-purple)] text-[var(--neon-purple)] text-xs font-mono uppercase">
|
||||
[{language}]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
'use client';
|
||||
'use client'
|
||||
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { CodeBlock } from './code-block';
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { CodeBlock } from './code-block'
|
||||
|
||||
interface MarkdownRendererProps {
|
||||
content: string;
|
||||
content: string
|
||||
}
|
||||
|
||||
export default function MarkdownRenderer({ content }: MarkdownRendererProps) {
|
||||
@@ -16,48 +16,42 @@ export default function MarkdownRenderer({ content }: MarkdownRendererProps) {
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
h1: ({ children }) => {
|
||||
const text = String(children);
|
||||
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
||||
return <h1 id={id}>{children}</h1>;
|
||||
const text = String(children)
|
||||
const id = text
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/(^-|-$)/g, '')
|
||||
return <h1 id={id}>{children}</h1>
|
||||
},
|
||||
h2: ({ children }) => {
|
||||
const text = String(children);
|
||||
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
||||
return <h2 id={id}>{children}</h2>;
|
||||
const text = String(children)
|
||||
const id = text
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/(^-|-$)/g, '')
|
||||
return <h2 id={id}>{children}</h2>
|
||||
},
|
||||
h3: ({ children }) => {
|
||||
const text = String(children);
|
||||
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
||||
return <h3 id={id}>{children}</h3>;
|
||||
const text = String(children)
|
||||
const id = text
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/(^-|-$)/g, '')
|
||||
return <h3 id={id}>{children}</h3>
|
||||
},
|
||||
code: ({ inline, className, children, ...props }: any) => {
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const match = /language-(\w+)/.exec(className || '')
|
||||
if (!inline && match) {
|
||||
return (
|
||||
<CodeBlock
|
||||
code={String(children).replace(/\n$/, '')}
|
||||
language={match[1]}
|
||||
/>
|
||||
);
|
||||
return <CodeBlock code={String(children).replace(/\n$/, '')} language={match[1]} />
|
||||
}
|
||||
return (
|
||||
<code {...props}>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
return <code {...props}>{children}</code>
|
||||
},
|
||||
img: ({ src, alt }) => {
|
||||
if (!src || typeof src !== 'string') return null;
|
||||
const isExternal = src.startsWith('http://') || src.startsWith('https://');
|
||||
if (!src || typeof src !== 'string') return null
|
||||
const isExternal = src.startsWith('http://') || src.startsWith('https://')
|
||||
|
||||
if (isExternal) {
|
||||
return (
|
||||
<img
|
||||
src={src}
|
||||
alt={alt || ''}
|
||||
className="w-full h-auto"
|
||||
/>
|
||||
);
|
||||
return <img src={src} alt={alt || ''} className="w-full h-auto" />
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -70,33 +64,25 @@ export default function MarkdownRenderer({ content }: MarkdownRendererProps) {
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
},
|
||||
a: ({ href, children }) => {
|
||||
if (!href) return <>{children}</>;
|
||||
const isExternal = href.startsWith('http://') || href.startsWith('https://');
|
||||
if (!href) return <>{children}</>
|
||||
const isExternal = href.startsWith('http://') || href.startsWith('https://')
|
||||
|
||||
if (isExternal) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<a href={href} target="_blank" rel="noopener noreferrer">
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={href}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
return <Link href={href}>{children}</Link>
|
||||
},
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</ReactMarkdown>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -28,11 +28,17 @@ export function Navbar() {
|
||||
}, [lastScrollY])
|
||||
|
||||
return (
|
||||
<nav className={`border-b-4 border-slate-700 bg-slate-900 dark:bg-zinc-950 sticky top-0 z-50 ${isVisible ? 'navbar-visible' : 'navbar-hidden'}`}>
|
||||
<nav
|
||||
className={`border-b-4 border-slate-700 bg-slate-900 dark:bg-zinc-950 sticky top-0 z-50 ${isVisible ? 'navbar-visible' : 'navbar-hidden'}`}
|
||||
>
|
||||
<div className="max-w-7xl mx-auto px-6 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-8">
|
||||
<Link href="/" className="font-mono text-sm uppercase tracking-wider transition-colors cursor-pointer" style={{ color: 'var(--neon-cyan)' }}>
|
||||
<Link
|
||||
href="/"
|
||||
className="font-mono text-sm uppercase tracking-wider transition-colors cursor-pointer"
|
||||
style={{ color: 'var(--neon-cyan)' }}
|
||||
>
|
||||
< HOME
|
||||
</Link>
|
||||
<span className="font-mono text-sm text-zinc-100 dark:text-zinc-300 uppercase tracking-wider">
|
||||
@@ -40,7 +46,10 @@ export function Navbar() {
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-6">
|
||||
<Link href="/about" className="font-mono text-sm text-zinc-400 dark:text-zinc-500 uppercase tracking-wider hover:text-cyan-400 dark:hover:text-cyan-300 transition-colors cursor-pointer">
|
||||
<Link
|
||||
href="/about"
|
||||
className="font-mono text-sm text-zinc-400 dark:text-zinc-500 uppercase tracking-wider hover:text-cyan-400 dark:hover:text-cyan-300 transition-colors cursor-pointer"
|
||||
>
|
||||
[ABOUT]
|
||||
</Link>
|
||||
<ThemeToggle />
|
||||
|
||||
@@ -25,15 +25,13 @@ export function ReadingProgress() {
|
||||
className="h-full bg-gradient-to-r from-[var(--neon-cyan)] via-[var(--neon-magenta)] to-[var(--neon-pink)] transition-all duration-150"
|
||||
style={{
|
||||
width: `${progress}%`,
|
||||
boxShadow: progress > 0 ? '0 0 8px var(--neon-cyan)' : 'none'
|
||||
boxShadow: progress > 0 ? '0 0 8px var(--neon-cyan)' : 'none',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="fixed top-4 right-4 z-50 px-3 py-1.5 bg-[rgb(var(--bg-primary))] border-2 border-[var(--neon-cyan)] text-xs font-mono font-bold text-[var(--neon-cyan)] relative">
|
||||
<span className="relative z-10">
|
||||
[{Math.round(progress)}%]
|
||||
</span>
|
||||
<span className="relative z-10">[{Math.round(progress)}%]</span>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -6,12 +6,14 @@ interface SearchBarProps {
|
||||
export function SearchBar({ searchQuery, onSearchChange }: SearchBarProps) {
|
||||
return (
|
||||
<div className="flex-1 flex items-center border border-slate-700 bg-zinc-900 transition-all focus-within:border-[var(--neon-cyan)] focus-within:shadow-[0_0_6px_rgba(0,255,255,0.4),inset_0_0_6px_rgba(0,255,255,0.05)]">
|
||||
<span className="pl-4 pr-2 font-mono text-lg" style={{ color: 'var(--neon-cyan)' }}>></span>
|
||||
<span className="pl-4 pr-2 font-mono text-lg" style={{ color: 'var(--neon-cyan)' }}>
|
||||
>
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="SEARCH POSTS..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => onSearchChange(e.target.value)}
|
||||
onChange={e => onSearchChange(e.target.value)}
|
||||
className="flex-1 bg-transparent font-mono text-zinc-100 dark:text-zinc-100 px-2 py-3 focus:outline-none placeholder:text-zinc-600 uppercase text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,12 +9,30 @@ export function SortDropdown({ sortBy, onSortChange }: SortDropdownProps) {
|
||||
return (
|
||||
<select
|
||||
value={sortBy}
|
||||
onChange={(e) => onSortChange(e.target.value as SortOption)}
|
||||
onChange={e => onSortChange(e.target.value as SortOption)}
|
||||
className="border-2 border-slate-700 bg-zinc-900 dark:bg-zinc-900 text-zinc-100 dark:text-zinc-100 font-mono px-6 py-3 uppercase text-sm cyber-focus-pink transition-all hover:border-cyan-400 cursor-pointer"
|
||||
>
|
||||
<option value="newest" className="bg-zinc-900 text-zinc-100" style={{ backgroundColor: '#18181b', color: '#f4f4f5' }}>NEWEST FIRST</option>
|
||||
<option value="oldest" className="bg-zinc-900 text-zinc-100" style={{ backgroundColor: '#18181b', color: '#f4f4f5' }}>OLDEST FIRST</option>
|
||||
<option value="title" className="bg-zinc-900 text-zinc-100" style={{ backgroundColor: '#18181b', color: '#f4f4f5' }}>BY TITLE</option>
|
||||
<option
|
||||
value="newest"
|
||||
className="bg-zinc-900 text-zinc-100"
|
||||
style={{ backgroundColor: '#18181b', color: '#f4f4f5' }}
|
||||
>
|
||||
NEWEST FIRST
|
||||
</option>
|
||||
<option
|
||||
value="oldest"
|
||||
className="bg-zinc-900 text-zinc-100"
|
||||
style={{ backgroundColor: '#18181b', color: '#f4f4f5' }}
|
||||
>
|
||||
OLDEST FIRST
|
||||
</option>
|
||||
<option
|
||||
value="title"
|
||||
className="bg-zinc-900 text-zinc-100"
|
||||
style={{ backgroundColor: '#18181b', color: '#f4f4f5' }}
|
||||
>
|
||||
BY TITLE
|
||||
</option>
|
||||
</select>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,9 @@ export function StickyFooter({ url, title }: StickyFooterProps) {
|
||||
${isVisible ? 'translate-y-0' : 'translate-y-full'}
|
||||
`}
|
||||
style={{
|
||||
boxShadow: isVisible ? '0 -8px 30px rgba(155,90,142,0.5), inset 0 4px 20px rgba(155,90,142,0.1)' : 'none'
|
||||
boxShadow: isVisible
|
||||
? '0 -8px 30px rgba(155,90,142,0.5), inset 0 4px 20px rgba(155,90,142,0.1)'
|
||||
: 'none',
|
||||
}}
|
||||
>
|
||||
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-[var(--neon-magenta)] to-transparent opacity-70" />
|
||||
@@ -60,7 +62,10 @@ export function StickyFooter({ url, title }: StickyFooterProps) {
|
||||
<div className="w-2 h-2 bg-[var(--neon-cyan)] shadow-[0_0_6px_rgba(90,139,149,1)]" />
|
||||
<div className="w-2 h-2 bg-[var(--neon-pink)] shadow-[0_0_6px_rgba(155,90,110,1)]" />
|
||||
</div>
|
||||
<span className="text-[var(--neon-cyan)] font-mono text-xs uppercase tracking-wider" style={{ textShadow: '0 0 8px rgba(90,139,149,0.6)' }}>
|
||||
<span
|
||||
className="text-[var(--neon-cyan)] font-mono text-xs uppercase tracking-wider"
|
||||
style={{ textShadow: '0 0 8px rgba(90,139,149,0.6)' }}
|
||||
>
|
||||
>> SHARE:
|
||||
</span>
|
||||
</div>
|
||||
@@ -89,7 +94,9 @@ export function StickyFooter({ url, title }: StickyFooterProps) {
|
||||
<button
|
||||
onClick={handleCopyLink}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-black border-4 border-[var(--neon-pink)] text-[var(--neon-pink)] font-mono text-xs uppercase tracking-wider transition-all hover:shadow-[0_0_25px_rgba(155,90,110,0.8)] hover:bg-pink-900/20"
|
||||
style={{ textShadow: copied ? '0 0 10px rgba(155,90,110,1)' : '0 0 8px rgba(155,90,110,0.6)' }}
|
||||
style={{
|
||||
textShadow: copied ? '0 0 10px rgba(155,90,110,1)' : '0 0 8px rgba(155,90,110,0.6)',
|
||||
}}
|
||||
>
|
||||
{copied ? '[✓ COPIED]' : '[COPY]'}
|
||||
</button>
|
||||
|
||||
@@ -17,8 +17,8 @@ export function TableOfContents({ headings }: TOCProps) {
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
setActiveId(entry.target.id)
|
||||
}
|
||||
@@ -43,31 +43,45 @@ export function TableOfContents({ headings }: TOCProps) {
|
||||
|
||||
<div className="border-b border-[var(--neon-magenta)] pb-3 mb-4 relative">
|
||||
<div className="flex gap-1.5 mb-2 justify-end">
|
||||
<div className="w-3 h-3 border border-[var(--neon-cyan)]/40 hover:bg-[var(--neon-cyan)]/10 transition-colors cursor-pointer" title="Minimize" />
|
||||
<div className="w-3 h-3 border border-[var(--neon-cyan)]/40 hover:bg-[var(--neon-cyan)]/10 transition-colors cursor-pointer" title="Maximize" />
|
||||
<div className="w-3 h-3 border border-[var(--neon-pink)]/40 hover:bg-[var(--neon-pink)]/10 transition-colors cursor-pointer" title="Close" />
|
||||
<div
|
||||
className="w-3 h-3 border border-[var(--neon-cyan)]/40 hover:bg-[var(--neon-cyan)]/10 transition-colors cursor-pointer"
|
||||
title="Minimize"
|
||||
/>
|
||||
<div
|
||||
className="w-3 h-3 border border-[var(--neon-cyan)]/40 hover:bg-[var(--neon-cyan)]/10 transition-colors cursor-pointer"
|
||||
title="Maximize"
|
||||
/>
|
||||
<div
|
||||
className="w-3 h-3 border border-[var(--neon-pink)]/40 hover:bg-[var(--neon-pink)]/10 transition-colors cursor-pointer"
|
||||
title="Close"
|
||||
/>
|
||||
</div>
|
||||
<h3 className="text-xs font-mono font-bold text-[var(--neon-cyan)] uppercase tracking-wider" style={{ textShadow: '0 0 6px rgba(90,139,149,0.5)' }}>
|
||||
<h3
|
||||
className="text-xs font-mono font-bold text-[var(--neon-cyan)] uppercase tracking-wider"
|
||||
style={{ textShadow: '0 0 6px rgba(90,139,149,0.5)' }}
|
||||
>
|
||||
>> NAVIGATION
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<nav className="space-y-1 relative">
|
||||
{headings.map((heading) => (
|
||||
{headings.map(heading => (
|
||||
<a
|
||||
key={heading.id}
|
||||
href={`#${heading.id}`}
|
||||
className={`
|
||||
block text-sm font-mono py-2 border-l-2 transition-all duration-150
|
||||
${heading.level === 2 ? 'pl-3' : 'pl-6'}
|
||||
${activeId === heading.id
|
||||
? 'text-[var(--neon-cyan)] border-[var(--neon-cyan)] bg-cyan-500/5 shadow-[0_0_8px_rgba(90,139,149,0.3)]'
|
||||
: 'text-zinc-500 border-zinc-900 hover:border-[var(--neon-magenta)] hover:text-[var(--neon-magenta)] hover:bg-magenta-500/3 hover:shadow-[0_0_4px_rgba(155,90,142,0.2)]'
|
||||
${
|
||||
activeId === heading.id
|
||||
? 'text-[var(--neon-cyan)] border-[var(--neon-cyan)] bg-cyan-500/5 shadow-[0_0_8px_rgba(90,139,149,0.3)]'
|
||||
: 'text-zinc-500 border-zinc-900 hover:border-[var(--neon-magenta)] hover:text-[var(--neon-magenta)] hover:bg-magenta-500/3 hover:shadow-[0_0_4px_rgba(155,90,142,0.2)]'
|
||||
}
|
||||
`}
|
||||
style={activeId === heading.id ? { textShadow: '0 0 4px rgba(90,139,149,0.5)' } : {}}
|
||||
>
|
||||
<span className="inline-block">{activeId === heading.id ? '▶ ' : '◆ '}</span>{heading.text}
|
||||
<span className="inline-block">{activeId === heading.id ? '▶ ' : '◆ '}</span>
|
||||
{heading.text}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
@@ -14,7 +14,7 @@ export function TagFilter({ allTags, selectedTags, onToggleTag, onClearTags }: T
|
||||
FILTER BY TAG
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{allTags.map((tag) => (
|
||||
{allTags.map(tag => (
|
||||
<button
|
||||
key={tag}
|
||||
onClick={() => onToggleTag(tag)}
|
||||
|
||||
Reference in New Issue
Block a user