feat: add GitHub star nudges to CLI build view and docs sidebar (#271)

* feat: load star count during context builds

* docs: document star prompt opt-out

* fix: initialize demo context star count

* feat(docs-site): add GitHub star count widget to docs sidebar

* test: isolate star-prompt build-view tests from ambient CI env
This commit is contained in:
Andrey Avtomonov 2026-06-08 16:14:56 +02:00 committed by GitHub
parent 5232578d44
commit 795a97485a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 928 additions and 12 deletions

View file

@ -2,10 +2,21 @@ import { source } from "@/lib/source";
import { DocsLayout } from "fumadocs-ui/layouts/docs";
import type { ReactNode } from "react";
import { baseOptions } from "@/app/layout.config";
import { GitHubStars } from "@/components/github-stars";
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout tree={source.pageTree} {...baseOptions}>
<DocsLayout
tree={source.pageTree}
{...baseOptions}
sidebar={{
banner: (
<div className="flex">
<GitHubStars />
</div>
),
}}
>
{children}
</DocsLayout>
);

View file

@ -869,6 +869,147 @@ body::after {
50% { opacity: 0.65; transform: scale(0.9); }
}
/*
GitHub star widget (navbar)
Split pill: GitHub mark + "Star" gold star + count.
*/
.ktx-stars {
display: inline-flex;
align-items: stretch;
height: 32px;
border-radius: 999px;
border: 1px solid var(--color-fd-border);
background: color-mix(in oklch, var(--color-fd-card) 72%, transparent);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
font-family: var(--font-display), var(--font-sans), sans-serif;
font-size: 13px;
line-height: 1;
color: var(--color-fd-foreground);
text-decoration: none;
overflow: hidden;
box-shadow: 0 1px 2px rgba(27, 27, 24, 0.04);
transition:
transform 0.3s var(--ktx-ease),
box-shadow 0.3s var(--ktx-ease),
border-color 0.3s ease;
animation: ktx-stars-in 0.5s var(--ktx-ease) both;
}
@keyframes ktx-stars-in {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.ktx-stars:hover {
transform: translateY(-1px);
border-color: color-mix(in oklch, var(--color-fd-primary) 45%, var(--color-fd-border));
box-shadow:
0 6px 18px -8px rgba(14, 116, 144, 0.28),
0 1px 2px rgba(27, 27, 24, 0.05);
}
.ktx-stars:focus-visible {
outline: 2px solid var(--color-fd-ring);
outline-offset: 2px;
}
.dark .ktx-stars {
background: color-mix(in oklch, var(--color-fd-card) 60%, transparent);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
.dark .ktx-stars:hover {
border-color: rgba(34, 211, 238, 0.4);
box-shadow:
0 6px 18px -8px rgba(34, 211, 238, 0.3),
0 1px 2px rgba(0, 0, 0, 0.3);
}
.ktx-stars-seg {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 0 11px;
}
.ktx-stars-seg--count {
border-left: 1px solid var(--color-fd-border);
background: color-mix(in oklch, var(--color-fd-primary) 6%, transparent);
transition: background 0.3s var(--ktx-ease);
}
.ktx-stars:hover .ktx-stars-seg--count {
background: color-mix(in oklch, var(--color-fd-primary) 12%, transparent);
}
.ktx-stars-gh {
width: 15px;
height: 15px;
opacity: 0.85;
}
.ktx-stars-text {
font-weight: 500;
letter-spacing: -0.01em;
}
.ktx-stars-star {
width: 14px;
height: 14px;
fill: #f5b301;
transition: transform 0.3s var(--ktx-ease), filter 0.3s var(--ktx-ease);
}
.ktx-stars:hover .ktx-stars-star {
transform: scale(1.18) rotate(-8deg);
filter: drop-shadow(0 1px 4px rgba(245, 179, 1, 0.55));
}
.ktx-stars-count {
font-weight: 600;
font-variant-numeric: tabular-nums;
color: var(--color-fd-foreground);
}
/* Skeleton shown only on the rare cold (uncached) fetch */
.ktx-stars--skeleton {
animation: none;
}
.ktx-stars-skeleton-bar {
display: inline-block;
width: 26px;
height: 11px;
border-radius: 4px;
background: linear-gradient(
90deg,
var(--color-fd-muted) 25%,
color-mix(in oklch, var(--color-fd-muted-foreground) 28%, var(--color-fd-muted)) 50%,
var(--color-fd-muted) 75%
);
background-size: 200% 100%;
animation: ktx-stars-shimmer 1.4s ease-in-out infinite;
}
@keyframes ktx-stars-shimmer {
from { background-position: 200% 0; }
to { background-position: -200% 0; }
}
/* Compact on phones: drop the "Star" word, keep mark + count */
@media (max-width: 640px) {
.ktx-stars-text { display: none; }
.ktx-stars-seg { padding: 0 9px; }
}
@media (prefers-reduced-motion: reduce) {
.ktx-stars { animation: none; transition: none; }
.ktx-stars:hover { transform: none; }
.ktx-stars:hover .ktx-stars-star { transform: none; }
.ktx-stars-skeleton-bar { animation: none; }
}
/* Dot grid */
.dot-grid {
background-image: radial-gradient(

View file

@ -1,5 +1,4 @@
import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
import { GitHubIcon } from "@/components/github-icon";
import { Logo } from "@/components/logo";
import { SlackIcon } from "@/components/slack-icon";
@ -26,14 +25,6 @@ export const baseOptions: BaseLayoutProps = {
},
],
},
{
type: "icon",
label: "GitHub",
icon: <GitHubIcon />,
text: "GitHub",
url: "https://github.com/kaelio/ktx",
external: true,
},
{
type: "icon",
label: "Join the ktx Slack community",