mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
Merge branch 'main' of github.com:heroui-inc/heroui into canary
This commit is contained in:
commit
d1e18595be
@ -2,7 +2,7 @@ import type {Metadata} from "next";
|
||||
|
||||
import {notFound} from "next/navigation";
|
||||
import {allBlogPosts} from "contentlayer2/generated";
|
||||
import {Link, User} from "@heroui/react";
|
||||
import {Link, Spacer, User} from "@heroui/react";
|
||||
import {format, parseISO} from "date-fns";
|
||||
import NextLink from "next/link";
|
||||
import {Balancer} from "react-wrap-balancer";
|
||||
@ -12,6 +12,7 @@ import {MDXContent} from "@/components/mdx-content";
|
||||
import {siteConfig} from "@/config/site";
|
||||
import {Route} from "@/libs/docs/page";
|
||||
import {ChevronRightLinearIcon} from "@/components/icons";
|
||||
import {CarbonAd} from "@/components/ads/carbon-ad";
|
||||
|
||||
interface BlogPostProps {
|
||||
params: {
|
||||
@ -100,6 +101,10 @@ export default async function DocPage({params}: BlogPostProps) {
|
||||
Back to blog
|
||||
</Link>
|
||||
|
||||
<CarbonAd />
|
||||
|
||||
<Spacer y={4} />
|
||||
|
||||
<time className="block text-small mb-2 text-default-500" dateTime={post.date}>
|
||||
{format(parseISO(post.date), "LLLL d, yyyy")}
|
||||
</time>
|
||||
|
||||
@ -12,7 +12,7 @@ import {siteConfig} from "@/config/site";
|
||||
import {fonts} from "@/config/fonts";
|
||||
import {Navbar} from "@/components/navbar";
|
||||
import {Footer} from "@/components/footer";
|
||||
import {ProBanner} from "@/components/pro-banner";
|
||||
import {PhBanner} from "@/components/ph-banner";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
@ -82,7 +82,7 @@ export default function RootLayout({children}: {children: React.ReactNode}) {
|
||||
>
|
||||
<Providers themeProps={{attribute: "class", defaultTheme: "dark"}}>
|
||||
<div className="relative flex flex-col" id="app-container">
|
||||
<ProBanner />
|
||||
<PhBanner />
|
||||
<Navbar mobileRoutes={manifest.mobileRoutes} routes={manifest.routes} />
|
||||
{children}
|
||||
<Analytics mode="production" />
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import React, {useCallback, useEffect} from "react";
|
||||
import Script from "next/script";
|
||||
import {Image} from "@heroui/react";
|
||||
|
||||
import carbonOptimize from "./carbon-optimize";
|
||||
|
||||
@ -10,6 +11,13 @@ import {useIsMounted} from "@/hooks/use-is-mounted";
|
||||
import {__PROD__, __ENABLE_ADS__} from "@/utils";
|
||||
|
||||
const EA_PROVIDER_RATIO = 0.85;
|
||||
const PRODUCT_HUNT_ENABLED = true;
|
||||
|
||||
const PH_INFO = {
|
||||
description: "Join the conversation and help us get #1 Product of the Day! ↗",
|
||||
title: "We're live on Product Hunt! (30% OFF)",
|
||||
url: "https://ph.heroui.chat?utm_source=heroui.chat&utm_medium=banner",
|
||||
};
|
||||
|
||||
export const CarbonAd: React.FC<unknown> = () => {
|
||||
const carbonRef = React.useRef(null);
|
||||
@ -41,6 +49,8 @@ export const CarbonAd: React.FC<unknown> = () => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (PRODUCT_HUNT_ENABLED) return;
|
||||
|
||||
const shouldShowEthicalAds = Math.random() < EA_PROVIDER_RATIO;
|
||||
|
||||
let loadCarbon: any = null;
|
||||
@ -96,6 +106,31 @@ export const CarbonAd: React.FC<unknown> = () => {
|
||||
};
|
||||
}, [isMounted]);
|
||||
|
||||
if (PRODUCT_HUNT_ENABLED) {
|
||||
return (
|
||||
<div className="px-2 not-prose hover:opacity-80 transition-[opacity] duration-200 carbon-ad-container max-h-[100px] min-h-[100px] h-[100px] m-0 p-0">
|
||||
<a
|
||||
className="group flex items-center flex gap-2 h-full"
|
||||
href={PH_INFO.url}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<Image
|
||||
alt="Product Hunt"
|
||||
className="m-0 w-[80px] h-[80px] object-cover"
|
||||
src="/product-hunt.png"
|
||||
/>
|
||||
<div className="flex flex-col gap-0.5 pointer-events-none">
|
||||
<div className="text-small md:text-medium font-medium no-underline">
|
||||
{PH_INFO.title}
|
||||
</div>
|
||||
<div className="text-tiny md:text-small text-default-500">{PH_INFO.description}</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!__PROD__ || !__ENABLE_ADS__) return null;
|
||||
|
||||
return (
|
||||
@ -110,7 +145,10 @@ export const CarbonAd: React.FC<unknown> = () => {
|
||||
style={{display: showEthicalAds ? "block" : "none"}}
|
||||
/>
|
||||
</>
|
||||
<div className="carbon-ad-container" style={{display: showEthicalAds ? "none" : "block"}}>
|
||||
<div
|
||||
className="carbon-ad-container max-h-[120px] p-0"
|
||||
style={{display: showEthicalAds ? "none" : "block"}}
|
||||
>
|
||||
<span ref={carbonRef} id="carbon-ad" />
|
||||
</div>
|
||||
</>
|
||||
|
||||
36
apps/docs/components/docs/ph-callout.tsx
Normal file
36
apps/docs/components/docs/ph-callout.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
"use client";
|
||||
|
||||
import NextLink from "next/link";
|
||||
|
||||
const PH_INFO = {
|
||||
description: "Join the conversation and help us get #1 Product of the Day! ↗",
|
||||
title: "Live on Product Hunt!",
|
||||
url: "https://ph.heroui.chat?utm_source=heroui.chat&utm_medium=callout",
|
||||
};
|
||||
|
||||
export const PHCallout = () => {
|
||||
return (
|
||||
<div className="relative w-full max-w-[12rem] flex flex-col items-center border border-default/60 hover:border-default/90 rounded-xl py-6 px-2 cursor-pointer">
|
||||
<div>
|
||||
<p className="leading-[1.025] tracking-tight text-center text-medium font-semibold">
|
||||
{PH_INFO.title}
|
||||
</p>
|
||||
<p className="text-center text-xs mt-2 px-3 font-medium text-default-500 dark:text-default-400 leading-tight">
|
||||
{PH_INFO.description}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-3 w-full max-w-[130px] flex group items-center text-foreground hover:shadow-sm relative overflow-hidden rounded-full p-[2px]">
|
||||
<span className="absolute inset-[-1000%] bg-[conic-gradient(from_90deg_at_50%_50%,#EC733A_0%,#F54180_50%,#EC733A_100%)]" />
|
||||
<div className="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-background transition-background p-2.5 text-xs font-medium hover:font-semibold text-foreground backdrop-blur-3xl">
|
||||
Get 30% off
|
||||
</div>
|
||||
</div>
|
||||
<NextLink
|
||||
className="absolute inset-0 z-[1]"
|
||||
href={PH_INFO.url}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -6,7 +6,7 @@ import {Divider, Spacer} from "@heroui/react";
|
||||
import {ChevronCircleTopLinearIcon} from "@heroui/shared-icons";
|
||||
import scrollIntoView from "scroll-into-view-if-needed";
|
||||
|
||||
import {HeroUIProCallout} from "./heroui-pro-callout";
|
||||
import {PHCallout} from "./ph-callout";
|
||||
|
||||
import {Heading} from "@/libs/docs/utils";
|
||||
import {useScrollSpy} from "@/hooks/use-scroll-spy";
|
||||
@ -124,7 +124,7 @@ export const DocsToc: FC<DocsTocProps> = ({headings}) => {
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<HeroUIProCallout />
|
||||
<PHCallout />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
109
apps/docs/components/ph-banner.tsx
Normal file
109
apps/docs/components/ph-banner.tsx
Normal file
@ -0,0 +1,109 @@
|
||||
"use client";
|
||||
|
||||
import {Icon} from "@iconify/react/dist/offline";
|
||||
import arrowRightIcon from "@iconify/icons-solar/arrow-right-linear";
|
||||
import {usePathname} from "next/navigation";
|
||||
import {useEffect} from "react";
|
||||
import {usePostHog} from "posthog-js/react";
|
||||
|
||||
import emitter from "@/libs/emitter";
|
||||
|
||||
const hideOnPaths = ["examples"];
|
||||
|
||||
export const PhBanner = () => {
|
||||
const posthog = usePostHog();
|
||||
|
||||
const handleClick = () => {
|
||||
posthog.capture("HeroUI Pro Banner", {
|
||||
action: "click",
|
||||
category: "landing-page",
|
||||
});
|
||||
};
|
||||
|
||||
const pathname = usePathname();
|
||||
const shouldBeVisible = !hideOnPaths.some((path) => pathname.includes(path));
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldBeVisible) return;
|
||||
|
||||
// listen to scroll event, dispatch an event when scroll is at the top < 48 px
|
||||
const handleScroll = () => {
|
||||
if (window.scrollY < 48) {
|
||||
emitter.emit("proBannerVisibilityChange", "visible");
|
||||
} else {
|
||||
emitter.emit("proBannerVisibilityChange", "hidden");
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
};
|
||||
}, [shouldBeVisible]);
|
||||
|
||||
if (!shouldBeVisible) return null;
|
||||
|
||||
return (
|
||||
<div className="relative z-50 isolate flex items-center gap-x-6 overflow-hidden bg-background border-b-1 border-divider px-6 py-2 sm:px-3.5 sm:before:flex-1">
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute left-[max(-7rem,calc(50%-52rem))] top-1/2 -z-10 -translate-y-1/2 transform-gpu blur-2xl"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute left-[max(45rem,calc(50%+8rem))] top-1/2 -z-10 -translate-y-1/2 transform-gpu blur-2xl"
|
||||
>
|
||||
<div
|
||||
className="aspect-[577/310] w-[36.0625rem] bg-gradient-to-r from-[#fff] to-[#EB5156] dark:from-[#EC733A] dark:to-[#EB5156] opacity-30 dark:opacity-20"
|
||||
style={{
|
||||
clipPath:
|
||||
"polygon(74.8% 41.9%, 97.2% 73.2%, 100% 34.9%, 92.5% 0.4%, 87.5% 0%, 75% 28.6%, 58.5% 54.6%, 50.1% 56.8%, 46.9% 44%, 48.3% 17.4%, 24.7% 53.9%, 0% 27.9%, 11.9% 74.2%, 24.9% 54.1%, 68.6% 100%, 74.8% 41.9%)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-full items-center justify-between md:justify-center gap-x-3">
|
||||
<a
|
||||
className="text-small flex items-end sm:text-[0.93rem] text-foreground hover:opacity-80 transition-opacity"
|
||||
href="https://ph.heroui.chat?utm_source=heroui.com&utm_medium=top-banner"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span aria-label="rocket" className="hidden md:block" role="img">
|
||||
😺
|
||||
</span>
|
||||
<span
|
||||
className="inline-flex md:ml-1 animate-text-gradient font-medium bg-clip-text text-transparent bg-[linear-gradient(90deg,#EB4533_0%,#8a56cc_50%,#EB4533_100%)] dark:bg-[linear-gradient(90deg,#FFEBF9_0%,#EB4533_50%,#FFEBF9_100%)]"
|
||||
style={{
|
||||
fontSize: "inherit",
|
||||
backgroundSize: "200%",
|
||||
backgroundClip: "text",
|
||||
WebkitBackgroundClip: "text",
|
||||
color: "transparent",
|
||||
}}
|
||||
>
|
||||
We're live on Product Hunt! (30% OFF)
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
className="flex group min-w-[120px] items-center font-semibold text-foreground shadow-sm gap-1.5 relative overflow-hidden rounded-full p-[1px] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
|
||||
href="https://ph.heroui.chat?utm_source=heroui.com&utm_medium=top-banner"
|
||||
rel="noopener noreferrer"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span className="absolute inset-[-1000%] animate-[spin_3s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#EC733A_0%,#EB4533_50%,#EB5156_100%)]" />
|
||||
<div className="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-background group-hover:bg-background/70 transition-background px-3 py-1 text-sm font-medium text-foreground backdrop-blur-3xl">
|
||||
Get 30% off
|
||||
<Icon
|
||||
aria-hidden="true"
|
||||
className="outline-none transition-transform group-hover:translate-x-0.5 [&>path]:stroke-[2px]"
|
||||
icon={arrowRightIcon}
|
||||
width={16}
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -7,6 +7,11 @@ description: API References for HeroUI CLI
|
||||
|
||||
------
|
||||
|
||||
|
||||
<CarbonAd/>
|
||||
|
||||
<Spacer y={4} />
|
||||
|
||||
Here's the API reference for the `HeroUI CLI`.
|
||||
|
||||
Once the `CLI` is installed, run the following command to display available commands:
|
||||
|
||||
@ -9,6 +9,9 @@ API reference for the `HeroUIProvider`.
|
||||
|
||||
------
|
||||
|
||||
|
||||
<CarbonAd/>
|
||||
|
||||
## Import
|
||||
|
||||
<ImportTabs
|
||||
|
||||
@ -8,6 +8,10 @@ description: Learn how to configure and customize colors with HeroUI.
|
||||
HeroUI's plugin enables you to personalize the semantic colors of the theme such as `primary`,
|
||||
`secondary`, `success`, etc.
|
||||
|
||||
<CarbonAd/>
|
||||
|
||||
<Spacer y={4} />
|
||||
|
||||
```js {7,11}
|
||||
module.exports = {
|
||||
plugins: [
|
||||
@ -28,7 +32,7 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
<CarbonAd/>
|
||||
|
||||
|
||||
> **Note**: Colors configurations apply globally across all components.
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ HeroUI provides layout customization options for spacing, fonts, and other visua
|
||||
|
||||
<CarbonAd/>
|
||||
|
||||
<Spacer y={4} />
|
||||
|
||||
```js {4,7,11}
|
||||
module.exports = {
|
||||
|
||||
@ -9,6 +9,8 @@ The development of HeroUI has been guided by a set of specific design and API pr
|
||||
These principles serve as the foundation for our library and play a crucial role in ensuring
|
||||
the efficiency, effectiveness, and user-friendliness of the components we offer.
|
||||
|
||||
<CarbonAd />
|
||||
|
||||
### Simplicity and Usability
|
||||
|
||||
Simplicity is the ultimate sophistication. At HeroUI, we believe in delivering simple and
|
||||
|
||||
@ -7,6 +7,10 @@ description: HeroUI Figma Kit helps you design beautiful and consistent user int
|
||||
|
||||
HeroUI components recreated in Figma. It includes components, colors, and typography from the HeroUI design system.
|
||||
|
||||
<CarbonAd />
|
||||
|
||||
<Spacer y={4} />
|
||||
|
||||
<iframe
|
||||
className="w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg aspect-video"
|
||||
height="600"
|
||||
|
||||
@ -7,6 +7,8 @@ description: HeroUI is a UI library for React that helps you build beautiful and
|
||||
|
||||
Welcome to the HeroUI documentation!
|
||||
|
||||
<CarbonAd />
|
||||
|
||||
<NextImage
|
||||
priority
|
||||
src="/heroui-banner.png"
|
||||
@ -17,6 +19,7 @@ Welcome to the HeroUI documentation!
|
||||
className="w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
|
||||
/>
|
||||
|
||||
|
||||
## What is HeroUI?
|
||||
|
||||
HeroUI is a UI library for React that helps you build beautiful and accessible user interfaces. Created on top of
|
||||
@ -111,6 +114,4 @@ Whether it's a feature request, bug report, or a project to showcase, please get
|
||||
|
||||
PRs on **HeroUI** are always welcome, please see our [contribution guidelines](https://github.com/heroui-inc/heroui/blob/main/CONTRIBUTING.md) to learn how you can contribute to this project.
|
||||
|
||||
<Spacer y={4}/>
|
||||
|
||||
<CarbonAd/>
|
||||
<Spacer y={4}/>
|
||||
BIN
apps/docs/public/product-hunt.png
Normal file
BIN
apps/docs/public/product-hunt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
@ -1,3 +1,10 @@
|
||||
<a href="https://ph.heroui.chat?utm_source=https://github.com/heroui-inc/heroui&utm_medium=banner">
|
||||
<img alt="HeroUI Chat on Product Hunt" src="https://heroui-chat-assets.nyc3.cdn.digitaloceanspaces.com/github_banner-round.png">
|
||||
</a>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://heroui.com">
|
||||
<img width="20%" src="https://raw.githubusercontent.com/heroui-inc/heroui/main/apps/docs/public/isotipo.png" alt="heorui" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user