💂♂️ fixed lint and prittier
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs';
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs'
|
||||
|
||||
export default function AboutBreadcrumb() {
|
||||
return (
|
||||
@@ -11,5 +11,5 @@ export default function AboutBreadcrumb() {
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs';
|
||||
import { getPostBySlug } from '@/lib/markdown';
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs'
|
||||
import { getPostBySlug } from '@/lib/markdown'
|
||||
|
||||
interface BreadcrumbItem {
|
||||
label: string;
|
||||
href: string;
|
||||
current?: boolean;
|
||||
label: string
|
||||
href: string
|
||||
current?: boolean
|
||||
}
|
||||
|
||||
function formatDirectoryName(name: string): string {
|
||||
@@ -12,34 +12,34 @@ function formatDirectoryName(name: string): string {
|
||||
tech: 'Tehnologie',
|
||||
design: 'Design',
|
||||
tutorial: 'Tutoriale',
|
||||
};
|
||||
}
|
||||
|
||||
return directoryNames[name] || name.charAt(0).toUpperCase() + name.slice(1);
|
||||
return directoryNames[name] || name.charAt(0).toUpperCase() + name.slice(1)
|
||||
}
|
||||
|
||||
export default async function BlogPostBreadcrumb({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ slug: string[] }>;
|
||||
params: Promise<{ slug: string[] }>
|
||||
}) {
|
||||
const { slug } = await params;
|
||||
const slugPath = slug.join('/');
|
||||
const post = getPostBySlug(slugPath);
|
||||
const { slug } = await params
|
||||
const slugPath = slug.join('/')
|
||||
const post = getPostBySlug(slugPath)
|
||||
|
||||
const items: BreadcrumbItem[] = [
|
||||
{
|
||||
label: 'Blog',
|
||||
href: '/blog',
|
||||
},
|
||||
];
|
||||
]
|
||||
|
||||
if (slug.length > 1) {
|
||||
for (let i = 0; i < slug.length - 1; i++) {
|
||||
const segmentPath = slug.slice(0, i + 1).join('/');
|
||||
const segmentPath = slug.slice(0, i + 1).join('/')
|
||||
items.push({
|
||||
label: formatDirectoryName(slug[i]),
|
||||
href: `/blog/${segmentPath}`,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export default async function BlogPostBreadcrumb({
|
||||
label: post ? post.frontmatter.title : slug[slug.length - 1],
|
||||
href: `/blog/${slugPath}`,
|
||||
current: true,
|
||||
});
|
||||
})
|
||||
|
||||
return <Breadcrumbs items={items} />;
|
||||
return <Breadcrumbs items={items} />
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs';
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs'
|
||||
|
||||
export default function BlogBreadcrumb() {
|
||||
return (
|
||||
@@ -11,5 +11,5 @@ export default function BlogBreadcrumb() {
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
'use client'
|
||||
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs';
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs'
|
||||
|
||||
export default function DefaultBreadcrumb() {
|
||||
return <Breadcrumbs />;
|
||||
return <Breadcrumbs />
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs';
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs'
|
||||
|
||||
export default async function TagBreadcrumb({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ tag: string }>;
|
||||
}) {
|
||||
const { tag } = await params;
|
||||
export default async function TagBreadcrumb({ params }: { params: Promise<{ tag: string }> }) {
|
||||
const { tag } = await params
|
||||
const tagName = tag
|
||||
.split('-')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
.join(' ')
|
||||
|
||||
return (
|
||||
<Breadcrumbs
|
||||
@@ -25,5 +21,5 @@ export default async function TagBreadcrumb({
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs';
|
||||
import { Breadcrumbs } from '@/components/layout/Breadcrumbs'
|
||||
|
||||
export default function TagsBreadcrumb() {
|
||||
return (
|
||||
@@ -11,5 +11,5 @@ export default function TagsBreadcrumb() {
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ export default function AboutPage() {
|
||||
|
||||
<div className="prose dark:prose-invert max-w-none">
|
||||
<p className="text-lg leading-relaxed mb-6">
|
||||
Bun venit pe blogul meu! Sunt un dezvoltator pasionat de tehnologie,
|
||||
specializat în dezvoltarea web modernă cu Next.js, React și TypeScript.
|
||||
Bun venit pe blogul meu! Sunt un dezvoltator pasionat de tehnologie, specializat în
|
||||
dezvoltarea web modernă cu Next.js, React și TypeScript.
|
||||
</p>
|
||||
|
||||
<h2 className="text-2xl font-semibold mt-8 mb-4">Ce vei găsi aici</h2>
|
||||
@@ -27,10 +27,18 @@ export default function AboutPage() {
|
||||
<h2 className="text-2xl font-semibold mt-8 mb-4">Tehnologii folosite</h2>
|
||||
<p>Acest blog este construit cu:</p>
|
||||
<ul className="space-y-2">
|
||||
<li><strong>Next.js 15</strong> - Framework React pentru producție</li>
|
||||
<li><strong>TypeScript</strong> - Pentru type safety</li>
|
||||
<li><strong>Tailwind CSS</strong> - Pentru stilizare rapidă</li>
|
||||
<li><strong>Markdown</strong> - Pentru conținut</li>
|
||||
<li>
|
||||
<strong>Next.js 15</strong> - Framework React pentru producție
|
||||
</li>
|
||||
<li>
|
||||
<strong>TypeScript</strong> - Pentru type safety
|
||||
</li>
|
||||
<li>
|
||||
<strong>Tailwind CSS</strong> - Pentru stilizare rapidă
|
||||
</li>
|
||||
<li>
|
||||
<strong>Markdown</strong> - Pentru conținut
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="text-2xl font-semibold mt-8 mb-4">Contact</h2>
|
||||
|
||||
@@ -10,10 +10,16 @@ export default function NotFound() {
|
||||
Ne pare rău, dar articolul pe care îl cauți nu există sau a fost mutat.
|
||||
</p>
|
||||
<div className="space-x-4">
|
||||
<Link href="/blog" className="inline-block px-6 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition">
|
||||
<Link
|
||||
href="/blog"
|
||||
className="inline-block px-6 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition"
|
||||
>
|
||||
Vezi toate articolele
|
||||
</Link>
|
||||
<Link href="/" className="inline-block px-6 py-3 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition">
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-block px-6 py-3 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition"
|
||||
>
|
||||
Pagina principală
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -10,10 +10,14 @@ import MarkdownRenderer from '@/components/blog/markdown-renderer'
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const posts = await getAllPosts()
|
||||
return posts.map((post) => ({ slug: post.slug.split('/') }))
|
||||
return posts.map(post => ({ slug: post.slug.split('/') }))
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<{ slug: string[] }> }): Promise<Metadata> {
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ slug: string[] }>
|
||||
}): Promise<Metadata> {
|
||||
const { slug } = await params
|
||||
const slugPath = slug.join('/')
|
||||
const post = getPostBySlug(slugPath)
|
||||
@@ -51,7 +55,10 @@ function extractHeadings(content: string) {
|
||||
while ((match = headingRegex.exec(content)) !== null) {
|
||||
const level = match[1].length
|
||||
const text = match[2]
|
||||
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '')
|
||||
const id = text
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/(^-|-$)/g, '')
|
||||
headings.push({ id, text, level })
|
||||
}
|
||||
|
||||
@@ -110,7 +117,8 @@ export default async function BlogPostPage({ params }: { params: Promise<{ slug:
|
||||
</h1>
|
||||
|
||||
<p className="text-lg text-[rgb(var(--text-secondary))] leading-relaxed mb-6 font-mono">
|
||||
<span className="text-[var(--neon-pink)]">>></span> {post.frontmatter.description}
|
||||
<span className="text-[var(--neon-pink)]">>></span>{' '}
|
||||
{post.frontmatter.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -121,9 +129,13 @@ export default async function BlogPostPage({ params }: { params: Promise<{ slug:
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-mono font-bold text-[var(--neon-cyan)] uppercase text-sm">{post.frontmatter.author}</p>
|
||||
<p className="font-mono font-bold text-[var(--neon-cyan)] uppercase text-sm">
|
||||
{post.frontmatter.author}
|
||||
</p>
|
||||
<div className="flex items-center gap-2 text-xs text-[rgb(var(--text-muted))] font-mono">
|
||||
<time className="text-[var(--neon-magenta)]">{formatDate(post.frontmatter.date)}</time>
|
||||
<time className="text-[var(--neon-magenta)]">
|
||||
{formatDate(post.frontmatter.date)}
|
||||
</time>
|
||||
<span className="text-[var(--neon-pink)]">//</span>
|
||||
<span className="text-[var(--neon-cyan)]">{post.readingTime}min READ</span>
|
||||
</div>
|
||||
@@ -147,17 +159,25 @@ export default async function BlogPostPage({ params }: { params: Promise<{ slug:
|
||||
|
||||
{relatedPosts.length > 0 && (
|
||||
<section className="mt-12 pt-8 border-t border-zinc-800">
|
||||
<h2 className="text-2xl font-mono font-bold uppercase text-[var(--neon-cyan)] mb-6">// Articole similare</h2>
|
||||
<h2 className="text-2xl font-mono font-bold uppercase text-[var(--neon-cyan)] mb-6">
|
||||
// Articole similare
|
||||
</h2>
|
||||
<div className="grid gap-6 md:grid-cols-3">
|
||||
{relatedPosts.map((relatedPost) => (
|
||||
{relatedPosts.map(relatedPost => (
|
||||
<Link
|
||||
key={relatedPost.slug}
|
||||
href={`/blog/${relatedPost.slug}`}
|
||||
className="block p-4 border border-zinc-800 bg-zinc-950 hover:border-[var(--neon-cyan)] transition-all hover:shadow-[0_0_8px_rgba(90,139,149,0.2)]"
|
||||
>
|
||||
<h3 className="font-mono font-semibold text-cyan-400 mb-2 line-clamp-2">{relatedPost.frontmatter.title}</h3>
|
||||
<p className="text-sm text-zinc-400 line-clamp-2">{relatedPost.frontmatter.description}</p>
|
||||
<p className="text-xs text-zinc-600 mt-2 font-mono">{formatDate(relatedPost.frontmatter.date)}</p>
|
||||
<h3 className="font-mono font-semibold text-cyan-400 mb-2 line-clamp-2">
|
||||
{relatedPost.frontmatter.title}
|
||||
</h3>
|
||||
<p className="text-sm text-zinc-400 line-clamp-2">
|
||||
{relatedPost.frontmatter.description}
|
||||
</p>
|
||||
<p className="text-xs text-zinc-600 mt-2 font-mono">
|
||||
{formatDate(relatedPost.frontmatter.date)}
|
||||
</p>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
@@ -170,7 +190,12 @@ export default async function BlogPostPage({ params }: { params: Promise<{ slug:
|
||||
className="flex items-center text-[var(--neon-pink)] hover:text-[var(--neon-magenta)] transition-all font-mono text-sm uppercase border border-[var(--neon-pink)] px-4 py-2 hover:shadow-[0_0_6px_rgba(155,90,110,0.3)]"
|
||||
>
|
||||
<svg className="mr-2 w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 19l-7-7 7-7"
|
||||
/>
|
||||
</svg>
|
||||
[BACK TO BLOG]
|
||||
</Link>
|
||||
|
||||
@@ -23,15 +23,14 @@ export default function BlogPageClient({ posts, allTags }: BlogPageClientProps)
|
||||
const postsPerPage = 9
|
||||
|
||||
const filteredAndSortedPosts = useMemo(() => {
|
||||
let result = posts.filter((post) => {
|
||||
const result = posts.filter(post => {
|
||||
const matchesSearch =
|
||||
searchQuery === '' ||
|
||||
post.frontmatter.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
post.frontmatter.description.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
|
||||
const matchesTags =
|
||||
selectedTags.length === 0 ||
|
||||
selectedTags.every((tag) => post.frontmatter.tags.includes(tag))
|
||||
selectedTags.length === 0 || selectedTags.every(tag => post.frontmatter.tags.includes(tag))
|
||||
|
||||
return matchesSearch && matchesTags
|
||||
})
|
||||
@@ -58,15 +57,12 @@ export default function BlogPageClient({ posts, allTags }: BlogPageClientProps)
|
||||
)
|
||||
|
||||
const toggleTag = (tag: string) => {
|
||||
setSelectedTags((prev) =>
|
||||
prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]
|
||||
)
|
||||
setSelectedTags(prev => (prev.includes(tag) ? prev.filter(t => t !== tag) : [...prev, tag]))
|
||||
setCurrentPage(1)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[rgb(var(--bg-primary))]">
|
||||
|
||||
<div className="max-w-7xl mx-auto px-6 py-12">
|
||||
{/* Header */}
|
||||
<div className="border-l border-[var(--neon-cyan)] pl-6 mb-12">
|
||||
@@ -83,15 +79,12 @@ export default function BlogPageClient({ posts, allTags }: BlogPageClientProps)
|
||||
<div className="flex flex-col lg:flex-row gap-4">
|
||||
<SearchBar
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={(value) => {
|
||||
onSearchChange={value => {
|
||||
setSearchQuery(value)
|
||||
setCurrentPage(1)
|
||||
}}
|
||||
/>
|
||||
<SortDropdown
|
||||
sortBy={sortBy}
|
||||
onSortChange={setSortBy}
|
||||
/>
|
||||
<SortDropdown sortBy={sortBy} onSortChange={setSortBy} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -109,7 +102,8 @@ export default function BlogPageClient({ posts, allTags }: BlogPageClientProps)
|
||||
{/* Results Count */}
|
||||
<div className="mb-6">
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase">
|
||||
FOUND {filteredAndSortedPosts.length} {filteredAndSortedPosts.length === 1 ? 'POST' : 'POSTS'}
|
||||
FOUND {filteredAndSortedPosts.length}{' '}
|
||||
{filteredAndSortedPosts.length === 1 ? 'POST' : 'POSTS'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -142,14 +136,14 @@ export default function BlogPageClient({ posts, allTags }: BlogPageClientProps)
|
||||
<div className="border border-[rgb(var(--border-primary))] bg-[rgb(var(--bg-secondary))] p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<button
|
||||
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
||||
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className="px-6 py-3 font-mono text-sm uppercase border border-[rgb(var(--border-primary))] text-[rgb(var(--text-primary))] disabled:opacity-30 disabled:cursor-not-allowed hover:border-[var(--neon-cyan)] hover:text-[var(--neon-cyan)] transition-colors cursor-pointer"
|
||||
>
|
||||
< PREV
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
{Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (
|
||||
{Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (
|
||||
<button
|
||||
key={page}
|
||||
onClick={() => setCurrentPage(page)}
|
||||
@@ -164,7 +158,7 @@ export default function BlogPageClient({ posts, allTags }: BlogPageClientProps)
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
|
||||
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className="px-6 py-3 font-mono text-sm uppercase border border-[rgb(var(--border-primary))] text-[rgb(var(--text-primary))] disabled:opacity-30 disabled:cursor-not-allowed hover:border-[var(--neon-cyan)] hover:text-[var(--neon-cyan)] transition-colors cursor-pointer"
|
||||
>
|
||||
|
||||
@@ -3,7 +3,7 @@ import BlogPageClient from './blog-client'
|
||||
|
||||
export default async function BlogPage() {
|
||||
const posts = await getAllPosts()
|
||||
const allTags = Array.from(new Set(posts.flatMap((post) => post.frontmatter.tags))).sort()
|
||||
const allTags = Array.from(new Set(posts.flatMap(post => post.frontmatter.tags))).sort()
|
||||
|
||||
return <BlogPageClient posts={posts} allTags={allTags} />
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "tailwindcss";
|
||||
@import 'tailwindcss';
|
||||
|
||||
@theme {
|
||||
--color-*: initial;
|
||||
@@ -70,12 +70,7 @@
|
||||
|
||||
/* Scanline effect */
|
||||
.scanline {
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
transparent 0%,
|
||||
rgba(6, 182, 212, 0.1) 50%,
|
||||
transparent 100%
|
||||
);
|
||||
background: linear-gradient(0deg, transparent 0%, rgba(6, 182, 212, 0.1) 50%, transparent 100%);
|
||||
background-size: 100% 3px;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -135,19 +130,43 @@
|
||||
}
|
||||
|
||||
@keyframes glitch-1 {
|
||||
0%, 100% { clip-path: polygon(0 0, 100% 0, 100% 45%, 0 45%); transform: translate(0); }
|
||||
20% { clip-path: polygon(0 15%, 100% 15%, 100% 65%, 0 65%); }
|
||||
40% { clip-path: polygon(0 30%, 100% 30%, 100% 70%, 0 70%); }
|
||||
60% { clip-path: polygon(0 5%, 100% 5%, 100% 60%, 0 60%); }
|
||||
80% { clip-path: polygon(0 25%, 100% 25%, 100% 40%, 0 40%); }
|
||||
0%,
|
||||
100% {
|
||||
clip-path: polygon(0 0, 100% 0, 100% 45%, 0 45%);
|
||||
transform: translate(0);
|
||||
}
|
||||
20% {
|
||||
clip-path: polygon(0 15%, 100% 15%, 100% 65%, 0 65%);
|
||||
}
|
||||
40% {
|
||||
clip-path: polygon(0 30%, 100% 30%, 100% 70%, 0 70%);
|
||||
}
|
||||
60% {
|
||||
clip-path: polygon(0 5%, 100% 5%, 100% 60%, 0 60%);
|
||||
}
|
||||
80% {
|
||||
clip-path: polygon(0 25%, 100% 25%, 100% 40%, 0 40%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glitch-2 {
|
||||
0%, 100% { clip-path: polygon(0 55%, 100% 55%, 100% 100%, 0 100%); transform: translate(0); }
|
||||
20% { clip-path: polygon(0 70%, 100% 70%, 100% 95%, 0 95%); }
|
||||
40% { clip-path: polygon(0 40%, 100% 40%, 100% 85%, 0 85%); }
|
||||
60% { clip-path: polygon(0 60%, 100% 60%, 100% 100%, 0 100%); }
|
||||
80% { clip-path: polygon(0 50%, 100% 50%, 100% 90%, 0 90%); }
|
||||
0%,
|
||||
100% {
|
||||
clip-path: polygon(0 55%, 100% 55%, 100% 100%, 0 100%);
|
||||
transform: translate(0);
|
||||
}
|
||||
20% {
|
||||
clip-path: polygon(0 70%, 100% 70%, 100% 95%, 0 95%);
|
||||
}
|
||||
40% {
|
||||
clip-path: polygon(0 40%, 100% 40%, 100% 85%, 0 85%);
|
||||
}
|
||||
60% {
|
||||
clip-path: polygon(0 60%, 100% 60%, 100% 100%, 0 100%);
|
||||
}
|
||||
80% {
|
||||
clip-path: polygon(0 50%, 100% 50%, 100% 90%, 0 90%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Grayscale filter with instant toggle */
|
||||
@@ -162,7 +181,7 @@
|
||||
/* Cyberpunk Glitch Effect for Button */
|
||||
.glitch-btn {
|
||||
position: relative;
|
||||
animation: glitch 300ms cubic-bezier(.25, .46, .45, .94);
|
||||
animation: glitch 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
|
||||
.glitch-layer {
|
||||
@@ -179,21 +198,22 @@
|
||||
}
|
||||
|
||||
.glitch-layer:first-of-type {
|
||||
animation: glitch-1 300ms cubic-bezier(.25, .46, .45, .94);
|
||||
animation: glitch-1 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
color: rgb(6 182 212); /* cyan-500 */
|
||||
transform: translate(-2px, 0);
|
||||
clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
|
||||
}
|
||||
|
||||
.glitch-layer:last-of-type {
|
||||
animation: glitch-2 300ms cubic-bezier(.25, .46, .45, .94);
|
||||
animation: glitch-2 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
color: rgb(16 185 129); /* emerald-500 */
|
||||
transform: translate(2px, 0);
|
||||
clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%);
|
||||
}
|
||||
|
||||
@keyframes glitch-1 {
|
||||
0%, 100% {
|
||||
0%,
|
||||
100% {
|
||||
transform: translate(0, 0);
|
||||
clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
|
||||
}
|
||||
@@ -212,7 +232,8 @@
|
||||
}
|
||||
|
||||
@keyframes glitch-2 {
|
||||
0%, 100% {
|
||||
0%,
|
||||
100% {
|
||||
transform: translate(0, 0);
|
||||
clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%);
|
||||
}
|
||||
@@ -262,7 +283,8 @@
|
||||
|
||||
/* SCP-style subtle flicker hover */
|
||||
@keyframes scp-flicker {
|
||||
0%, 100% {
|
||||
0%,
|
||||
100% {
|
||||
border-color: rgb(71 85 105);
|
||||
box-shadow: 0 0 0 rgba(90, 139, 149, 0);
|
||||
transform: translate(0, 0);
|
||||
@@ -292,7 +314,9 @@
|
||||
.cyber-glitch-hover:hover {
|
||||
animation: scp-flicker 150ms ease-in-out 3;
|
||||
border-color: var(--neon-cyan) !important;
|
||||
box-shadow: 0 1px 4px rgba(90, 139, 149, 0.15), inset 0 0 8px rgba(90, 139, 149, 0.05);
|
||||
box-shadow:
|
||||
0 1px 4px rgba(90, 139, 149, 0.15),
|
||||
inset 0 0 8px rgba(90, 139, 149, 0.05);
|
||||
}
|
||||
|
||||
/* Navbar hide on scroll */
|
||||
@@ -405,7 +429,9 @@
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
position: relative;
|
||||
box-shadow: -4px 0 15px rgba(155,90,142,0.3), inset 0 0 20px rgba(155,90,142,0.05);
|
||||
box-shadow:
|
||||
-4px 0 15px rgba(155, 90, 142, 0.3),
|
||||
inset 0 0 20px rgba(155, 90, 142, 0.05);
|
||||
}
|
||||
|
||||
.cyberpunk-prose blockquote::before {
|
||||
@@ -426,8 +452,8 @@
|
||||
font-size: 0.875rem;
|
||||
font-family: monospace;
|
||||
border: 2px solid var(--neon-cyan);
|
||||
box-shadow: 0 0 8px rgba(90,139,149,0.3);
|
||||
text-shadow: 0 0 6px rgba(90,139,149,0.6);
|
||||
box-shadow: 0 0 8px rgba(90, 139, 149, 0.3);
|
||||
text-shadow: 0 0 6px rgba(90, 139, 149, 0.6);
|
||||
}
|
||||
|
||||
.cyberpunk-prose pre {
|
||||
@@ -437,7 +463,9 @@
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
overflow-x: auto;
|
||||
box-shadow: 0 0 25px rgba(123,101,147,0.6), inset 0 0 25px rgba(123,101,147,0.1);
|
||||
box-shadow:
|
||||
0 0 25px rgba(123, 101, 147, 0.6),
|
||||
inset 0 0 25px rgba(123, 101, 147, 0.1);
|
||||
}
|
||||
|
||||
.cyberpunk-prose pre code {
|
||||
@@ -450,7 +478,7 @@
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
border: 4px solid var(--neon-pink);
|
||||
box-shadow: 0 0 20px rgba(155,90,110,0.5);
|
||||
box-shadow: 0 0 20px rgba(155, 90, 110, 0.5);
|
||||
}
|
||||
|
||||
.cyberpunk-prose hr {
|
||||
@@ -460,4 +488,3 @@
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,11 +28,7 @@ export const metadata: Metadata = {
|
||||
},
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="ro" suppressHydrationWarning className={jetbrainsMono.variable}>
|
||||
<body className="font-mono bg-zinc-50 text-slate-900 dark:bg-zinc-900 dark:text-slate-100 transition-colors duration-300">
|
||||
@@ -51,7 +47,9 @@ export default function RootLayout({
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="border-2 border-slate-300 dark:border-slate-800 p-6">
|
||||
<p className="text-center text-slate-500 dark:text-slate-500 font-mono text-xs uppercase tracking-wider">
|
||||
© 2025 <span style={{ color: 'var(--neon-cyan)' }}>//</span> BLOG & <span style={{ color: 'var(--neon-pink)' }}>PORTOFOLIU</span> <span style={{ color: 'var(--neon-cyan)' }}>//</span> ALL RIGHTS RESERVED
|
||||
© 2025 <span style={{ color: 'var(--neon-cyan)' }}>//</span> BLOG &{' '}
|
||||
<span style={{ color: 'var(--neon-pink)' }}>PORTOFOLIU</span>{' '}
|
||||
<span style={{ color: 'var(--neon-cyan)' }}>//</span> ALL RIGHTS RESERVED
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
40
app/page.tsx
40
app/page.tsx
@@ -22,19 +22,35 @@ export default async function HomePage() {
|
||||
<div className="mb-8 flex items-center justify-between border-b-2 border-slate-300 dark:border-slate-800 pb-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<Image src="/logo.png" alt="Logo" width={32} height={32} className="opacity-80" />
|
||||
<span className="font-mono text-xs text-slate-500 uppercase tracking-widest">TERMINAL:// V2.0</span>
|
||||
<span className="font-mono text-xs text-slate-500 uppercase tracking-widest">
|
||||
TERMINAL:// V2.0
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex gap-4 items-center">
|
||||
<Link href="/blog" className="font-mono text-xs text-slate-600 dark:text-slate-400 uppercase tracking-wider hover:text-cyan-600 dark:hover:text-cyan-400">[BLOG]</Link>
|
||||
<Link href="/about" className="font-mono text-xs text-slate-600 dark:text-slate-400 uppercase tracking-wider hover:text-cyan-600 dark:hover:text-cyan-400">[ABOUT]</Link>
|
||||
<Link
|
||||
href="/blog"
|
||||
className="font-mono text-xs text-slate-600 dark:text-slate-400 uppercase tracking-wider hover:text-cyan-600 dark:hover:text-cyan-400"
|
||||
>
|
||||
[BLOG]
|
||||
</Link>
|
||||
<Link
|
||||
href="/about"
|
||||
className="font-mono text-xs text-slate-600 dark:text-slate-400 uppercase tracking-wider hover:text-cyan-600 dark:hover:text-cyan-400"
|
||||
>
|
||||
[ABOUT]
|
||||
</Link>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-l-4 border-cyan-700 dark:border-cyan-900 pl-6 mb-8">
|
||||
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">DOCUMENT LEVEL-1 // CLASSIFIED</p>
|
||||
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">
|
||||
DOCUMENT LEVEL-1 // CLASSIFIED
|
||||
</p>
|
||||
<h1 className="text-4xl md:text-6xl lg:text-7xl font-mono font-bold text-slate-900 dark:text-slate-100 uppercase tracking-tight mb-6">
|
||||
BUILD. WRITE.<br/>SHARE.
|
||||
BUILD. WRITE.
|
||||
<br />
|
||||
SHARE.
|
||||
</h1>
|
||||
<p className="text-base md:text-lg lg:text-xl text-slate-700 dark:text-slate-400 font-mono leading-relaxed max-w-2xl">
|
||||
> Explorează idei despre dezvoltare, design și tehnologie_
|
||||
@@ -42,10 +58,16 @@ export default async function HomePage() {
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4 flex-wrap mt-12">
|
||||
<Link href="/blog" className="px-6 md:px-8 py-3 md:py-4 bg-cyan-700 dark:bg-cyan-900 text-white dark:text-slate-100 border-2 border-cyan-600 dark:border-cyan-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-cyan-600 dark:hover:bg-cyan-800 hover:border-cyan-500 dark:hover:border-cyan-600 rounded-none transition-colors duration-200">
|
||||
<Link
|
||||
href="/blog"
|
||||
className="px-6 md:px-8 py-3 md:py-4 bg-cyan-700 dark:bg-cyan-900 text-white dark:text-slate-100 border-2 border-cyan-600 dark:border-cyan-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-cyan-600 dark:hover:bg-cyan-800 hover:border-cyan-500 dark:hover:border-cyan-600 rounded-none transition-colors duration-200"
|
||||
>
|
||||
[EXPLOREAZĂ BLOG]
|
||||
</Link>
|
||||
<Link href="/about" className="px-6 md:px-8 py-3 md:py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 rounded-none transition-colors duration-200">
|
||||
<Link
|
||||
href="/about"
|
||||
className="px-6 md:px-8 py-3 md:py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 rounded-none transition-colors duration-200"
|
||||
>
|
||||
[DESPRE MINE]
|
||||
</Link>
|
||||
</div>
|
||||
@@ -81,7 +103,9 @@ export default async function HomePage() {
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full bg-zinc-300 dark:bg-zinc-800 flex items-center justify-center">
|
||||
<span className="font-mono text-6xl text-slate-400 dark:text-slate-700">#{String(index + 1).padStart(2, '0')}</span>
|
||||
<span className="font-mono text-6xl text-slate-400 dark:text-slate-700">
|
||||
#{String(index + 1).padStart(2, '0')}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="absolute inset-0 bg-zinc-100/60 dark:bg-zinc-900/60"></div>
|
||||
|
||||
Reference in New Issue
Block a user