feat(cli): add ultracite, oxlint, fumadocs addons (#427)

This commit is contained in:
Aman Varshney
2025-07-29 00:13:51 +05:30
committed by GitHub
parent 82a4f42eca
commit 216c242f7d
66 changed files with 794 additions and 251 deletions

View File

@@ -129,11 +129,15 @@ const getBadgeColors = (category: string): string => {
}
};
const TechIcon: React.FC<{
function TechIcon({
icon,
name,
className,
}: {
icon: string;
name: string;
className?: string;
}> = ({ icon, name, className }) => {
}) {
const [mounted, setMounted] = useState(false);
const { theme } = useTheme();
@@ -168,7 +172,7 @@ const TechIcon: React.FC<{
{icon}
</span>
);
};
}
const getCategoryDisplayName = (categoryKey: string): string => {
const result = categoryKey.replace(/([A-Z])/g, " $1");
@@ -754,10 +758,36 @@ const analyzeStackCompatibility = (stack: StackState): CompatibilityResult => {
if (
nextStack.addons.includes("husky") &&
!nextStack.addons.includes("biome")
!nextStack.addons.includes("biome") &&
!nextStack.addons.includes("oxlint")
) {
notes.addons.notes.push(
"Husky addon is selected without Biome. Consider adding Biome for lint-staged integration.",
"Husky addon is selected without a linter. Consider adding Biome or Oxlint for lint-staged integration.",
);
}
if (nextStack.addons.includes("ultracite")) {
if (nextStack.addons.includes("biome")) {
notes.addons.notes.push(
"Ultracite includes Biome setup. Biome addon will be removed.",
);
nextStack.addons = nextStack.addons.filter(
(addon) => addon !== "biome",
);
changed = true;
changes.push({
category: "addons",
message: "Biome addon removed (included in Ultracite)",
});
}
}
if (
nextStack.addons.includes("oxlint") &&
nextStack.addons.includes("biome")
) {
notes.addons.notes.push(
"Both Oxlint and Biome are selected. Consider using only one linter.",
);
}
@@ -967,7 +997,26 @@ const generateCommand = (stackState: StackState): string => {
if (!checkDefault("addons", stackState.addons)) {
if (stackState.addons.length > 0) {
flags.push(`--addons ${stackState.addons.join(" ")}`);
const validAddons = stackState.addons.filter((addon) =>
[
"pwa",
"tauri",
"starlight",
"biome",
"husky",
"turborepo",
"ultracite",
"fumadocs",
"oxlint",
].includes(addon),
);
if (validAddons.length > 0) {
flags.push(`--addons ${validAddons.join(" ")}`);
} else {
if (DEFAULT_STACK.addons.length > 0) {
flags.push("--addons none");
}
}
} else {
if (DEFAULT_STACK.addons.length > 0) {
flags.push("--addons none");
@@ -1687,7 +1736,10 @@ const StackBuilder = () => {
<TechIcon
icon={tech.icon}
name={tech.name}
className="mr-1.5 h-3 w-3 sm:h-4 sm:w-4"
className={cn(
"mr-1.5 h-3 w-3 sm:h-4 sm:w-4",
tech.className,
)}
/>
)}
<span

View File

@@ -414,14 +414,14 @@ export default function AnalyticsPage() {
const loadAnalyticsData = useCallback(async () => {
try {
const response = await fetch("/analytics-data.json");
const response = await fetch("https://r2.amanv.dev/analytics-data.json");
const analyticsData = await response.json();
setData(analyticsData.data || []);
setLastUpdated(analyticsData.lastUpdated || null);
console.log(
`Loaded ${analyticsData.data?.length || 0} records from static JSON`,
`Loaded ${analyticsData.data?.length || 0} records from R2 bucket`,
);
console.log(`Data generated at: ${analyticsData.generatedAt}`);
} catch (error: unknown) {

View File

@@ -0,0 +1,11 @@
import { getLLMText } from "@/lib/get-llm-text";
import { source } from "@/lib/source";
export const revalidate = false;
export async function GET() {
const scan = source.getPages().map(getLLMText);
const scanned = await Promise.all(scan);
return new Response(scanned.join("\n\n"));
}

View File

@@ -0,0 +1,21 @@
import { notFound } from "next/navigation";
import { type NextRequest, NextResponse } from "next/server";
import { getLLMText } from "@/lib/get-llm-text";
import { source } from "@/lib/source";
export const revalidate = false;
export async function GET(
_req: NextRequest,
{ params }: { params: Promise<{ slug?: string[] }> },
) {
const { slug } = await params;
const page = source.getPage(slug);
if (!page) notFound();
return new NextResponse(await getLLMText(page));
}
export function generateStaticParams() {
return source.generateParams();
}