diff --git a/apps/web/app/(marketing)/blog/_components/html-renderer.module.css b/apps/web/app/(marketing)/blog/_components/html-renderer.module.css index 1c05748a4..b31f68626 100644 --- a/apps/web/app/(marketing)/blog/_components/html-renderer.module.css +++ b/apps/web/app/(marketing)/blog/_components/html-renderer.module.css @@ -3,15 +3,15 @@ } .HTML h1 { - @apply mt-14 text-4xl font-semibold font-heading tracking-tight ; + @apply mt-14 text-4xl font-semibold font-heading tracking-tight; } .HTML h2 { - @apply mb-4 mt-12 font-semibold text-2xl font-heading tracking-tight; + @apply mb-6 mt-12 font-semibold text-2xl font-heading tracking-tight; } .HTML h3 { - @apply mt-10 text-xl font-semibold font-heading tracking-tight; + @apply mt-12 text-xl font-semibold font-heading tracking-tight; } .HTML h4 { @@ -41,11 +41,11 @@ For more info: https://github.com/tailwindlabs/tailwindcss/issues/3258#issuecomm } .HTML p { - @apply mb-4 mt-2 text-base leading-7; + @apply mb-6 mt-4 text-base leading-7 text-muted-foreground; } .HTML li { - @apply relative my-1.5 text-base leading-7; + @apply relative my-1.5 text-base leading-7 text-muted-foreground; } .HTML ul > li:before { @@ -55,7 +55,7 @@ For more info: https://github.com/tailwindlabs/tailwindcss/issues/3258#issuecomm } .HTML ol > li:before { - @apply inline-flex font-medium; + @apply inline-flex font-medium text-muted-foreground; content: counters(counts, '.') '. '; font-feature-settings: 'tnum'; @@ -63,7 +63,7 @@ For more info: https://github.com/tailwindlabs/tailwindcss/issues/3258#issuecomm .HTML b, .HTML strong { - @apply font-bold; + @apply font-semibold text-secondary-foreground; } :global(.dark) .HTML b, @@ -92,10 +92,35 @@ For more info: https://github.com/tailwindlabs/tailwindcss/issues/3258#issuecomm font-feature-settings: 'tnum'; } +.HTML p > code, .HTML li > code { + @apply p-0.5 text-sm font-semibold bg-muted/50 border font-mono text-secondary-foreground; +} + .HTML blockquote { @apply my-4 border-l-8 border border-primary px-6 py-4 text-lg font-medium text-muted-foreground; } -.HTML pre { - @apply my-6 text-sm text-current border p-6 rounded-lg overflow-x-scroll; +.HTML a { + @apply border-b-black border-b hover:border-b-2 pb-0.5 text-secondary-foreground font-semibold; } + +:global(.dark) .HTML a { + @apply border-yellow-300; +} + +.HTML hr { + @apply mt-8 mb-6 border-border; +} + +.HTML [role='alert'] { + @apply py-4 m-0 my-8; +} + +.HTML [role='alert'] * { + color: inherit; + @apply m-0 p-0 text-sm; +} + +.HTML [role='alert'] h5 { + color: inherit; +} \ No newline at end of file diff --git a/apps/web/app/(marketing)/blog/page.tsx b/apps/web/app/(marketing)/blog/page.tsx index 605e30e1e..e7febf287 100644 --- a/apps/web/app/(marketing)/blog/page.tsx +++ b/apps/web/app/(marketing)/blog/page.tsx @@ -37,6 +37,7 @@ const getContentItems = cache( limit, offset, language, + content: false, sortBy: 'publishedAt', sortDirection: 'desc', }); diff --git a/apps/web/app/(marketing)/docs/[...slug]/page.tsx b/apps/web/app/(marketing)/docs/[...slug]/page.tsx index 4bb257976..f29a3b7dd 100644 --- a/apps/web/app/(marketing)/docs/[...slug]/page.tsx +++ b/apps/web/app/(marketing)/docs/[...slug]/page.tsx @@ -61,13 +61,15 @@ async function DocumentationPage({ params }: DocumentationPageProps) { ); return ( -
-
-
+
+
+

{page.title}

-

+

{description}

diff --git a/apps/web/app/(marketing)/docs/_components/docs-nav-link.tsx b/apps/web/app/(marketing)/docs/_components/docs-nav-link.tsx index 960ce90b9..012971fbd 100644 --- a/apps/web/app/(marketing)/docs/_components/docs-nav-link.tsx +++ b/apps/web/app/(marketing)/docs/_components/docs-nav-link.tsx @@ -1,13 +1,20 @@ 'use client'; +import { useRef } from 'react'; + import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { SidebarMenuButton, SidebarMenuItem } from '@kit/ui/shadcn-sidebar'; import { cn, isRouteActive } from '@kit/ui/utils'; -export function DocsNavLink({ label, url }: { label: string; url: string }) { +export function DocsNavLink({ + label, + url, + children, +}: React.PropsWithChildren<{ label: string; url: string }>) { const currentPath = usePathname(); + const ref = useRef(null); const isCurrent = isRouteActive(url, currentPath, true); return ( @@ -15,10 +22,16 @@ export function DocsNavLink({ label, url }: { label: string; url: string }) { - {label} + + {label} + + + {children} diff --git a/apps/web/app/(marketing)/docs/_components/docs-navigation-collapsible.tsx b/apps/web/app/(marketing)/docs/_components/docs-navigation-collapsible.tsx new file mode 100644 index 000000000..5a36aa498 --- /dev/null +++ b/apps/web/app/(marketing)/docs/_components/docs-navigation-collapsible.tsx @@ -0,0 +1,30 @@ +'use client'; + +import { usePathname } from 'next/navigation'; + +import { Cms } from '@kit/cms'; +import { Collapsible } from '@kit/ui/collapsible'; +import { isRouteActive } from '@kit/ui/utils'; + +export function DocsNavigationCollapsible( + props: React.PropsWithChildren<{ + node: Cms.ContentItem; + prefix: string; + }>, +) { + const currentPath = usePathname(); + const prefix = props.prefix; + + const isChildActive = props.node.children.some((child) => + isRouteActive(prefix + '/' + child.url, currentPath, false), + ); + + return ( + + {props.children} + + ); +} diff --git a/apps/web/app/(marketing)/docs/_components/docs-navigation.tsx b/apps/web/app/(marketing)/docs/_components/docs-navigation.tsx index cc2e7bad4..becaa8991 100644 --- a/apps/web/app/(marketing)/docs/_components/docs-navigation.tsx +++ b/apps/web/app/(marketing)/docs/_components/docs-navigation.tsx @@ -1,66 +1,137 @@ +import { ChevronDown } from 'lucide-react'; + import { Cms } from '@kit/cms'; +import { CollapsibleContent, CollapsibleTrigger } from '@kit/ui/collapsible'; import { Sidebar, SidebarGroup, SidebarGroupContent, SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, SidebarMenuSub, } from '@kit/ui/shadcn-sidebar'; import { DocsNavLink } from '~/(marketing)/docs/_components/docs-nav-link'; +import { DocsNavigationCollapsible } from '~/(marketing)/docs/_components/docs-navigation-collapsible'; import { FloatingDocumentationNavigation } from './floating-docs-navigation'; -function Node({ node, level }: { node: Cms.ContentItem; level: number }) { - const pathPrefix = `/docs`; - const url = `${pathPrefix}/${node.slug}`; +function Node({ + node, + level, + prefix, +}: { + node: Cms.ContentItem; + level: number; + prefix: string; +}) { + const url = `${prefix}/${node.slug}`; + const label = node.label ? node.label : node.title; + + const Container = (props: React.PropsWithChildren) => { + if (node.collapsible) { + return ( + + {props.children} + + ); + } + + return props.children; + }; + + const ContentContainer = (props: React.PropsWithChildren) => { + if (node.collapsible) { + return {props.children}; + } + + return props.children; + }; + + const Trigger = () => { + if (node.collapsible) { + return ( + + + + {label} + + + + + ); + } + + return ; + }; return ( - <> - + + - {(node.children ?? []).length > 0 && ( - - )} - + + + + ); } -function Tree({ pages, level }: { pages: Cms.ContentItem[]; level: number }) { +function Tree({ + pages, + level, + prefix, +}: { + pages: Cms.ContentItem[]; + level: number; + prefix: string; +}) { if (level === 0) { return pages.map((treeNode, index) => ( - - - - - - - + )); } return ( {pages.map((treeNode, index) => ( - + ))} ); } -export function DocsNavigation({ pages }: { pages: Cms.ContentItem[] }) { +export function DocsNavigation({ + pages, + prefix = '/docs', +}: { + pages: Cms.ContentItem[]; + prefix?: string; +}) { return ( <> - + + + + + + +
- + + + + + + +
diff --git a/apps/web/app/(marketing)/docs/_lib/server/docs.loader.ts b/apps/web/app/(marketing)/docs/_lib/server/docs.loader.ts index 996a9d97e..3bec1b3be 100644 --- a/apps/web/app/(marketing)/docs/_lib/server/docs.loader.ts +++ b/apps/web/app/(marketing)/docs/_lib/server/docs.loader.ts @@ -18,7 +18,8 @@ async function docsLoader(language: string | undefined) { const data = await cms.getContentItems({ collection: 'documentation', language, - limit: 500, + limit: Infinity, + content: false, }); return data.items; diff --git a/apps/web/app/(marketing)/docs/layout.tsx b/apps/web/app/(marketing)/docs/layout.tsx index 096384a54..1ad7cd137 100644 --- a/apps/web/app/(marketing)/docs/layout.tsx +++ b/apps/web/app/(marketing)/docs/layout.tsx @@ -15,7 +15,7 @@ async function DocsLayout({ children }: React.PropsWithChildren) { return ( diff --git a/apps/web/app/(marketing)/layout.tsx b/apps/web/app/(marketing)/layout.tsx index d7295d1ef..dda93b0a9 100644 --- a/apps/web/app/(marketing)/layout.tsx +++ b/apps/web/app/(marketing)/layout.tsx @@ -2,6 +2,7 @@ import { getSupabaseServerClient } from '@kit/supabase/server-client'; import { SiteFooter } from '~/(marketing)/_components/site-footer'; import { SiteHeader } from '~/(marketing)/_components/site-header'; +import { BackgroundHue } from '~/components/background-hue'; import { withI18n } from '~/lib/i18n/with-i18n'; async function SiteLayout(props: React.PropsWithChildren) { @@ -17,6 +18,7 @@ async function SiteLayout(props: React.PropsWithChildren) { {props.children} +
); diff --git a/apps/web/app/(marketing)/page.tsx b/apps/web/app/(marketing)/page.tsx index 50665141b..e79f56aa0 100644 --- a/apps/web/app/(marketing)/page.tsx +++ b/apps/web/app/(marketing)/page.tsx @@ -10,7 +10,6 @@ import { FeatureGrid, FeatureShowcase, FeatureShowcaseIconContainer, - GradientSecondaryText, Hero, Pill, SecondaryHero, @@ -24,38 +23,40 @@ import { withI18n } from '~/lib/i18n/with-i18n'; function Home() { return (
- - The leading SaaS Starter Kit for ambitious developers - - } - title={ - <> - The ultimate SaaS Starter - for your next project - - } - subtitle={ - - Build and Ship a SaaS faster than ever before with the next-gen SaaS - Starter Kit. Ship your SaaS in days, not months. - - } - cta={} - image={ - {`App - } - /> +
+ + The leading SaaS Starter Kit for ambitious developers + + } + title={ + <> + The ultimate SaaS Starter + for your next project + + } + subtitle={ + + Build and Ship a SaaS faster than ever before with the next-gen + SaaS Starter Kit. Ship your SaaS in days, not months. + + } + cta={} + image={ + {`App + } + /> +
.{' '} - + Unleash your creativity and build your SaaS faster than ever with Makerkit. - + } icon={ @@ -83,9 +84,7 @@ function Home() { > @@ -155,7 +154,7 @@ function Home() { } > Get started for free. No credit card required.} + pill={No credit card required.} heading="Fair pricing for all types of businesses" subheading="Get started on our free plan and upgrade when you are ready." /> diff --git a/apps/web/app/auth/layout.tsx b/apps/web/app/auth/layout.tsx index ff7b33bc3..341bda461 100644 --- a/apps/web/app/auth/layout.tsx +++ b/apps/web/app/auth/layout.tsx @@ -1,9 +1,16 @@ import { AuthLayoutShell } from '@kit/auth/shared'; import { AppLogo } from '~/components/app-logo'; +import { BackgroundHue } from '~/components/background-hue'; function AuthLayout({ children }: React.PropsWithChildren) { - return {children}; + return ( + + {children} + + + + ); } export default AuthLayout; diff --git a/apps/web/app/sitemap.xml/route.ts b/apps/web/app/sitemap.xml/route.ts index 6d34cb8f0..33db9e9a3 100644 --- a/apps/web/app/sitemap.xml/route.ts +++ b/apps/web/app/sitemap.xml/route.ts @@ -54,6 +54,7 @@ async function getContentItems() { const posts = client .getContentItems({ collection: 'posts', + content: false, limit, }) .then((response) => response.items) @@ -69,6 +70,7 @@ async function getContentItems() { const docs = client .getContentItems({ collection: 'documentation', + content: false, limit, }) .then((response) => response.items) diff --git a/apps/web/components/app-logo.tsx b/apps/web/components/app-logo.tsx index 5646b8bc7..55a4864c4 100644 --- a/apps/web/components/app-logo.tsx +++ b/apps/web/components/app-logo.tsx @@ -31,10 +31,14 @@ export function AppLogo({ label, className, }: { - href?: string; + href?: string | null; className?: string; label?: string; }) { + if (href === null) { + return ; + } + return ( diff --git a/apps/web/components/background-hue.tsx b/apps/web/components/background-hue.tsx new file mode 100644 index 000000000..6c8e0f40b --- /dev/null +++ b/apps/web/components/background-hue.tsx @@ -0,0 +1,52 @@ +const DEFAULT_COLORS_SCALE = { + 0: 'hsl(var(--primary))', + 1: 'hsl(var(--primary))', + 2: 'hsl(var(--primary))', +}; + +export function BackgroundHue({ + className, + opacity = 0.03, + colorsScale = DEFAULT_COLORS_SCALE, +}: { + className?: string; + opacity?: number; + colorsScale?: Record; +}) { + const colors = Object.values(colorsScale).map((color, index, array) => { + const offset = array.length > 1 ? index / (array.length - 1) : 0; + const stopOpacity = 1 - index / (array.length - 1); + + return ( + + ); + }); + + return ( + + ); +} diff --git a/apps/web/package.json b/apps/web/package.json index e429446a0..dd44bad54 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -55,8 +55,8 @@ "@makerkit/data-loader-supabase-nextjs": "^1.2.3", "@marsidev/react-turnstile": "^1.1.0", "@radix-ui/react-icons": "^1.3.2", - "@supabase/supabase-js": "^2.47.1", - "@tanstack/react-query": "5.62.2", + "@supabase/supabase-js": "^2.47.2", + "@tanstack/react-query": "5.62.3", "@tanstack/react-table": "^8.20.5", "date-fns": "^4.1.0", "lucide-react": "^0.468.0", @@ -65,10 +65,10 @@ "next-themes": "0.4.4", "react": "19.0.0", "react-dom": "19.0.0", - "react-hook-form": "^7.53.2", + "react-hook-form": "^7.54.0", "react-i18next": "^15.1.3", "recharts": "2.14.1", - "sonner": "^1.7.0", + "sonner": "^1.7.1", "tailwind-merge": "^2.5.5", "zod": "^3.23.8" }, diff --git a/packages/billing/gateway/package.json b/packages/billing/gateway/package.json index 1b0303573..585187b28 100644 --- a/packages/billing/gateway/package.json +++ b/packages/billing/gateway/package.json @@ -27,13 +27,13 @@ "@kit/tailwind-config": "workspace:*", "@kit/tsconfig": "workspace:*", "@kit/ui": "workspace:*", - "@supabase/supabase-js": "^2.47.1", + "@supabase/supabase-js": "^2.47.2", "@types/react": "npm:types-react@19.0.0-rc.1", "date-fns": "^4.1.0", "lucide-react": "^0.468.0", "next": "15.0.4", "react": "19.0.0", - "react-hook-form": "^7.53.2", + "react-hook-form": "^7.54.0", "react-i18next": "^15.1.3", "zod": "^3.23.8" }, diff --git a/packages/billing/gateway/src/components/pricing-table.tsx b/packages/billing/gateway/src/components/pricing-table.tsx index eaf0ce089..40b7ba4cf 100644 --- a/packages/billing/gateway/src/components/pricing-table.tsx +++ b/packages/billing/gateway/src/components/pricing-table.tsx @@ -392,32 +392,36 @@ function PlanIntervalSwitcher( }>, ) { return ( -
+
{props.intervals.map((plan, index) => { const selected = plan === props.interval; const className = cn( - 'animate-in fade-in !outline-none transition-all focus:!ring-0', + 'animate-in fade-in rounded-full !outline-none transition-all focus:!ring-0', { - 'rounded-r-none border-r-transparent': index === 0, - 'rounded-l-none': index === props.intervals.length - 1, - ['hover:text-primary text-muted-foreground border']: !selected, - ['hover:text-initial hover:bg-background cursor-default font-semibold']: - selected, + 'border-r-transparent': index === 0, + ['hover:text-primary text-muted-foreground']: !selected, + ['cursor-default font-semibold']: selected, + ['hover:bg-initial']: !selected }, ); return (