218 lines
13 KiB
TypeScript
218 lines
13 KiB
TypeScript
import type { Metadata } from 'next'
|
|
import Link from 'next/link'
|
|
import SeoFooter from '@/components/seo/SeoFooter'
|
|
import SeoNavbar from '@/components/seo/SeoNavbar'
|
|
import { siteConfig } from '@/lib/site'
|
|
|
|
const repositoryUrl = 'https://github.com/knuthtimo-lab/greenlenspro-cli'
|
|
|
|
export const metadata: Metadata = {
|
|
title: 'Developer Suite & Open Source Tools',
|
|
description: 'Official GreenLens developer tools: VS Code extension, Python SDK and CLI, Node.js CLI, Chrome extension, and GitHub Action.',
|
|
alternates: { canonical: '/developers' },
|
|
openGraph: {
|
|
title: 'Developer Suite & Open Source Tools | GreenLens',
|
|
description: 'Open-source GreenLens tools for VS Code, Python, Node.js, Chrome, and GitHub Actions.',
|
|
url: `${siteConfig.domain}/developers`,
|
|
type: 'website',
|
|
},
|
|
twitter: {
|
|
card: 'summary_large_image',
|
|
title: 'Developer Suite & Open Source Tools | GreenLens',
|
|
description: 'Open-source GreenLens tools for VS Code, Python, Node.js, Chrome, and GitHub Actions.',
|
|
},
|
|
}
|
|
|
|
const engineeringPosts = [
|
|
{ slug: 'vision-ai-plant-disease-diagnostic', title: 'Building a Plant Disease Diagnostic Engine with Vision AI & Multi-Symptom Scoring', readTime: '8 min read' },
|
|
{ slug: 'chrome-extension-manifest-v3-image-scanner', title: 'How to Build a Lightweight Chrome Extension (Manifest V3) for Real-Time Image & Canvas Inspection', readTime: '7 min read' },
|
|
{ slug: 'zero-dependency-python-sdk', title: 'Designing a Zero-Dependency Python SDK for REST APIs with Automatic Retries & Rate-Limit Backoff', readTime: '7 min read' },
|
|
{ slug: 'react-native-offline-first-sync', title: 'Offline-First Mobile Architecture: Syncing Local SQLite Storage with Remote AI Services in React Native', readTime: '8 min read' },
|
|
{ slug: 'typescript-cli-automation-tool', title: 'Building a CLI Tool in TypeScript for Automated Image & Asset Diagnostic Workflows', readTime: '6 min read' },
|
|
{ slug: 'computer-vision-edge-cases-plant-health', title: 'Computer Vision Edge Cases: Why Plant Models Agree on Species But Disagree on Health', readTime: '7 min read' },
|
|
{ slug: 'programmatic-seo-nextjs-app-router', title: 'Programmatic SEO Infrastructure with Next.js App Router: Type-Safe Page Factories', readTime: '7 min read' },
|
|
{ slug: 'automated-content-syndication-engine', title: 'Automated Content Syndication: Publishing Developer Posts to DEV.to and Hashnode', readTime: '6 min read' },
|
|
{ slug: 'cross-platform-design-system-tokens', title: 'Building a Cross-Platform Design System for Web (Next.js) and Mobile (React Native)', readTime: '7 min read' },
|
|
]
|
|
|
|
const tools = [
|
|
{
|
|
icon: '💻',
|
|
eyebrow: 'VS Code Marketplace',
|
|
title: 'VS Code extension',
|
|
description: 'Search plant care, diagnose leaf symptoms, and set hydration-break timers without leaving VS Code.',
|
|
command: 'Ctrl+Shift+P → GreenLens: Search Houseplant Care',
|
|
href: 'https://marketplace.visualstudio.com/items?itemName=TimoKnuth.greenlens-vscode',
|
|
linkLabel: 'VS Code Marketplace',
|
|
},
|
|
{
|
|
icon: '🐍',
|
|
eyebrow: 'Python SDK & CLI',
|
|
title: 'Python SDK and CLI',
|
|
description: 'Use the greenlens-python package in applications or call greenlens-py directly for care guides, light evaluations, and symptom diagnostics.',
|
|
command: 'pip install greenlens-python\ngreenlens-py care "Monstera"',
|
|
href: 'https://pypi.org/project/greenlens-python/',
|
|
linkLabel: 'Python SDK & CLI on PyPI',
|
|
},
|
|
{
|
|
icon: '📦',
|
|
eyebrow: 'NPM Package',
|
|
title: 'Node.js CLI and package',
|
|
description: 'A zero-dependency terminal utility and Node module for rapid plant-care lookup in any shell or application.',
|
|
command: 'npx greenlenspro-cli care "Monstera"',
|
|
href: 'https://www.npmjs.com/package/greenlenspro-cli',
|
|
linkLabel: 'Node.js package on NPM',
|
|
},
|
|
{
|
|
icon: '🧩',
|
|
eyebrow: 'Chrome & Firefox Stores',
|
|
title: 'Browser extensions',
|
|
description: 'Search a local plant catalog, check leaf symptoms, or select a plant photo from the current browser page for AI analysis.',
|
|
command: 'Browser popup + photo scan tool',
|
|
href: siteConfig.chromeWebStoreUrl,
|
|
linkLabel: 'Chrome Web Store',
|
|
secondaryHref: siteConfig.firefoxAddonUrl,
|
|
secondaryLinkLabel: 'Firefox Add-ons',
|
|
},
|
|
{
|
|
icon: '🐙',
|
|
eyebrow: 'GitHub CI/CD',
|
|
title: 'GitHub Action',
|
|
description: 'Run plant-care and diagnosis lookups in CI/CD workflows and print results directly in build output.',
|
|
command: 'uses: knuthtimo-lab/greenlenspro-cli@v1',
|
|
href: `${repositoryUrl}#github-action`,
|
|
linkLabel: 'View GitHub Action',
|
|
},
|
|
{
|
|
icon: '📁',
|
|
eyebrow: 'Open source',
|
|
title: 'GitHub repository',
|
|
description: 'Browse the complete source code, releases, installation notes, and contribution context for greenlenspro-cli.',
|
|
command: 'github.com/knuthtimo-lab/greenlenspro-cli',
|
|
href: repositoryUrl,
|
|
linkLabel: 'Open GitHub repository',
|
|
},
|
|
]
|
|
|
|
export default function DevelopersPage() {
|
|
return (
|
|
<div className="min-h-screen bg-background text-ink font-body">
|
|
<SeoNavbar locale="de" methodologyHref="#methodology" showDevelopers />
|
|
|
|
<main>
|
|
<section className="pt-36 pb-20 md:pt-44 md:pb-28" id="advantage">
|
|
<div className="max-w-[1200px] mx-auto px-6 grid lg:grid-cols-[minmax(0,1.05fr)_minmax(360px,0.75fr)] gap-14 lg:gap-20 items-center">
|
|
<div>
|
|
<p className="text-xs font-bold tracking-[0.18em] uppercase text-primary mb-6">Developer suite & open source</p>
|
|
<h1 className="font-display text-5xl md:text-6xl lg:text-7xl font-bold leading-[0.98] tracking-tight text-ink max-w-3xl">
|
|
Plant care tools for the stack you already use.
|
|
</h1>
|
|
<p className="mt-7 max-w-2xl text-base md:text-lg leading-relaxed text-on-surface-variant">
|
|
Bring GreenLens care guidance, symptom checks, and lighting evaluations into VS Code, Python, Node.js, your browser, or a GitHub workflow.
|
|
</p>
|
|
<div className="mt-9 flex flex-wrap gap-4">
|
|
<a href={repositoryUrl} target="_blank" rel="noopener noreferrer" className="inline-flex items-center rounded-full bg-ink px-6 py-3 text-sm font-bold text-white transition-colors hover:bg-primary">
|
|
Explore on GitHub <span aria-hidden="true" className="ml-2">→</span>
|
|
</a>
|
|
<Link href="/support" className="inline-flex items-center rounded-full border border-ink px-6 py-3 text-sm font-bold text-ink transition-colors hover:bg-surface-container">
|
|
Developer support
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
<aside className="rounded-[2rem] bg-ink p-7 md:p-9 text-white shadow-[0_24px_60px_-30px_rgba(1,38,31,0.6)]" aria-label="GitHub repository overview">
|
|
<div className="flex items-center justify-between border-b border-white/15 pb-5">
|
|
<span className="text-sm font-bold tracking-wide">greenlenspro-cli</span>
|
|
<span className="text-[10px] font-bold tracking-[0.14em] uppercase text-primary-fixed">Open source</span>
|
|
</div>
|
|
<div className="py-7 font-mono text-sm leading-8 text-white/80">
|
|
<p><span className="text-primary-fixed">$</span> npx greenlenspro-cli care "Monstera"</p>
|
|
<p className="mt-5 text-white/55"># GitHub Actions</p>
|
|
<p><span className="text-primary-fixed">uses:</span> knuthtimo-lab/greenlenspro-cli@v1</p>
|
|
</div>
|
|
<a href={repositoryUrl} target="_blank" rel="noopener noreferrer" className="inline-flex items-center text-sm font-bold text-primary-fixed hover:text-white transition-colors">
|
|
View repository <span aria-hidden="true" className="ml-2">↗</span>
|
|
</a>
|
|
</aside>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="border-y border-outline-variant/60 bg-surface-container-low py-20 md:py-28" id="methodology">
|
|
<div className="max-w-[1200px] mx-auto px-6">
|
|
<div className="max-w-2xl mb-12 md:mb-16">
|
|
<p className="text-xs font-bold tracking-[0.18em] uppercase text-primary mb-5">Tools & integrations</p>
|
|
<h2 className="font-display text-4xl md:text-5xl font-bold leading-tight text-ink">One plant-care toolkit, six practical entry points.</h2>
|
|
</div>
|
|
|
|
<div className="grid gap-5 md:grid-cols-2">
|
|
{tools.map((tool) => (
|
|
<article key={tool.title} className="flex flex-col rounded-3xl bg-white p-7 md:p-8 border border-outline-variant/70 transition-transform duration-300 hover:-translate-y-1 hover:shadow-[0_18px_40px_-28px_rgba(1,38,31,0.38)]">
|
|
<div className="flex items-start justify-between gap-5">
|
|
<span className="text-3xl leading-none" aria-hidden="true">{tool.icon}</span>
|
|
<span className="text-right text-[10px] font-bold tracking-[0.15em] uppercase text-primary">{tool.eyebrow}</span>
|
|
</div>
|
|
<h3 className="mt-8 font-display text-3xl font-bold leading-tight text-ink">{tool.title}</h3>
|
|
<p className="mt-4 max-w-[60ch] text-sm leading-7 text-on-surface-variant">{tool.description}</p>
|
|
<code className="mt-6 block whitespace-pre-line rounded-xl bg-ink px-4 py-3 font-mono text-xs leading-6 text-primary-fixed">{tool.command}</code>
|
|
<div className="mt-7 flex flex-wrap gap-4 items-center">
|
|
<a href={tool.href} target="_blank" rel="noopener noreferrer" className="inline-flex w-fit items-center text-sm font-bold text-primary hover:text-ink transition-colors">
|
|
{tool.linkLabel} <span aria-hidden="true" className="ml-2">→</span>
|
|
</a>
|
|
{tool.secondaryHref && (
|
|
<a href={tool.secondaryHref} target="_blank" rel="noopener noreferrer" className="inline-flex w-fit items-center text-sm font-bold text-primary hover:text-ink transition-colors">
|
|
{tool.secondaryLinkLabel} <span aria-hidden="true" className="ml-2">→</span>
|
|
</a>
|
|
)}
|
|
</div>
|
|
</article>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="py-20 md:py-28 border-b border-outline-variant/60" id="engineering-blog">
|
|
<div className="max-w-[1200px] mx-auto px-6">
|
|
<div className="max-w-2xl mb-12 md:mb-16">
|
|
<p className="text-xs font-bold tracking-[0.18em] uppercase text-primary mb-5">Engineering blog</p>
|
|
<h2 className="font-display text-4xl md:text-5xl font-bold leading-tight text-ink">How we built the GreenLens platform.</h2>
|
|
<p className="mt-5 max-w-2xl text-base leading-relaxed text-on-surface-variant">
|
|
Deep dives into the real architecture behind GreenLens: the vision AI diagnostic pipeline, the Chrome extension, the Python SDK, offline-first sync, and more.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
{engineeringPosts.map((post) => (
|
|
<Link
|
|
key={post.slug}
|
|
href={`/blog/${post.slug}`}
|
|
className="flex flex-col rounded-2xl bg-white p-6 border border-outline-variant/70 transition-transform duration-300 hover:-translate-y-1 hover:shadow-[0_18px_40px_-28px_rgba(1,38,31,0.38)]"
|
|
>
|
|
<span className="text-[10px] font-bold tracking-[0.15em] uppercase text-primary">{post.readTime}</span>
|
|
<h3 className="mt-3 font-display text-lg font-bold leading-snug text-ink">{post.title}</h3>
|
|
<span className="mt-4 inline-flex w-fit items-center text-sm font-bold text-primary">
|
|
Read the post <span aria-hidden="true" className="ml-2">→</span>
|
|
</span>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="py-20 md:py-28" id="faq">
|
|
<div className="max-w-[1200px] mx-auto px-6 grid gap-8 lg:grid-cols-[1fr_auto] lg:items-end">
|
|
<div>
|
|
<p className="text-xs font-bold tracking-[0.18em] uppercase text-primary mb-5">Need the full app?</p>
|
|
<h2 className="font-display text-4xl md:text-5xl font-bold leading-tight text-ink max-w-2xl">Use GreenLens on your phone for camera-based plant scans and ongoing care.</h2>
|
|
</div>
|
|
<a href={siteConfig.iosAppStoreUrl} target="_blank" rel="noopener noreferrer" className="inline-flex w-fit items-center rounded-full bg-ink px-6 py-3 text-sm font-bold text-white transition-colors hover:bg-primary">
|
|
Download on the App Store <span aria-hidden="true" className="ml-2">→</span>
|
|
</a>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<SeoFooter locale="de" />
|
|
</div>
|
|
)
|
|
}
|