feat: implement comprehensive UI/UX improvements
This commit implements 7 requested improvements: 1. Add footer component to all pages - Created reusable AppFooter component - Added to layout.tsx with flex-1 main container - Includes links to Legal, Disclaimer, Imprint, GitHub 2. Change search highlight from yellow to more discreet color - Updated mark styling with purple theme colors - Uses color-mix for theme-aware transparency - Added subtle border-bottom for better visibility 3. Strip markdown from search results - Created stripMarkdown function - Removes HTML tags, markdown links, images, formatting - Shows clean text descriptions only 4. Add page number links to pagination - Created getPageNumbers function with smart ellipsis - Shows current page ±2 pages with first/last always visible - Example: 1 ... 5 6 [7] 8 9 ... 20 5. Adjust README badge display to be inline - Custom marked renderer detects badges (shields.io, badgen, etc.) - Applies inline-block with !my-0 !mx-1 align-middle classes - Badges now display inline in paragraph flow 6. Fix relative image URLs in READMEs - Custom image renderer converts relative to absolute GitHub URLs - Handles ./path and path patterns - Converts to raw.githubusercontent.com URLs - Also handles /blob/ URLs conversion 7. Fix command menu highlight contrast - Reuses mark styling from search highlights - Consistent purple theme colors across app 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
37
components/layout/app-footer.tsx
Normal file
37
components/layout/app-footer.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
export function AppFooter() {
|
||||
return (
|
||||
<footer className="border-t border-border/40 px-6 py-12 lg:px-8">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="flex flex-col items-center justify-between gap-4 sm:flex-row">
|
||||
<div className="text-center sm:text-left">
|
||||
<div className="gradient-text mb-2 text-xl font-bold">Awesome</div>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Built with 💜💗💛 and maximum awesomeness
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap justify-center gap-6 text-sm">
|
||||
<Link href="/legal" className="text-muted-foreground hover:text-primary">
|
||||
Legal
|
||||
</Link>
|
||||
<Link href="/disclaimer" className="text-muted-foreground hover:text-primary">
|
||||
Disclaimer
|
||||
</Link>
|
||||
<Link href="/imprint" className="text-muted-foreground hover:text-primary">
|
||||
Imprint
|
||||
</Link>
|
||||
<a
|
||||
href="https://github.com/sindresorhus/awesome"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-muted-foreground hover:text-primary"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
@@ -8,9 +8,10 @@ import 'highlight.js/styles/github-dark.css'
|
||||
|
||||
interface ReadmeViewerProps {
|
||||
content: string
|
||||
repositoryUrl?: string
|
||||
}
|
||||
|
||||
export function ReadmeViewer({ content }: ReadmeViewerProps) {
|
||||
export function ReadmeViewer({ content, repositoryUrl }: ReadmeViewerProps) {
|
||||
const [html, setHtml] = React.useState('')
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -30,13 +31,59 @@ export function ReadmeViewer({ content }: ReadmeViewerProps) {
|
||||
breaks: true,
|
||||
})
|
||||
|
||||
// Custom renderer to fix relative image URLs
|
||||
if (repositoryUrl) {
|
||||
const renderer = {
|
||||
image(href: string, title: string | null, text: string) {
|
||||
let imgSrc = href
|
||||
|
||||
// Convert GitHub URLs to raw content URLs
|
||||
if (repositoryUrl.includes('github.com')) {
|
||||
const match = repositoryUrl.match(/github\.com\/([^\/]+)\/([^\/]+)/)
|
||||
if (match) {
|
||||
const [, owner, repo] = match
|
||||
const cleanRepo = repo.replace(/\.git$/, '')
|
||||
|
||||
// Handle relative URLs
|
||||
if (!imgSrc.startsWith('http://') && !imgSrc.startsWith('https://') && !imgSrc.startsWith('//')) {
|
||||
// Remove leading ./
|
||||
imgSrc = imgSrc.replace(/^\.\//, '')
|
||||
// Build raw GitHub URL (main/master branch assumed)
|
||||
imgSrc = `https://raw.githubusercontent.com/${owner}/${cleanRepo}/master/${imgSrc}`
|
||||
}
|
||||
// Handle GitHub blob URLs - convert to raw
|
||||
else if (imgSrc.includes('github.com') && imgSrc.includes('/blob/')) {
|
||||
imgSrc = imgSrc.replace('github.com', 'raw.githubusercontent.com').replace('/blob/', '/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const titleAttr = title ? ` title="${title}"` : ''
|
||||
|
||||
// Check if it's a badge (shields.io, badgen, etc.)
|
||||
const isBadge = imgSrc.includes('shields.io') ||
|
||||
imgSrc.includes('badgen.net') ||
|
||||
imgSrc.includes('badge') ||
|
||||
imgSrc.includes('img.shields') ||
|
||||
imgSrc.match(/\/badges?\//)
|
||||
|
||||
if (isBadge) {
|
||||
return `<img src="${imgSrc}" alt="${text}" ${titleAttr} class="inline-block !my-0 !mx-1 align-middle" />`
|
||||
}
|
||||
|
||||
return `<img src="${imgSrc}" alt="${text}" ${titleAttr} />`
|
||||
}
|
||||
}
|
||||
marked.use({ renderer })
|
||||
}
|
||||
|
||||
// Parse markdown
|
||||
const parseMarkdown = async () => {
|
||||
const result = await marked.parse(content)
|
||||
setHtml(result)
|
||||
}
|
||||
parseMarkdown()
|
||||
}, [content])
|
||||
}, [content, repositoryUrl])
|
||||
|
||||
return (
|
||||
<article
|
||||
|
||||
Reference in New Issue
Block a user