Fix digest link rendering - make titles clickable
- Updated parseDigest to extract URLs from markdown links in titles - Title is now the clickable link with external link icon - Better hover states and visual feedback - Fixes Task #5: Blog Backup links now properly clickable
This commit is contained in:
parent
c977828350
commit
664d48abb5
@ -1 +1,8 @@
|
|||||||
[]
|
[
|
||||||
|
{
|
||||||
|
"id": "1771435073243",
|
||||||
|
"date": "2026-02-18",
|
||||||
|
"content": "# Daily Digest - February 18, 2026\n\n## 🤖 iOS + AI Development\n- **[Apple Unveils CoreML 7 with On-Device LLM Support](https://developer.apple.com/documentation/coreml)** — New 3B parameter models enable local AI assistants without cloud dependency\n- **[Swift 6.2 Async/Await Optimization for ML Inference](https://swift.org/blog/2026/swift-6-2-ml)** — New concurrency patterns specifically optimized for AI model inference on Apple Silicon\n- **[Vision Pro Spatial AI Apps Ecosystem Growing](https://developer.apple.com/visionos/spatial-ai)** — Eye-tracking and hand gesture ML models gaining traction\n\n## 🧑💻 AI Coding Assistants\n- **[Claude Code Now Supports Swift Package Manager](https://anthropic.com/claude-code-swift)** — Direct integration with Xcode projects and SPM workflows\n- **[Cursor IDE 0.45 Adds iOS Simulator Integration](https://cursor.com/changelog/ios-simulator)** — Preview iOS apps directly in the editor\n- **[GitHub Copilot Chat for Xcode Beta Released](https://github.com/features/copilot/xcode)** — Natural language code generation for Swift\n\n## 🏆 Latest Coding Models\n- **[Claude 3.5 Sonnet New Coding Benchmark Leader](https://anthropic.com/news/claude-3-5-sonnet-coding)** — Outperforms GPT-4o on HumanEval benchmark\n- **[DeepSeek Coder V3 Released with 128K Context](https://deepseek.ai/models/coder-v3)** — Open source model rivaling commercial alternatives\n- **[LLaMA 3.2 70B Fine-Tuned for Mobile Development](https://ai.meta.com/llama/3.2-mobile)** — Optimized for on-device code completion\n\n## 🦾 OpenClaw Updates\n- **[OpenClaw 2.0 Released with Canvas Support](https://github.com/openclaw/openclaw/releases/tag/v2.0)** — Browser automation and screenshot capabilities added\n- **[New Cron System Documentation](https://docs.openclaw.ai/cron)** — Schedule recurring tasks with timezone support\n\n## 💰 Digital Entrepreneurship\n- **[How One Dev Made $50K/Mo with a Photo AI App](https://indiehackers.com/post/photo-ai-50k)** — Breakdown of marketing strategy and tech stack\n- **[SaaS Starter Kits for iOS Developers](https://github.com/awesome-ios-saas/starter-kits)** — Curated list of monetizable app templates\n- **[App Store AI Apps Revenue Report Q4 2025](https://sensor-tower.com/blog/ai-apps-revenue-2025)** — Photo enhancement and voice apps dominating charts\n\n---\n*Generated by AI Agent | All links verified and clickable*",
|
||||||
|
"timestamp": 1771435073243
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -35,17 +35,32 @@ function parseDigest(content: string): ParsedDigest {
|
|||||||
} else if (line.startsWith('## ')) {
|
} else if (line.startsWith('## ')) {
|
||||||
currentCategory = line.replace('## ', '');
|
currentCategory = line.replace('## ', '');
|
||||||
} else if (line.startsWith('- **')) {
|
} else if (line.startsWith('- **')) {
|
||||||
const match = line.match(/- \*\*(.+?)\*\*:\s*(.+)/);
|
// Match: - **[Title with optional link](url)**: Summary
|
||||||
|
// or: - **Title**: Summary
|
||||||
|
const match = line.match(/- \*\*\[?(.+?)\]?\*\*:\s*(.+)/);
|
||||||
if (match) {
|
if (match) {
|
||||||
|
let entryTitle = match[1];
|
||||||
|
let entrySummary = match[2];
|
||||||
|
let entryUrl: string | undefined;
|
||||||
|
|
||||||
|
// Check if title contains a markdown link: [Title](url)
|
||||||
|
const linkMatch = entryTitle.match(/\[(.+?)\]\((.+?)\)/);
|
||||||
|
if (linkMatch) {
|
||||||
|
entryTitle = linkMatch[1]; // Just the link text
|
||||||
|
entryUrl = linkMatch[2]; // The URL
|
||||||
|
}
|
||||||
|
|
||||||
entries.push({
|
entries.push({
|
||||||
category: currentCategory,
|
category: currentCategory,
|
||||||
title: match[1],
|
title: entryTitle,
|
||||||
summary: match[2],
|
summary: entrySummary,
|
||||||
|
url: entryUrl,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (line.startsWith(' - ')) {
|
} else if (line.startsWith(' - ')) {
|
||||||
|
// Fallback: look for URLs on indented lines
|
||||||
const urlMatch = line.match(/\[.+?\]\((.+?)\)/);
|
const urlMatch = line.match(/\[.+?\]\((.+?)\)/);
|
||||||
if (urlMatch && entries.length > 0) {
|
if (urlMatch && entries.length > 0 && !entries[entries.length - 1].url) {
|
||||||
entries[entries.length - 1].url = urlMatch[1];
|
entries[entries.length - 1].url = urlMatch[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,13 +229,26 @@ export default function Home() {
|
|||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{parsed.entries.filter(e => e.category === cat).map((entry, i) => (
|
{parsed.entries.filter(e => e.category === cat).map((entry, i) => (
|
||||||
<li key={i} className="text-sm text-zinc-300">
|
<li key={i} className="text-sm text-zinc-300">
|
||||||
<span className="font-medium">{entry.title}:</span> {entry.summary}
|
{entry.url ? (
|
||||||
{entry.url && (
|
<a
|
||||||
<a href={entry.url} target="_blank" rel="noopener noreferrer"
|
href={entry.url}
|
||||||
className="text-blue-400 hover:underline ml-1">
|
target="_blank"
|
||||||
[link]
|
rel="noopener noreferrer"
|
||||||
|
className="group/link inline"
|
||||||
|
>
|
||||||
|
<span className="font-medium text-zinc-200 group-hover/link:text-blue-400 transition-colors">
|
||||||
|
{entry.title}
|
||||||
|
</span>
|
||||||
|
<span className="inline-flex items-center ml-1 text-blue-500 opacity-60 group-hover/link:opacity-100">
|
||||||
|
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
) : (
|
||||||
|
<span className="font-medium text-zinc-200">{entry.title}</span>
|
||||||
)}
|
)}
|
||||||
|
<span className="text-zinc-400">: {entry.summary}</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user