Developer
This commit is contained in:
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,7 +1,8 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
node_modules/
|
||||||
|
**/node_modules/
|
||||||
/.pnp
|
/.pnp
|
||||||
.pnp.*
|
.pnp.*
|
||||||
.yarn/*
|
.yarn/*
|
||||||
@@ -20,6 +21,16 @@
|
|||||||
# production
|
# production
|
||||||
/build
|
/build
|
||||||
|
|
||||||
|
# Separate package projects (they are published from their own repositories)
|
||||||
|
/chrome-decision-kit/
|
||||||
|
/decision-kit/
|
||||||
|
/python-decision-kit/
|
||||||
|
/vscode-decision-kit/
|
||||||
|
|
||||||
|
# Package build artefacts
|
||||||
|
**/*.egg-info/
|
||||||
|
*.vsix
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.pem
|
*.pem
|
||||||
|
|||||||
179
app/developer/page.tsx
Normal file
179
app/developer/page.tsx
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { ArrowUpRight, Box, Check, Code2, Puzzle, Terminal } from "lucide-react";
|
||||||
|
import Nav from "@/components/nav";
|
||||||
|
import Footer from "@/components/footer";
|
||||||
|
|
||||||
|
function GithubIcon({ className }: { className?: string }) {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className} aria-hidden="true">
|
||||||
|
<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 0 6 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4" />
|
||||||
|
<path d="M9 18c-4.51 2-5-2-7-2" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Decision Kit – Developer Suite",
|
||||||
|
description: "Open-Source-Tools von Entscheidomat: Repository, VS Code Extension, Chrome Extension, npm-Paket, Python SDK und GitHub Action.",
|
||||||
|
openGraph: {
|
||||||
|
title: "Decision Kit – Developer Suite | Entscheidomat",
|
||||||
|
description: "Zufalls-Entscheidungstools für VS Code, Chrome, Node.js, Python und GitHub Actions.",
|
||||||
|
url: "https://entscheidomat.com/developer",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type Asset = {
|
||||||
|
title: string;
|
||||||
|
eyebrow: string;
|
||||||
|
description: string;
|
||||||
|
icon: typeof Puzzle;
|
||||||
|
action?: string;
|
||||||
|
href?: string;
|
||||||
|
snippet?: string;
|
||||||
|
status: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const assets: Asset[] = [
|
||||||
|
{
|
||||||
|
title: "GitHub Repository",
|
||||||
|
eyebrow: "Open Source · MIT",
|
||||||
|
description: "Der vollständige Decision-Kit-Quellcode mit Releases, Issues und Contribution Guide – die zentrale Anlaufstelle für Entwickler.",
|
||||||
|
icon: Code2,
|
||||||
|
action: "Repository öffnen",
|
||||||
|
href: "https://github.com/knuthtimo-lab/decision-kit",
|
||||||
|
snippet: "git clone https://github.com/knuthtimo-lab/decision-kit.git",
|
||||||
|
status: "knuthtimo-lab/decision-kit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Decision Kit für VS Code",
|
||||||
|
eyebrow: "Extension · v1.0.0",
|
||||||
|
description: "Ziehe einen Gewinner aus markiertem Text, würfle mit Notation wie 2d6+3 und öffne das Glücksrad direkt in deiner IDE.",
|
||||||
|
icon: Puzzle,
|
||||||
|
action: "Im VS Code Store öffnen",
|
||||||
|
href: "https://marketplace.visualstudio.com/items?itemName=TimoKnuth.decisionkit-vscode",
|
||||||
|
status: "Visual Studio Marketplace",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Decision Kit für Chrome",
|
||||||
|
eyebrow: "Browser-Erweiterung · Manifest V3",
|
||||||
|
description: "Random Picker, Glücksrad, Würfel, Münzwurf und praktische Kontextmenü-Kürzel für schnelle Entscheidungen im Browser.",
|
||||||
|
icon: Puzzle,
|
||||||
|
status: "Chrome Web Store – Veröffentlichung vorbereitet",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "TypeScript Library",
|
||||||
|
eyebrow: "npm · v1.0.0",
|
||||||
|
description: "Zufallsalgorithmen, Würfel-Parser, Glücksrad-Logik und React Hooks als wiederverwendbare Bausteine.",
|
||||||
|
icon: Box,
|
||||||
|
action: "npm-Paket ansehen",
|
||||||
|
href: "https://www.npmjs.com/package/decision-kit",
|
||||||
|
snippet: "npm install decision-kit",
|
||||||
|
status: "Node.js & React",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Python SDK & CLI",
|
||||||
|
eyebrow: "PyPI · v1.0.0",
|
||||||
|
description: "Decision-Kit für Python-Skripte, Automatisierungen und die Kommandozeile.",
|
||||||
|
icon: Terminal,
|
||||||
|
action: "PyPI-Projekt ansehen",
|
||||||
|
href: "https://pypi.org/project/decision-kit/",
|
||||||
|
snippet: "pip install decision-kit",
|
||||||
|
status: "Python Package Index",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "GitHub Action",
|
||||||
|
eyebrow: "GitHub Marketplace",
|
||||||
|
description: "Nutze Auslosungen, Teamaufteilungen und Zufallsentscheidungen direkt in deinen CI/CD-Workflows.",
|
||||||
|
icon: Code2,
|
||||||
|
action: "Action ansehen",
|
||||||
|
href: "https://github.com/marketplace/actions/decision-kit-action",
|
||||||
|
snippet: "uses: knuthtimo-lab/decision-kit@v1.0.0",
|
||||||
|
status: "Für GitHub Actions",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function DeveloperPage() {
|
||||||
|
const jsonLd = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "SoftwareApplication",
|
||||||
|
name: "Decision Kit",
|
||||||
|
operatingSystem: "All",
|
||||||
|
applicationCategory: "DeveloperApplication",
|
||||||
|
author: { "@type": "Organization", name: "Entscheidomat" },
|
||||||
|
codeRepository: "https://github.com/knuthtimo-lab/decision-kit",
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, "\\u003c") }} />
|
||||||
|
<Nav />
|
||||||
|
<main className="flex-1 bg-paper pb-20 pt-28 sm:pt-32">
|
||||||
|
<div className="mx-auto w-full max-w-6xl px-5 sm:px-8">
|
||||||
|
<header className="max-w-3xl">
|
||||||
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-[#0d7a57]">Entscheidomat für Entwickler</p>
|
||||||
|
<h1 className="mt-4 text-balance font-display text-5xl font-semibold leading-[0.9] tracking-[-0.045em] text-ink sm:text-6xl">Decision Kit, dort wo du arbeitest.</h1>
|
||||||
|
<p className="mt-6 max-w-2xl text-base leading-7 text-ink-soft sm:text-lg">Eine offene Sammlung von Tools für faire Zufallsentscheidungen – im Editor, im Browser, im Terminal und im Workflow.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section className="relative mt-12 overflow-hidden rounded-[2rem] bg-[#0b241b] px-6 py-7 text-white shadow-[0_22px_60px_rgb(13_122_87/0.22)] sm:px-10 sm:py-10">
|
||||||
|
<div className="pointer-events-none absolute -right-24 -top-36 h-80 w-80 rounded-full bg-[#38b98c]/25 blur-3xl" />
|
||||||
|
<div className="relative grid gap-8 lg:grid-cols-[1.25fr_0.75fr] lg:items-end">
|
||||||
|
<div>
|
||||||
|
<div className="inline-flex items-center gap-2 text-sm font-semibold text-emerald-200"><GithubIcon className="h-4 w-4" />Open Source · MIT-Lizenz</div>
|
||||||
|
<h2 className="mt-5 max-w-xl text-3xl font-semibold tracking-tight sm:text-4xl">Der gesamte Code lebt auf GitHub.</h2>
|
||||||
|
<p className="mt-4 max-w-xl text-sm leading-6 text-emerald-50/75 sm:text-base">Quellcode, Issues, Releases und Contribution Guide findest du im offiziellen Decision-Kit-Repository.</p>
|
||||||
|
<a href="https://github.com/knuthtimo-lab/decision-kit" target="_blank" rel="noopener noreferrer" className="mt-7 inline-flex items-center gap-2 rounded-full bg-white px-5 py-3 text-sm font-semibold text-[#0b241b] transition duration-200 hover:-translate-y-0.5 hover:bg-emerald-50 active:translate-y-0">
|
||||||
|
GitHub-Repository öffnen <ArrowUpRight className="h-4 w-4" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="rounded-2xl border border-white/15 bg-black/20 p-5 font-mono text-xs leading-6 text-emerald-50 shadow-inner">
|
||||||
|
<p className="text-emerald-200/70"># Starte lokal</p>
|
||||||
|
<p className="mt-2 break-all">git clone https://github.com/knuthtimo-lab/decision-kit.git</p>
|
||||||
|
<div className="my-4 h-px bg-white/10" />
|
||||||
|
<p className="text-emerald-200/70"># Oder als Paket</p>
|
||||||
|
<p className="mt-2">npm install decision-kit</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mt-16" aria-labelledby="integrations-heading">
|
||||||
|
<div className="flex flex-col justify-between gap-4 border-b border-line pb-5 sm:flex-row sm:items-end">
|
||||||
|
<div>
|
||||||
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-[#0d7a57]">Integrationen</p>
|
||||||
|
<h2 id="integrations-heading" className="mt-2 text-2xl font-semibold tracking-tight text-ink sm:text-3xl">Installieren, einbinden, loslegen.</h2>
|
||||||
|
</div>
|
||||||
|
<p className="max-w-sm text-sm leading-6 text-ink-soft">Jede Integration ist unabhängig nutzbar und verweist direkt auf ihren offiziellen Kanal.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6 grid gap-4 md:grid-cols-2">
|
||||||
|
{assets.map((asset) => {
|
||||||
|
const Icon = asset.icon;
|
||||||
|
return (
|
||||||
|
<article key={asset.title} className="group flex min-h-64 flex-col rounded-3xl border border-line bg-surface p-6 transition duration-200 hover:-translate-y-1 hover:border-[#0d7a57]/40 hover:shadow-lift">
|
||||||
|
<div className="flex items-start justify-between gap-4">
|
||||||
|
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-[#e6f7f0] text-[#0d7a57]"><Icon className="h-5 w-5" /></div>
|
||||||
|
<p className="pt-1 text-right text-[11px] font-semibold uppercase tracking-[0.12em] text-[#0d7a57]">{asset.eyebrow}</p>
|
||||||
|
</div>
|
||||||
|
<h3 className="mt-6 text-xl font-semibold tracking-tight text-ink">{asset.title}</h3>
|
||||||
|
<p className="mt-2 max-w-md text-sm leading-6 text-ink-soft">{asset.description}</p>
|
||||||
|
{asset.snippet && <code className="mt-5 block overflow-x-auto rounded-xl bg-[#111412] px-3.5 py-3 font-mono text-xs text-emerald-100">{asset.snippet}</code>}
|
||||||
|
<div className="mt-auto flex items-center justify-between gap-4 pt-6">
|
||||||
|
<span className="inline-flex items-center gap-1.5 text-xs font-medium text-ink-soft"><Check className="h-3.5 w-3.5 text-[#0d7a57]" />{asset.status}</span>
|
||||||
|
{asset.href && asset.action ? (
|
||||||
|
<a href={asset.href} target="_blank" rel="noopener noreferrer" className="inline-flex shrink-0 items-center gap-1.5 text-sm font-semibold text-[#0d7a57] transition hover:text-[#095c41] hover:underline">{asset.action} <ArrowUpRight className="h-4 w-4" /></a>
|
||||||
|
) : <span className="text-xs font-semibold text-[#0d7a57]">Bald verfügbar</span>}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div className="mt-14 border-t border-line pt-8 text-sm text-ink-soft">Zurück zu den <Link href="/" className="font-semibold text-[#0d7a57] hover:underline">Entscheidungstools</Link>.</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -143,10 +143,6 @@ body {
|
|||||||
|
|
||||||
/* Der Inline-Check im Root-Layout läuft vor der Hydration. Dadurch blitzt der
|
/* Der Inline-Check im Root-Layout läuft vor der Hydration. Dadurch blitzt der
|
||||||
Preloader bei einem Reload innerhalb derselben Browser-Session nicht auf. */
|
Preloader bei einem Reload innerhalb derselben Browser-Session nicht auf. */
|
||||||
html[data-preloader="cached"] [data-preloader-overlay] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Der Preloader würde auf einem gedrosselten Mobilgerät das LCP-Element
|
/* Der Preloader würde auf einem gedrosselten Mobilgerät das LCP-Element
|
||||||
verdecken. Die Seite bleibt dort sofort lesbar; Desktop behält den Effekt. */
|
verdecken. Die Seite bleibt dort sofort lesbar; Desktop behält den Effekt. */
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
lang="de"
|
lang="de"
|
||||||
|
data-preloader="active"
|
||||||
className={`${inter.variable} ${cormorant.variable} h-full antialiased`}
|
className={`${inter.variable} ${cormorant.variable} h-full antialiased`}
|
||||||
>
|
>
|
||||||
<body className="flex min-h-full flex-col">
|
<body className="flex min-h-full flex-col">
|
||||||
@@ -100,15 +101,6 @@ export default function RootLayout({
|
|||||||
crossOrigin="anonymous"
|
crossOrigin="anonymous"
|
||||||
strategy="beforeInteractive"
|
strategy="beforeInteractive"
|
||||||
/>
|
/>
|
||||||
<Script id="preloader-session" strategy="beforeInteractive">
|
|
||||||
{`try {
|
|
||||||
const hasSeenPreloader = sessionStorage.getItem("entscheidomat:preloader-seen") === "1";
|
|
||||||
const isMobile = window.matchMedia("(max-width: 767px)").matches;
|
|
||||||
document.documentElement.dataset.preloader = hasSeenPreloader || isMobile ? "cached" : "active";
|
|
||||||
} catch {
|
|
||||||
document.documentElement.dataset.preloader = window.matchMedia("(max-width: 767px)").matches ? "cached" : "active";
|
|
||||||
}`}
|
|
||||||
</Script>
|
|
||||||
<script
|
<script
|
||||||
type="application/ld+json"
|
type="application/ld+json"
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import DirectAnswer from "@/components/direct-answer";
|
|||||||
import Playground from "@/components/playground";
|
import Playground from "@/components/playground";
|
||||||
import Features from "@/components/features";
|
import Features from "@/components/features";
|
||||||
import HomepageFaq, { HOMEPAGE_FAQS } from "@/components/homepage-faq";
|
import HomepageFaq, { HOMEPAGE_FAQS } from "@/components/homepage-faq";
|
||||||
|
import DeveloperEcosystem from "@/components/developer-ecosystem";
|
||||||
import Footer from "@/components/footer";
|
import Footer from "@/components/footer";
|
||||||
import DeferredScrollFlourishes from "@/components/deferred-scroll-flourishes";
|
import DeferredScrollFlourishes from "@/components/deferred-scroll-flourishes";
|
||||||
|
|
||||||
@@ -59,6 +60,9 @@ export default function Home() {
|
|||||||
<DirectAnswer />
|
<DirectAnswer />
|
||||||
<Playground />
|
<Playground />
|
||||||
<Features />
|
<Features />
|
||||||
|
<div className="mx-auto w-full max-w-6xl px-5 sm:px-8">
|
||||||
|
<DeveloperEcosystem />
|
||||||
|
</div>
|
||||||
<HomepageFaq />
|
<HomepageFaq />
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
changeFrequency: "monthly" as const,
|
changeFrequency: "monthly" as const,
|
||||||
priority: 0.8,
|
priority: 0.8,
|
||||||
})),
|
})),
|
||||||
|
{
|
||||||
|
url: `${SITE_URL}/developer`,
|
||||||
|
lastModified: "2026-08-01",
|
||||||
|
changeFrequency: "weekly",
|
||||||
|
priority: 0.9,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
url: `${SITE_URL}/impressum`,
|
url: `${SITE_URL}/impressum`,
|
||||||
lastModified: "2026-07-23",
|
lastModified: "2026-07-23",
|
||||||
|
|||||||
164
components/developer-ecosystem.tsx
Normal file
164
components/developer-ecosystem.tsx
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { Code2, Terminal, Puzzle, Box, ArrowUpRight, CheckCircle2, Sparkles } from "lucide-react";
|
||||||
|
|
||||||
|
function GithubIcon(props: React.SVGProps<SVGSVGElement>) {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" {...props}>
|
||||||
|
<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4" />
|
||||||
|
<path d="M9 18c-4.51 2-5-2-7-2" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEVELOPER_TOOLS = [
|
||||||
|
{
|
||||||
|
id: "github-repo",
|
||||||
|
title: "GitHub Repository",
|
||||||
|
badge: "Open Source",
|
||||||
|
icon: GithubIcon,
|
||||||
|
description: "Der Quellcode des Decision-Kit & Entscheidomat Ökosystems auf GitHub. Sterne, Issues & Contribution Guide.",
|
||||||
|
snippet: "git clone https://github.com/knuthtimo-lab/decision-kit.git",
|
||||||
|
link: "https://github.com/knuthtimo-lab/decision-kit",
|
||||||
|
actionText: "GitHub Repo besuchen",
|
||||||
|
highlight: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "vscode",
|
||||||
|
title: "VS Code Extension",
|
||||||
|
badge: "Marketplace",
|
||||||
|
icon: Puzzle,
|
||||||
|
description: "Zufallssieger aus Markierungen ziehen, Würfeln via Befehlspalette (2d6+3) & Glücksrad-Tab direkt in der IDE.",
|
||||||
|
link: "https://marketplace.visualstudio.com/items?itemName=TimoKnuth.decisionkit-vscode",
|
||||||
|
actionText: "VS Code Store öffnen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "chrome",
|
||||||
|
title: "Chrome Web Store Extension",
|
||||||
|
badge: "Soon",
|
||||||
|
icon: Puzzle,
|
||||||
|
description: "Random Picker, Glücksrad, Würfel, Münzwurf und Kontextmenü-Kürzel – die Veröffentlichung im Chrome Web Store ist in Vorbereitung.",
|
||||||
|
link: "/developer",
|
||||||
|
actionText: "Demnächst verfügbar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "npm",
|
||||||
|
title: "NPM TypeScript Library",
|
||||||
|
badge: "npm v1.0.0",
|
||||||
|
icon: Box,
|
||||||
|
description: "Vose Alias Method für O(1) Zufallswahl, Glücksrad-Physik, RPG-Dice Parser & React 18/19 Hooks.",
|
||||||
|
snippet: "npm install decision-kit",
|
||||||
|
link: "https://www.npmjs.com/package/decision-kit",
|
||||||
|
actionText: "npm Registry öffnen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "pypi",
|
||||||
|
title: "Python SDK & CLI",
|
||||||
|
badge: "PyPI v1.0.0",
|
||||||
|
icon: Terminal,
|
||||||
|
description: "Entscheidungs-Engine & Terminal-CLI für Python-Entwickler, Data Scientists und Automationen.",
|
||||||
|
snippet: "pip install decision-kit",
|
||||||
|
link: "https://pypi.org/project/decision-kit/",
|
||||||
|
actionText: "PyPI Project öffnen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "github-action",
|
||||||
|
title: "GitHub Action",
|
||||||
|
badge: "Marketplace",
|
||||||
|
icon: Code2,
|
||||||
|
description: "Automatisierte Zufallsentscheidungen & Team-Aufteilungen direkt in GitHub CI/CD Actions Workflows.",
|
||||||
|
link: "https://github.com/marketplace/actions/decision-kit-action",
|
||||||
|
actionText: "GitHub Action ansehen"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function DeveloperEcosystem() {
|
||||||
|
return (
|
||||||
|
<section className="my-16 overflow-hidden rounded-3xl border border-line bg-surface p-6 shadow-lift sm:p-10">
|
||||||
|
<div className="mx-auto max-w-3xl text-center">
|
||||||
|
<div className="inline-flex items-center gap-2 rounded-full border border-[#0d7a57]/20 bg-[#e6f7f0] px-3.5 py-1 text-xs font-semibold uppercase tracking-wider text-[#0d7a57]">
|
||||||
|
<Sparkles className="h-3.5 w-3.5" />
|
||||||
|
<span>Developer & Extension Suite</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="mt-4 text-2xl font-bold tracking-tight text-ink sm:text-3xl">
|
||||||
|
Entscheidomat überall nutzen: VS Code, Chrome, Terminal & Code
|
||||||
|
</h2>
|
||||||
|
<p className="mt-3 text-sm text-ink-soft sm:text-base">
|
||||||
|
Nutze unsere Entscheidungstools direkt in deinem Browser, in deiner Lieblings-IDE oder als Open-Source Package in Node.js, Python & GitHub Actions.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-10 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{DEVELOPER_TOOLS.map((tool) => {
|
||||||
|
const Icon = tool.icon;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={tool.id}
|
||||||
|
className={`group flex flex-col justify-between rounded-2xl border p-5 transition-all duration-200 hover:-translate-y-1 hover:shadow-soft ${
|
||||||
|
tool.highlight
|
||||||
|
? "border-[#0d7a57]/40 bg-[#e6f7f0]/30"
|
||||||
|
: "border-line bg-paper hover:border-[#0d7a57]/30"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between gap-2">
|
||||||
|
<div className="flex items-center gap-2.5">
|
||||||
|
<div className="flex h-10 w-10 items-center justify-center rounded-xl border border-[#0d7a57]/20 bg-[#e6f7f0] text-[#0d7a57]">
|
||||||
|
<Icon className="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<h3 className="font-bold text-ink group-hover:text-[#0d7a57] transition-colors">
|
||||||
|
{tool.title}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<span className="rounded-full bg-[#0d7a57]/10 px-2.5 py-0.5 text-xs font-semibold text-[#0d7a57]">
|
||||||
|
{tool.badge}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="mt-3 text-xs leading-relaxed text-ink-soft sm:text-sm">
|
||||||
|
{tool.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{tool.snippet && (
|
||||||
|
<div className="mt-3 overflow-x-auto rounded-xl border border-slate-800 bg-[#111412] px-3.5 py-2 font-mono text-xs shadow-inner">
|
||||||
|
<span className="text-[#10b981] font-bold">$ </span>
|
||||||
|
<span className="text-emerald-200">{tool.snippet}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-5 flex items-center justify-between border-t border-line/60 pt-3">
|
||||||
|
<span className="inline-flex items-center gap-1 text-[11px] font-semibold text-ink-soft">
|
||||||
|
<CheckCircle2 className="h-3.5 w-3.5 text-[#0d7a57]" />
|
||||||
|
<span>Open Source</span>
|
||||||
|
</span>
|
||||||
|
{tool.id === "chrome" ? (
|
||||||
|
<span className="text-xs font-semibold text-ink-soft">Chrome Web Store · Soon</span>
|
||||||
|
) : (
|
||||||
|
<a
|
||||||
|
href={tool.link}
|
||||||
|
target={tool.link.startsWith("http") ? "_blank" : "_self"}
|
||||||
|
rel={tool.link.startsWith("http") ? "noopener noreferrer" : undefined}
|
||||||
|
className="inline-flex items-center gap-1 text-xs font-semibold text-[#0d7a57] hover:underline"
|
||||||
|
>
|
||||||
|
<span>{tool.actionText}</span>
|
||||||
|
<ArrowUpRight className="h-3.5 w-3.5" />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8 text-center">
|
||||||
|
<Link
|
||||||
|
href="/developer"
|
||||||
|
className="inline-flex items-center gap-2 rounded-full border border-line bg-surface px-6 py-2.5 text-sm font-semibold text-ink shadow-soft transition-all hover:border-[#0d7a57]/40 hover:bg-[#e6f7f0] hover:text-[#0d7a57]"
|
||||||
|
>
|
||||||
|
<span>Alle Extensions, Repositories & Dokumentation ansehen</span>
|
||||||
|
<ArrowUpRight className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -16,7 +16,11 @@ export default function Footer() {
|
|||||||
<p>
|
<p>
|
||||||
Gebaut für alle, die sich (manchmal) nicht entscheiden können.
|
Gebaut für alle, die sich (manchmal) nicht entscheiden können.
|
||||||
</p>
|
</p>
|
||||||
<nav aria-label="Rechtliches" className="flex items-center gap-4">
|
<nav aria-label="Rechtliches und Erweiterungen" className="flex flex-wrap items-center justify-center gap-4">
|
||||||
|
<span className="inline-flex items-center gap-1.5 text-ink-soft">
|
||||||
|
Chrome Extension
|
||||||
|
<span className="rounded-full border border-[#0d7a57]/20 bg-[#e6f7f0] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-[#0d7a57]">Soon</span>
|
||||||
|
</span>
|
||||||
<Link href="/impressum" className="transition-colors hover:text-[#0d7a57]">
|
<Link href="/impressum" className="transition-colors hover:text-[#0d7a57]">
|
||||||
Impressum
|
Impressum
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -323,4 +323,3 @@ export default function Hero() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ export default function Nav() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<Link href="/developer" className="rounded-full px-4 py-2 text-sm font-medium text-ink-soft transition-colors duration-200 hover:bg-[#e6f7f0] hover:text-[#0d7a57]">Extensions & API</Link>
|
||||||
<Link href="/#features" className="rounded-full px-4 py-2 text-sm font-medium text-ink-soft transition-colors duration-200 hover:bg-[#e6f7f0] hover:text-[#0d7a57]">Features</Link>
|
<Link href="/#features" className="rounded-full px-4 py-2 text-sm font-medium text-ink-soft transition-colors duration-200 hover:bg-[#e6f7f0] hover:text-[#0d7a57]">Features</Link>
|
||||||
{soundButton}
|
{soundButton}
|
||||||
</div>
|
</div>
|
||||||
@@ -125,7 +126,8 @@ export default function Nav() {
|
|||||||
<div className="grid gap-1">
|
<div className="grid gap-1">
|
||||||
{TOOLS.map((tool) => <Link key={tool.href} href={tool.href} onClick={closeMenus} className="flex items-center justify-between rounded-2xl px-4 py-3 hover:bg-[#e6f7f0]"><span><span className="block font-semibold text-ink">{tool.label}</span><span className="text-xs text-ink-soft">{tool.hint}</span></span><span className="text-[#0d7a57]">→</span></Link>)}
|
{TOOLS.map((tool) => <Link key={tool.href} href={tool.href} onClick={closeMenus} className="flex items-center justify-between rounded-2xl px-4 py-3 hover:bg-[#e6f7f0]"><span><span className="block font-semibold text-ink">{tool.label}</span><span className="text-xs text-ink-soft">{tool.hint}</span></span><span className="text-[#0d7a57]">→</span></Link>)}
|
||||||
</div>
|
</div>
|
||||||
<Link href="/#features" onClick={closeMenus} className="mt-3 block rounded-2xl border border-line px-4 py-3 font-semibold text-ink">Features</Link>
|
<Link href="/developer" onClick={closeMenus} className="mt-3 block rounded-2xl border border-line bg-[#e6f7f0] px-4 py-3 font-semibold text-[#0d7a57]">Extensions & Developer Suite</Link>
|
||||||
|
<Link href="/#features" onClick={closeMenus} className="mt-2 block rounded-2xl border border-line px-4 py-3 font-semibold text-ink">Features</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -387,4 +387,3 @@ export default function ScrollFlourishes() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
package-lock.json
generated
14
package-lock.json
generated
@@ -74,7 +74,6 @@
|
|||||||
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.7",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/generator": "^7.29.7",
|
"@babel/generator": "^7.29.7",
|
||||||
@@ -289,7 +288,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz",
|
||||||
"integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==",
|
"integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/wasi-threads": "1.2.2",
|
"@emnapi/wasi-threads": "1.2.2",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
@@ -300,7 +298,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz",
|
||||||
"integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==",
|
"integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
@@ -1593,7 +1590,6 @@
|
|||||||
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
|
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@@ -1653,7 +1649,6 @@
|
|||||||
"integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==",
|
"integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.65.0",
|
"@typescript-eslint/scope-manager": "8.65.0",
|
||||||
"@typescript-eslint/types": "8.65.0",
|
"@typescript-eslint/types": "8.65.0",
|
||||||
@@ -2257,7 +2252,6 @@
|
|||||||
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
|
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -2601,7 +2595,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.10.44",
|
"baseline-browser-mapping": "^2.10.44",
|
||||||
"caniuse-lite": "^1.0.30001806",
|
"caniuse-lite": "^1.0.30001806",
|
||||||
@@ -3201,7 +3194,6 @@
|
|||||||
"integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==",
|
"integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@@ -3387,7 +3379,6 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@@ -5651,7 +5642,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
||||||
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -5661,7 +5651,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
||||||
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@@ -6354,7 +6343,6 @@
|
|||||||
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -6517,7 +6505,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -6796,7 +6783,6 @@
|
|||||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user