chore: remove unused images, update project image paths to webp format, and enhance accessibility with aria-labels across components
This commit is contained in:
@@ -7,7 +7,7 @@ function BuyMeCoffee({ classname }: { classname?: string }) {
|
||||
href='https://ko-fi.com/cojoo'
|
||||
target='_blank'
|
||||
className={cn(
|
||||
'border relative group w-36 mx-auto cursor-pointer h-32 grid place-content-center p-10 py-14 bg-primary rounded-md overflow-hidden',
|
||||
'border relative group w-36 mx-auto cursor-pointer h-32 grid place-content-center p-10 py-14 bg-primary rounded-md overflow-hidden',
|
||||
classname
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -84,7 +84,7 @@ const Navbar = () => {
|
||||
<>
|
||||
<motion.header
|
||||
aria-label="Navigation"
|
||||
role="navigation"
|
||||
role="banner"
|
||||
layout={!isMobile}
|
||||
initial={sizeVariants[0]}
|
||||
animate={isMobile ? sizeVariants[0] : sizeVariants[scrollLevel]}
|
||||
@@ -113,7 +113,6 @@ const Navbar = () => {
|
||||
className="font-custom flex shrink-0 items-center gap-2 text-xl font-bold"
|
||||
aria-label="Home"
|
||||
title="Home"
|
||||
navigation="true"
|
||||
>
|
||||
<Logo className="h-8 w-8" />
|
||||
<span className={
|
||||
@@ -123,7 +122,7 @@ const Navbar = () => {
|
||||
</Link>
|
||||
|
||||
<div className="flex items-center gap-2 md:gap-4">
|
||||
<nav className="hidden items-center gap-6 md:flex" aria-label="Main navigation" role="navigation">
|
||||
<nav className="hidden items-center gap-6 md:flex" aria-label="Main navigation">
|
||||
{NAV_LINKS.map((item) => {
|
||||
const isActive = activePath.startsWith(item.href) && item.href !== "/";
|
||||
return (
|
||||
|
||||
@@ -11,9 +11,8 @@ function Logo({ className }: { className?: string }) {
|
||||
)}
|
||||
role="img"
|
||||
aria-label="Logo"
|
||||
aria-hidden="true"
|
||||
name="logo"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
>
|
||||
<path
|
||||
d="M0 0h216.667C290.305 0 350 59.546 350 133s-59.695 133-133.333 133L0 0zm231.629 231.641c48.131-7.203 85.038-48.623 85.038-98.641 0-55.09-44.772-99.75-100-99.75h-54.862C185.557 59.722 200 94.678 200 133c0 17.331-2.96 33.991-8.405 49.492l40.034 49.149zm-66.243-81.326c.844-5.646 1.281-11.428 1.281-17.315 0-42.333-22.66-79.386-56.541-99.75H70.032l95.354 117.065z"
|
||||
|
||||
@@ -8,6 +8,7 @@ export const SITE: Site = {
|
||||
author: 'Cojocaru David',
|
||||
locale: 'en-US',
|
||||
location: 'Romania',
|
||||
email: 'contact@cojocarudavid.me'
|
||||
}
|
||||
|
||||
export const NAV_LINKS: SocialLink[] = [
|
||||
|
||||
@@ -97,7 +97,7 @@ export default function ThemeToggle() {
|
||||
localStorage.setItem("theme", newTheme);
|
||||
};
|
||||
|
||||
return <button onClick={toggleTheme}>{theme === "light" ? "🌙" : "🌞"}</button>;
|
||||
return <button onClick={toggleTheme} aria-label="Toggle theme">{theme === "light" ? "🌙" : "🌞"}</button>;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -123,8 +123,8 @@ Create `index.html` in the same folder. Paste and save.
|
||||
<body>
|
||||
<h1>💬 Mini Chat</h1>
|
||||
<div id="chat"></div>
|
||||
<input id="msgBox" placeholder="Type and hit Enter">
|
||||
<button onclick="sendMsg()">Send</button>
|
||||
<input id="msgBox" placeholder="Type and hit Enter" aria-label="Message input">
|
||||
<button onclick="sendMsg()" aria-label="Send message">Send</button>
|
||||
|
||||
<script>
|
||||
const socket = new WebSocket('ws://localhost:8080');
|
||||
|
||||
@@ -109,7 +109,7 @@ const Task = ({ task, onDelete, onToggle }) => {
|
||||
/>
|
||||
<span>{task.text}</span>
|
||||
</div>
|
||||
<button onClick={() => onDelete(task.id)} className="delete-btn">
|
||||
<button onClick={() => onDelete(task.id)} className="delete-btn" aria-label="Delete task">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
@@ -187,7 +187,7 @@ const TaskForm = ({ onAdd }) => {
|
||||
placeholder="What needs to be done?"
|
||||
className="task-input"
|
||||
/>
|
||||
<button type="submit" className="add-btn">
|
||||
<button type="submit" className="add-btn" aria-label="Add task">
|
||||
Add Task
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -127,9 +127,9 @@ Open `index.html` and paste this:
|
||||
<h1>🌤️ Weather Check</h1>
|
||||
|
||||
<div class="search-box">
|
||||
<input type="text" id="city-input" placeholder="Enter city name...">
|
||||
<button id="search-btn">Search</button>
|
||||
<button id="location-btn">Use My Location</button>
|
||||
<input type="text" id="city-input" placeholder="Enter city name..." aria-label="City input">
|
||||
<button id="search-btn" aria-label="Search">Search</button>
|
||||
<button id="location-btn" aria-label="Use my location">Use My Location</button>
|
||||
</div>
|
||||
|
||||
<div id="weather-info" class="hidden">
|
||||
|
||||
6
src/content/blog/what-is-tailwind/index.mdx
vendored
6
src/content/blog/what-is-tailwind/index.mdx
vendored
@@ -51,7 +51,7 @@ Instead of writing CSS like:
|
||||
I just typed:
|
||||
|
||||
```html
|
||||
<button class="px-8 py-3 bg-blue-500 text-white rounded-lg font-semibold hover:bg-blue-600 transition">
|
||||
<button class="px-8 py-3 bg-blue-500 text-white rounded-lg font-semibold hover:bg-blue-600 transition" aria-label="Get started">
|
||||
Get Started
|
||||
</button>
|
||||
```
|
||||
@@ -420,7 +420,7 @@ Let's build something useful. A **responsive card** that looks great everywhere.
|
||||
<div class="p-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900">Card Title</h3>
|
||||
<p class="mt-2 text-gray-600">Brief description here</p>
|
||||
<button class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
|
||||
<button class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" aria-label="Learn more">
|
||||
Learn More
|
||||
</button>
|
||||
</div>
|
||||
@@ -432,7 +432,7 @@ Let's build something useful. A **responsive card** that looks great everywhere.
|
||||
```html
|
||||
<!-- Changes to horizontal layout on desktop -->
|
||||
<div class="max-w-4xl mx-auto md:flex">
|
||||
<img class="md:w-48 md:h-auto" src="/img.jpg">
|
||||
<img class="md:w-48 md:h-auto" src="/img.jpg" alt="Card image">
|
||||
<div class="p-6">
|
||||
<!-- Same content, now horizontal -->
|
||||
</div>
|
||||
|
||||
@@ -103,12 +103,12 @@ Without dimensions, the browser can't reserve space. When the image finally load
|
||||
|
||||
Good:
|
||||
```html
|
||||
<img src="dog.jpg" width="800" height="450" loading="lazy">
|
||||
<img src="dog.jpg" width="800" height="450" loading="lazy" alt="Dog">
|
||||
```
|
||||
|
||||
Bad:
|
||||
```html
|
||||
<img src="dog.jpg" loading="lazy">
|
||||
<img src="dog.jpg" loading="lazy" alt="Dog">
|
||||
```
|
||||
|
||||
### **Mistake 3: Overdoing Fade-In Animations**
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: 'cojocarudavid.me (old)'
|
||||
description: 'Blazing fast personal website built with Astro.js and styled with Tailwind CSS.'
|
||||
tags: ['astro', 'tailwindcss', 'typescript']
|
||||
image: '../../../public/static/cojocarudavidme.png'
|
||||
image: '../../../public/static/cojocarudavidme.webp'
|
||||
link: 'https://github.com/cojocaru-david/cojocarudavid.me'
|
||||
startDate: '2023-10-16'
|
||||
endDate: '2025-04-28'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: 'David Dark Code'
|
||||
description: 'David Dark is a dark theme for VS Code. It is based on the github theme and the default dark theme. It is designed to be easy on the eyes and to be used for long periods of time.'
|
||||
tags: ['vscode', 'theme', 'dark']
|
||||
image: '../../../public/static/david-dark-code.png'
|
||||
image: '../../../public/static/david-dark-code.webp'
|
||||
link: 'https://github.com/cojocaru-david/david-dark-code'
|
||||
startDate: '2023-10-17'
|
||||
endDate: '2023-10-17'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: 'Dream Home Template'
|
||||
description: 'A modern, responsive real estate platform built with React, Vite, and Tailwind CSS. Find your dream home with intuitive search, detailed property listings, and seamless user experience.'
|
||||
tags: ['react', 'vite', 'tailwindcss']
|
||||
image: '../../../public/static/dream-home-template.png'
|
||||
image: '../../../public/static/dream-home-template.webp'
|
||||
link: 'https://dreamhome.cojocarudavid.me'
|
||||
startDate: '2025-04-16'
|
||||
endDate: '2025-05-29'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: 'Modern Portfolio'
|
||||
description: 'Modern Portfolio is a personal website that showcases my work and projects. It is built with Astro.js and styled with Tailwind CSS, providing a fast and responsive user experience. The website features a clean design, easy navigation, and a focus on showcasing my skills and projects.'
|
||||
tags: ['astro', 'tailwindcss', 'typescript']
|
||||
image: '../../../public/static/modern-portfolio.png'
|
||||
image: '../../../public/static/modern-portfolio.webp'
|
||||
link: 'https://cojocarudavid.me'
|
||||
startDate: '2025-03-30'
|
||||
---
|
||||
|
||||
48
src/content/projects/snippetslibrary.md
Normal file
48
src/content/projects/snippetslibrary.md
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
name: 'SnippetsLibrary'
|
||||
description: 'A secure, lightning-fast code snippet manager to store, organize, and share your code with beautiful syntax highlighting.'
|
||||
tags: ['react', 'vite', 'tailwindcss', 'typescript', 'bun', 'hono', 'drizzle-orm', 'postgresql', 'jwt', 'github-oauth', 'cloudflare-workers']
|
||||
image: '../../../public/static/snippetslibrary.webp'
|
||||
link: 'https://snippetslibrary.com'
|
||||
startDate: '2025-07-23'
|
||||
---
|
||||
|
||||
# SnippetsLibrary
|
||||
|
||||
Manage your personal and team code snippets with speed and confidence. SnippetsLibrary makes it easy to create, organize, search, and share snippets with first-class DX and beautiful syntax highlighting.
|
||||
|
||||
I have 50+ users and I'm working on a new version with a lot of new features.
|
||||
And 200+ snippets.
|
||||
|
||||
## ✨ Highlights
|
||||
|
||||
- **Secure auth**: GitHub OAuth + JWT sessions
|
||||
- **Sharing**: Public share links with SEO-friendly pages
|
||||
- **Search & filter**: Language, visibility, keywords, pagination
|
||||
- **Syntax highlighting**: 20+ languages, themes, copy-preserving formatting
|
||||
- **Fast**: Bun runtime, Hono server, optimized client with Vite
|
||||
|
||||
## 🛠️ Tech Stack
|
||||
|
||||
- Frontend: React, Vite, Tailwind CSS, shadcn/ui
|
||||
- Backend: Bun, Hono, JWT, Drizzle ORM, PostgreSQL
|
||||
- Infra: Cloudflare Workers, GitHub Actions, Drizzle Kit
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
1. Clone the repo:
|
||||
```bash
|
||||
git clone https://github.com/cojocaru-david/snippetslibrary.com
|
||||
cd snippetslibrary.com
|
||||
```
|
||||
2. Install deps: `bun install`
|
||||
3. Configure `.env` in `server/` (DB, GitHub OAuth, JWT, FRONTEND_URL)
|
||||
4. Migrate DB: `cd server && bun run db:migrate`
|
||||
5. Start dev: `bun run dev` (client on 5173, server on 8000)
|
||||
|
||||
## 🔗 Links
|
||||
|
||||
- Live: https://snippetslibrary.com
|
||||
- Repo: https://github.com/cojocaru-david/snippetslibrary.com
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: 'TailCI'
|
||||
description: 'TailCI is a lightweight, fast, and modern web application built with CodeIgniter and styled with Tailwind CSS. It combines the simplicity of CodeIgniter’s PHP framework with the utility-first power of Tailwind CSS for rapid development and clean design.'
|
||||
tags: ['codeigniter', 'tailwindcss', 'php']
|
||||
image: '../../../public/static/tailci.png'
|
||||
image: '../../../public/static/tailci.webp'
|
||||
link: 'https://tailci.cojocarudavid.me'
|
||||
startDate: '2025-03-30'
|
||||
---
|
||||
|
||||
@@ -107,7 +107,7 @@ const canonicalUrl = new URL(`/blog/${post.id}/`, Astro.site).toString();
|
||||
|
||||
{headings.length > 0 && <TableOfContents headings={headings} />}
|
||||
|
||||
<article class="prose col-start-2 max-w-none">
|
||||
<article class="prose col-start-2 max-w-none" aria-label="Blog post">
|
||||
<Content />
|
||||
</article>
|
||||
|
||||
@@ -137,7 +137,7 @@ const canonicalUrl = new URL(`/blog/${post.id}/`, Astro.site).toString();
|
||||
title="Share on Facebook"
|
||||
aria-label="Share on Facebook"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" aria-label="Share on Facebook">
|
||||
<Icon name="line-md:facebook" class="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
@@ -148,7 +148,7 @@ const canonicalUrl = new URL(`/blog/${post.id}/`, Astro.site).toString();
|
||||
title="Share on Twitter"
|
||||
aria-label="Share on Twitter"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" aria-label="Share on Twitter">
|
||||
<Icon name="line-md:twitter" class="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
@@ -159,7 +159,7 @@ const canonicalUrl = new URL(`/blog/${post.id}/`, Astro.site).toString();
|
||||
title="Share on LinkedIn"
|
||||
aria-label="Share on LinkedIn"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" aria-label="Share on LinkedIn">
|
||||
<Icon name="line-md:linkedin" class="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
@@ -170,7 +170,7 @@ const canonicalUrl = new URL(`/blog/${post.id}/`, Astro.site).toString();
|
||||
title="Share on Reddit"
|
||||
aria-label="Share on Reddit"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" aria-label="Share on Reddit">
|
||||
<Icon name="line-md:reddit-loop" class="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
@@ -181,7 +181,7 @@ const canonicalUrl = new URL(`/blog/${post.id}/`, Astro.site).toString();
|
||||
title="Share on WhatsApp"
|
||||
aria-label="Share on WhatsApp"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" aria-label="Share on WhatsApp">
|
||||
<Icon name="mdi:whatsapp" class="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
@@ -192,7 +192,7 @@ const canonicalUrl = new URL(`/blog/${post.id}/`, Astro.site).toString();
|
||||
title="Share on Telegram"
|
||||
aria-label="Share on Telegram"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" aria-label="Share on Telegram">
|
||||
<Icon name="line-md:telegram" class="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
@@ -203,7 +203,7 @@ const canonicalUrl = new URL(`/blog/${post.id}/`, Astro.site).toString();
|
||||
title="Share on Pinterest"
|
||||
aria-label="Share on Pinterest"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" aria-label="Share on Pinterest">
|
||||
<Icon name="mdi:pinterest" class="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
@@ -88,16 +88,16 @@ const currentUrl = Astro.url;
|
||||
<Image
|
||||
src={project.data.image}
|
||||
alt={project.data.name}
|
||||
class="col-start-2 mb-8 h-auto w-full rounded-3xl object-cover"
|
||||
class="col-start-2 mb-8 h-[500px] w-full rounded-3xl object-cover"
|
||||
loading="lazy"
|
||||
fetchpriority="low"
|
||||
width={1800}
|
||||
height={1600}
|
||||
width={1200}
|
||||
height={800}
|
||||
/>
|
||||
|
||||
{headings.length > 0 && <TableOfContents headings={headings} />}
|
||||
|
||||
<article class="prose col-start-2 max-w-none">
|
||||
<article class="prose col-start-2 max-w-none" aria-label="Project">
|
||||
<Content />
|
||||
</article>
|
||||
|
||||
@@ -116,7 +116,7 @@ const currentUrl = Astro.url;
|
||||
<h3 class="text-base font-semibold">Project Links</h3>
|
||||
<ul class="list-disc pl-4">
|
||||
<li>
|
||||
<a href={project.data.link} target="_blank" rel="noopener noreferrer">
|
||||
<a href={project.data.link} target="_blank" rel="noopener noreferrer" aria-label="Project link">
|
||||
{project.data.link}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -58,7 +58,7 @@ const currentUrl = Astro.url;
|
||||
<div
|
||||
class="group h-full w-full transition-all duration-300 hover:translate-y-[-4px] even:sm:mt-14"
|
||||
>
|
||||
<a class="flex flex-col h-full w-full rounded-2xl overflow-hidden bg-card hover:shadow-lg transition-all duration-300 border border-card-foreground/10" href={`/projects/${project.id}`}>
|
||||
<a class="flex flex-col h-full w-full rounded-2xl overflow-hidden bg-card hover:shadow-lg transition-all duration-300 border border-card-foreground/10" href={`/projects/${project.id}`} aria-label="Project link">
|
||||
<div
|
||||
class="aspect-[16/10] w-full overflow-hidden"
|
||||
>
|
||||
|
||||
@@ -1,43 +1,50 @@
|
||||
import { SITE } from '@/consts'
|
||||
import rss from '@astrojs/rss'
|
||||
import type { APIContext } from 'astro'
|
||||
import { getAllPosts } from '@/lib/data-utils'
|
||||
import { SITE } from '@/consts';
|
||||
import rss from '@astrojs/rss';
|
||||
import type { APIRoute } from 'astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
export async function GET(context: APIContext) {
|
||||
export const GET: APIRoute = async ({ site }) => {
|
||||
try {
|
||||
const posts = await getAllPosts()
|
||||
const blogPosts = await getCollection('blog');
|
||||
const posts = blogPosts
|
||||
.filter((post) => !post.data.draft)
|
||||
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
||||
|
||||
const now = new Date();
|
||||
const lastBuildDate = posts.length > 0 ? posts[0].data.date : now;
|
||||
|
||||
return rss({
|
||||
title: `${SITE.title} - Tech Blog`,
|
||||
description: SITE.description,
|
||||
site: context.site ?? SITE.href,
|
||||
site: site ?? SITE.href.replace(/\/$/, ''),
|
||||
trailingSlash: false,
|
||||
customData: `
|
||||
<language>${SITE.locale || 'en-us'}</language>
|
||||
<lastBuildDate>${lastBuildDate.toUTCString()}</lastBuildDate>
|
||||
<ttl>60</ttl>
|
||||
<managingEditor>${SITE.author} (${SITE.email || 'contact@cojocarudavid.me'})</managingEditor>
|
||||
<webMaster>${SITE.author} (${SITE.email || 'contact@cojocarudavid.me'})</webMaster>
|
||||
<image>
|
||||
<url>${new URL('/ogImage.png', site ?? SITE.href).href}</url>
|
||||
<title>${SITE.title}</title>
|
||||
<link>${site ?? SITE.href}</link>
|
||||
</image>
|
||||
<atom:link href="${new URL('/rss.xml', site ?? SITE.href).href}" rel="self" type="application/rss+xml" />
|
||||
`.trim(),
|
||||
xmlns: {
|
||||
atom: 'http://www.w3.org/2005/Atom'
|
||||
},
|
||||
items: posts.map((post) => ({
|
||||
title: post.data.title,
|
||||
description: post.data.description,
|
||||
description: post.data.description || '',
|
||||
pubDate: post.data.date,
|
||||
link: `/blog/${post.id}/`,
|
||||
categories: post.data.tags || [],
|
||||
author: post.data.authors ? post.data.authors.join(', ') : SITE.author,
|
||||
customData: `
|
||||
<language>${SITE.locale}</language>
|
||||
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
|
||||
${post.data.tags ? `<category>${post.data.tags.join(', ')}</category>` : ''}
|
||||
`.trim(),
|
||||
})),
|
||||
customData: `
|
||||
<language>${SITE.locale}</language>
|
||||
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
|
||||
<ttl>60</ttl>
|
||||
<image>
|
||||
<url>${new URL('/ogImage.png', SITE.href).toString()}</url>
|
||||
<title>${SITE.title}</title>
|
||||
<link>${SITE.href}</link>
|
||||
</image>
|
||||
`.trim(),
|
||||
})
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error generating RSS feed:', error)
|
||||
return new Response('Error generating RSS feed', { status: 500 })
|
||||
console.error('Error generating RSS feed:', error);
|
||||
return new Response('Error generating RSS feed', { status: 500 });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -118,17 +118,5 @@
|
||||
@apply text-foreground bg-muted border-border rounded-md border px-3 py-1 font-mono text-xs font-medium shadow-sm;
|
||||
@apply [&>span[data-line='']>*]:text-(--shiki-light) dark:[&>span[data-line='']>*]:text-(--shiki-dark);
|
||||
}
|
||||
|
||||
.katex-display {
|
||||
@apply my-8 overflow-x-auto overflow-y-hidden py-3 tracking-normal;
|
||||
@apply [&>span[data-line='']>*]:text-(--shiki-light) dark:[&>span[data-line='']>*]:text-(--shiki-dark);
|
||||
}
|
||||
|
||||
.katex {
|
||||
@apply text-foreground;
|
||||
}
|
||||
.katex * {
|
||||
@apply text-foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ export type Site = {
|
||||
author: string
|
||||
locale: string
|
||||
location: string
|
||||
email: string
|
||||
}
|
||||
|
||||
export type SocialLink = {
|
||||
|
||||
Reference in New Issue
Block a user