feat: add tools section with MarkItDown, update Caddyfile for md subdomain
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
const tools = [
|
||||
{
|
||||
id: '01',
|
||||
title: 'MarkItDown',
|
||||
desc: 'Convert any document to Markdown. Drop a PDF, DOCX, PPTX, XLSX, HTML, or CSV and get clean Markdown output instantly.',
|
||||
tags: ['python', 'fastapi', 'markitdown'],
|
||||
url: 'https://md.carloselugo.com',
|
||||
status: 'live',
|
||||
},
|
||||
]
|
||||
|
||||
const statusLabel = {
|
||||
live: { text: 'live', color: '#c8ff00' },
|
||||
wip: { text: 'wip', color: '#ff6b35' },
|
||||
}
|
||||
|
||||
export function renderTools() {
|
||||
const cards = tools.map(t => {
|
||||
const s = statusLabel[t.status]
|
||||
return `
|
||||
<a class="tool-card reveal" href="${t.url}" target="_blank" rel="noopener">
|
||||
<div class="card-top">
|
||||
<span class="card-id mono">${t.id}</span>
|
||||
<span class="card-status mono" style="color:${s.color}">● ${s.text}</span>
|
||||
</div>
|
||||
<h3 class="card-title">${t.title}</h3>
|
||||
<p class="card-desc">${t.desc}</p>
|
||||
<div class="tool-bottom">
|
||||
<div class="card-tags">
|
||||
${t.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
|
||||
</div>
|
||||
<span class="tool-link mono">open ↗</span>
|
||||
</div>
|
||||
</a>
|
||||
`
|
||||
}).join('')
|
||||
|
||||
return `
|
||||
<section class="tools" id="tools">
|
||||
<div class="container">
|
||||
<div class="section-head reveal">
|
||||
<div class="accent-line"></div>
|
||||
<h2 class="section-title">Tools</h2>
|
||||
<p class="section-sub">Self-hosted utilities running on the homelab.</p>
|
||||
</div>
|
||||
<div class="tool-grid">
|
||||
${cards}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.tools { padding: 0 0 100px; }
|
||||
.section-sub {
|
||||
font-size: 0.88rem;
|
||||
color: var(--muted);
|
||||
margin-top: 8px;
|
||||
}
|
||||
.tool-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1px;
|
||||
background: var(--border);
|
||||
border: 1px solid var(--border);
|
||||
margin-top: 48px;
|
||||
}
|
||||
.tool-card {
|
||||
background: var(--bg-card);
|
||||
padding: 32px;
|
||||
transition: background 0.2s;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
.tool-card:hover { background: #161616; }
|
||||
.tool-card:hover .tool-link { color: var(--accent); letter-spacing: 0.12em; }
|
||||
.tool-bottom {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
gap: 12px;
|
||||
}
|
||||
.tool-link {
|
||||
font-size: 0.72rem;
|
||||
color: var(--muted);
|
||||
white-space: nowrap;
|
||||
transition: color 0.2s, letter-spacing 0.2s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import './style.css'
|
||||
import { renderHeader } from './components/header.js'
|
||||
import { renderHero } from './components/hero.js'
|
||||
import { renderProjects } from './components/projects.js'
|
||||
import { renderTools } from './components/tools.js'
|
||||
import { renderBlog, initBlog } from './components/blog.js'
|
||||
import { renderFooter } from './components/footer.js'
|
||||
|
||||
@@ -12,6 +13,7 @@ app.innerHTML = `
|
||||
<main>
|
||||
${renderHero()}
|
||||
${renderProjects()}
|
||||
${renderTools()}
|
||||
${renderBlog()}
|
||||
</main>
|
||||
${renderFooter()}
|
||||
|
||||
Reference in New Issue
Block a user