Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions app/components/Hero/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { SiGithub } from "@icons-pack/react-simple-icons";
import Link from "next/link";
import { ExternalLink } from "lucide-react";
import { ExternalLink, BookOpen } from "lucide-react";
import { CodeSnippet } from "@/components/CodeSnippet";

export function Hero() {
return (
<section className="container mx-auto px-4 pt-20 text-center">
<h1 className="mb-6 text-5xl font-extrabold tracking-tight lg:text-6xl text-muted-foreground">
<h1 className="mb-6 text-5xl font-extrabold tracking-tight lg:text-6xl text-foreground">
Build faster with <span className="text-primary">cur8d</span>
</h1>
<div className="mx-auto mb-10 max-w-2xl text-xl text-muted-foreground">
Expand All @@ -26,10 +26,24 @@ export function Hero() {
<CodeSnippet code="npx create-cur8d --template tsx awesome-app" />
</div>

<div className="flex justify-center gap-4">
<div className="flex flex-wrap items-center justify-center gap-4">
<Link
href="https://cur8d.dev/typescript"
className="btn-primary"
target="_blank"
rel="noopener noreferrer"
>
<BookOpen className="size-4" aria-hidden="true" />
Documentation
<ExternalLink
className="size-4 text-primary-foreground/80"
aria-hidden="true"
/>
<span className="sr-only"> (opens in a new window)</span>
</Link>
<Link
href="https://github.com/cur8d/typescript"
className="inline-flex items-center justify-center gap-2 rounded-xl border border-border bg-background px-8 py-3 text-sm font-medium transition-colors hover:bg-secondary focus-visible:ring-2 focus-visible:ring-primary"
className="btn-secondary"
target="_blank"
rel="noopener noreferrer"
>
Expand Down
8 changes: 8 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,12 @@
.focus-ring {
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2;
}

.btn-primary {
@apply focus-ring inline-flex items-center justify-center gap-2 rounded-xl bg-primary text-primary-foreground px-8 py-3 text-sm font-medium shadow-sm transition-all hover:bg-primary/90 hover:shadow;
}

.btn-secondary {
@apply focus-ring inline-flex items-center justify-center gap-2 rounded-xl border border-border bg-background px-8 py-3 text-sm font-medium transition-colors hover:bg-secondary;
}
}
18 changes: 9 additions & 9 deletions app/hooks/use-search-state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ interface SearchContextValue {
onClose: () => void;
onOpenChange: (open: boolean) => void;
toggle: () => void;
open: () => void;
close: () => void;
setOpen: (open: boolean) => void;
}

const SearchContext = createContext<SearchContextValue | undefined>(undefined);
Expand All @@ -20,13 +23,18 @@ export function SearchProvider({ children }: { children: ReactNode }) {
const onOpenChange = useCallback((open: boolean) => setIsOpen(open), []);
const toggle = useCallback(() => setIsOpen((prev) => !prev), []);

// Performance optimization: Include HeroUI compatibility aliases directly in the
// context value memoization to prevent allocating a new wrapper object on every call to useSearchState.
const value = useMemo(
() => ({
isOpen,
onOpen,
onClose,
onOpenChange,
toggle,
open: onOpen,
close: onClose,
setOpen: onOpenChange,
}),
[isOpen, onOpen, onClose, onOpenChange, toggle]
);
Expand All @@ -40,13 +48,5 @@ export function useSearchState() {
throw new Error("useSearchState must be used within a SearchProvider");
}

return useMemo(
() => ({
...context,
open: context.onOpen,
close: context.onClose,
setOpen: context.onOpenChange,
}),
[context]
);
return context;
}
6 changes: 5 additions & 1 deletion docs/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ async function getMdxFiles(
baseDir: string,
results: string[] = [],
): Promise<string[]> {
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
const resolvedDir = path.resolve(dir);
if (!resolvedDir.startsWith(path.resolve(baseDir))) {
throw new Error("Path traversal detected");
}
const entries = await fs.promises.readdir(resolvedDir, { withFileTypes: true });

await Promise.all(
entries.map(async (entry) => {
Expand Down
4 changes: 3 additions & 1 deletion docs/content/reference/utilities.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export default function Page() {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: safeJsonLdStringify(jsonLd) }}
>
{safeJsonLdStringify(jsonLd)}
</script>
/>
);
}
Expand Down
9 changes: 5 additions & 4 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
},
"dependencies": {
"@tailwindcss/postcss": "^4.3.3",
"framer-motion": "13.1.1",
"next": "16.3.2",
"framer-motion": "13.2.0",
"next": "16.3.4",
"next-themes": "0.4.6",
"nextra": "4.6.1",
"nextra-theme-docs": "4.6.1",
Expand All @@ -20,9 +20,10 @@
"tailwindcss": "4.3.3"
},
"devDependencies": {
"@types/node": "26.2.0",
"@types/node": "26.4.1",
"@types/react": "19.2.18",
"@types/react-dom": "19.2.4",
"@types/react-dom": "19.2.5",
"prettier": "^3.8.1",
"typescript": "6.0.3"
}
}
18 changes: 18 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
compress: true,
poweredByHeader: false,
experimental: {
optimizePackageImports: [
"@heroui/react",
"@heroui/styles",
"lucide-react",
"react-icons",
],
},
async headers() {
return [
{
Expand Down Expand Up @@ -34,6 +44,14 @@ const nextConfig: NextConfig = {
key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=()",
},
{
key: "Cross-Origin-Opener-Policy",
value: "same-origin",
},
{
key: "Cross-Origin-Resource-Policy",
value: "same-origin",
},
],
},
];
Expand Down
40 changes: 20 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,43 +29,43 @@
"@vercel/blob": "2.8.0",
"@vercel/speed-insights": "^2.0.0",
"cmdk": "1.1.1",
"framer-motion": "13.1.1",
"lucide-react": "1.33.0",
"next": "16.3.2",
"framer-motion": "13.2.0",
"lucide-react": "1.39.0",
"next": "16.3.4",
"next-themes": "0.4.6",
"postcss": "^8.5.26",
"react": "19.2.8",
"react-dom": "19.2.8",
"zod": "4.4.3"
"zod": "4.5.4"
},
"devDependencies": {
"@axe-core/playwright": "4.13.0",
"@eslint/eslintrc": "^3.3.6",
"@eslint/eslintrc": "^3.3.7",
"@eslint/js": "10.0.1",
"@next/bundle-analyzer": "16.3.2",
"@next/eslint-plugin-next": "^16.3.2",
"@next/bundle-analyzer": "16.3.4",
"@next/eslint-plugin-next": "^16.3.4",
"@playwright/test": "1.62.1",
"@testing-library/jest-dom": "^7.0.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.6",
"@types/node": "26.2.0",
"@testing-library/react": "^16.3.3",
"@testing-library/user-event": "^14.6.7",
"@types/node": "26.4.1",
"@types/react": "19.2.18",
"@types/react-dom": "19.2.4",
"@typescript-eslint/eslint-plugin": "^8.67.0",
"@typescript-eslint/parser": "^8.67.0",
"@vitejs/plugin-react": "6.1.0",
"@types/react-dom": "19.2.5",
"@typescript-eslint/eslint-plugin": "^8.69.0",
"@typescript-eslint/parser": "^8.69.0",
"@vitejs/plugin-react": "6.1.1",
"@vitest/coverage-v8": "4.1.11",
"eslint": "10.9.0",
"eslint-config-next": "16.3.2",
"firebase-tools": "^15.28.1",
"globals": "^17.11.0",
"eslint": "10.9.1",
"eslint-config-next": "16.3.4",
"firebase-tools": "^15.28.2",
"globals": "^17.12.0",
"jsdom": "30.0.1",
"playwright": "1.62.1",
"prettier": "3.9.6",
"tailwindcss": "4.3.3",
"tsx": "^4.23.12",
"tsx": "^4.23.13",
"typescript": "6.0.3",
"vercel": "^59.5.0",
"vercel": "^59.11.2",
"vite": "^8.2.2",
"vitest": "4.1.11"
}
Expand Down
Loading