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
afe5897576
@ -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 {HeroUIChatBanner} from "@/components/heroui-chat-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 />
|
||||
<HeroUIChatBanner />
|
||||
<Navbar mobileRoutes={manifest.mobileRoutes} routes={manifest.routes} />
|
||||
{children}
|
||||
<Analytics mode="production" />
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {HeroUIProvider, ToastProvider} from "@heroui/react";
|
||||
import {HeroUIProvider} from "@heroui/react";
|
||||
import {ThemeProvider as NextThemesProvider} from "next-themes";
|
||||
import {ThemeProviderProps} from "next-themes";
|
||||
import {useRouter} from "next/navigation";
|
||||
@ -44,7 +44,6 @@ export function Providers({children, themeProps}: ProvidersProps) {
|
||||
return (
|
||||
<ProviderWrapper>
|
||||
<HeroUIProvider navigate={router.push}>
|
||||
<ToastProvider />
|
||||
<NextThemesProvider {...themeProps}>{children}</NextThemesProvider>
|
||||
</HeroUIProvider>
|
||||
</ProviderWrapper>
|
||||
|
||||
92
apps/docs/components/heroui-chat-banner.tsx
Normal file
92
apps/docs/components/heroui-chat-banner.tsx
Normal file
@ -0,0 +1,92 @@
|
||||
"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 HeroUIChatBanner = () => {
|
||||
const posthog = usePostHog();
|
||||
|
||||
const handleClick = () => {
|
||||
posthog.capture("HeroUI Chat 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 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://heroui.pro?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,#27272A_0%,#52525B_50%,#52525B_100%)] dark:bg-[linear-gradient(90deg,#E5E5E5_0%,#A1A1AA_50%,#E5E5E5_100%)]"
|
||||
style={{
|
||||
fontSize: "inherit",
|
||||
backgroundSize: "200%",
|
||||
backgroundClip: "text",
|
||||
WebkitBackgroundClip: "text",
|
||||
color: "transparent",
|
||||
}}
|
||||
>
|
||||
Generate, edit and deploy beautiful apps
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
className="flex group min-w-[120px] items-center font-semibold text-background bg-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://heroui.chat?utm_source=heroui.com&utm_medium=top-banner"
|
||||
rel="noopener noreferrer"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-foreground group-hover:bg-foreground/70 transition-background px-3 py-1 text-sm font-medium text-background">
|
||||
HeroUI Chat
|
||||
<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>
|
||||
);
|
||||
};
|
||||
20
apps/docs/components/icons/circle-info.tsx
Normal file
20
apps/docs/components/icons/circle-info.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import {IconSvgProps} from "@/types";
|
||||
|
||||
export const CircleInfo = ({size = 24, width, height, ...props}: IconSvgProps) => (
|
||||
<svg
|
||||
aria-label="CircleInfo"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
viewBox="0 0 16 16"
|
||||
width={size || width}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M8 13.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14m1-9.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0m-.25 3a.75.75 0 0 0-1.5 0V11a.75.75 0 0 0 1.5 0z"
|
||||
fill="#A1A1AA"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@ -17,3 +17,4 @@ export * from "./mirror-left";
|
||||
export * from "./palette-round";
|
||||
export * from "./filters";
|
||||
export * from "./scaling";
|
||||
export * from "./circle-info";
|
||||
|
||||
@ -89,3 +89,23 @@ export const CodeRabbitLogo = () => (
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const MochiiAILogo = () => (
|
||||
<svg height="16.918" viewBox="0 0 100 16.918" width="100" xmlns="http://www.w3.org/2000/svg">
|
||||
<g
|
||||
fill="#7078fc"
|
||||
fillRule="evenodd"
|
||||
fontSize="9pt"
|
||||
id="svgGroup"
|
||||
stroke="#9b7bfa"
|
||||
strokeLinecap="round"
|
||||
strokeWidth="0.25mm"
|
||||
style={{stroke: "#9b7bfa", strokeWidth: "0.25mm", fill: "#7078fc"}}
|
||||
>
|
||||
<path
|
||||
d="M 2.156 16.654 L 0 16.654 L 0 0.264 L 1.98 0.264 L 8.118 8.998 L 7.106 8.998 L 13.2 0.264 L 15.18 0.264 L 15.18 16.654 L 13.002 16.654 L 13.002 2.992 L 13.772 3.234 L 7.678 11.814 L 7.502 11.814 L 1.474 3.234 L 2.156 2.992 L 2.156 16.654 Z M 48.268 16.654 L 46.222 16.654 L 46.222 0 L 48.268 0 L 48.268 7.106 L 47.894 6.908 Q 48.334 5.786 49.313 5.159 A 3.96 3.96 0 0 1 50.973 4.571 A 5.069 5.069 0 0 1 51.612 4.532 A 4.869 4.869 0 0 1 52.96 4.713 A 4.198 4.198 0 0 1 53.889 5.104 Q 54.89 5.676 55.473 6.688 A 4.393 4.393 0 0 1 56.042 8.584 A 5.331 5.331 0 0 1 56.056 8.976 L 56.056 16.654 L 53.988 16.654 L 53.988 9.636 A 4.486 4.486 0 0 0 53.928 8.882 Q 53.857 8.465 53.701 8.12 A 2.628 2.628 0 0 0 53.625 7.964 Q 53.262 7.282 52.624 6.897 A 2.681 2.681 0 0 0 51.512 6.531 A 3.367 3.367 0 0 0 51.15 6.512 A 2.961 2.961 0 0 0 50.092 6.698 A 2.777 2.777 0 0 0 49.676 6.897 Q 49.016 7.282 48.642 7.975 Q 48.268 8.667 48.268 9.634 A 3.42 3.42 0 0 0 48.268 9.636 L 48.268 16.654 Z M 77.352 16.654 L 75.042 16.654 L 80.916 0.264 L 83.468 0.264 L 89.342 16.654 L 87.032 16.654 L 85.69 12.804 L 78.694 12.804 L 77.352 16.654 Z M 43.538 7.722 L 41.712 8.602 Q 41.294 7.678 40.436 7.095 A 3.385 3.385 0 0 0 38.681 6.518 A 4.171 4.171 0 0 0 38.456 6.512 Q 37.378 6.512 36.509 7.062 Q 35.64 7.612 35.134 8.558 Q 34.628 9.504 34.628 10.736 A 4.8 4.8 0 0 0 34.816 12.098 A 4.221 4.221 0 0 0 35.134 12.881 A 3.953 3.953 0 0 0 36.196 14.167 A 3.853 3.853 0 0 0 36.509 14.388 Q 37.378 14.938 38.456 14.938 A 3.659 3.659 0 0 0 39.661 14.744 A 3.287 3.287 0 0 0 40.436 14.355 Q 41.294 13.772 41.712 12.804 L 43.538 13.728 A 4.294 4.294 0 0 1 42.487 15.3 A 4.992 4.992 0 0 1 42.416 15.367 Q 41.646 16.082 40.634 16.5 A 5.609 5.609 0 0 1 38.601 16.916 A 6.426 6.426 0 0 1 38.456 16.918 A 6.332 6.332 0 0 1 36.623 16.66 A 5.509 5.509 0 0 1 35.365 16.104 Q 34.012 15.29 33.242 13.882 A 6.328 6.328 0 0 1 32.493 11.282 A 7.674 7.674 0 0 1 32.472 10.714 Q 32.472 8.932 33.242 7.546 Q 34.012 6.16 35.365 5.346 Q 36.718 4.532 38.456 4.532 A 5.745 5.745 0 0 1 40.249 4.808 A 5.376 5.376 0 0 1 40.634 4.95 Q 41.646 5.368 42.416 6.072 Q 43.186 6.776 43.538 7.722 Z M 22.09 16.572 A 6.319 6.319 0 0 0 24.2 16.918 Q 25.872 16.918 27.247 16.115 Q 28.622 15.312 29.458 13.915 A 5.696 5.696 0 0 0 30.037 12.59 A 6.626 6.626 0 0 0 30.294 10.714 A 7.463 7.463 0 0 0 30.244 9.838 A 5.956 5.956 0 0 0 29.491 7.524 Q 28.688 6.138 27.302 5.335 A 5.832 5.832 0 0 0 26.31 4.878 A 6.319 6.319 0 0 0 24.2 4.532 Q 22.462 4.532 21.076 5.346 Q 19.69 6.16 18.887 7.546 Q 18.084 8.932 18.084 10.714 A 7.441 7.441 0 0 0 18.104 11.262 A 6.103 6.103 0 0 0 18.898 13.904 Q 19.712 15.312 21.098 16.115 A 5.832 5.832 0 0 0 22.09 16.572 Z M 93.566 16.654 L 91.41 16.654 L 91.41 0.264 L 93.566 0.264 L 93.566 16.654 Z M 61.028 16.654 L 58.982 16.654 L 58.982 4.796 L 61.028 4.796 L 61.028 16.654 Z M 66.242 16.654 L 64.196 16.654 L 64.196 4.796 L 66.242 4.796 L 66.242 16.654 Z M 24.2 14.938 Q 25.3 14.938 26.191 14.388 Q 27.082 13.838 27.599 12.87 A 4.425 4.425 0 0 0 28.108 11.008 A 5.279 5.279 0 0 0 28.116 10.714 A 4.819 4.819 0 0 0 27.97 9.507 A 3.988 3.988 0 0 0 27.599 8.569 Q 27.082 7.634 26.191 7.073 Q 25.3 6.512 24.2 6.512 Q 23.078 6.512 22.187 7.073 Q 21.296 7.634 20.768 8.569 A 4.086 4.086 0 0 0 20.273 10.126 A 5.114 5.114 0 0 0 20.24 10.714 A 4.619 4.619 0 0 0 20.467 12.179 A 4.215 4.215 0 0 0 20.768 12.87 A 4.041 4.041 0 0 0 21.866 14.167 A 3.935 3.935 0 0 0 22.187 14.388 A 3.714 3.714 0 0 0 24.026 14.935 A 4.471 4.471 0 0 0 24.2 14.938 Z M 82.5 1.826 L 79.376 10.824 L 85.008 10.824 L 81.884 1.826 L 82.5 1.826 Z M 72.38 16.654 L 70.246 16.654 L 70.246 14.014 L 72.38 14.014 L 72.38 16.654 Z M 61.028 2.904 L 58.982 2.904 L 58.982 0.264 L 61.028 0.264 L 61.028 2.904 Z M 66.242 2.904 L 64.196 2.904 L 64.196 0.264 L 66.242 0.264 L 66.242 2.904 Z"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {Button, Link} from "@heroui/react";
|
||||
|
||||
import {sectionWrapper} from "@/components/primitives";
|
||||
import {Story2DesignLogo, CodeRabbitLogo} from "@/components/icons/sponsors";
|
||||
import {Story2DesignLogo, CodeRabbitLogo, MochiiAILogo} from "@/components/icons/sponsors";
|
||||
import {HeartFilledIcon} from "@/components/icons";
|
||||
import {siteConfig} from "@/config/site";
|
||||
import {Sponsor, SponsorItem} from "@/components/marketing/sponsor-item";
|
||||
@ -17,6 +17,11 @@ const sponsors: Sponsor[] = [
|
||||
href: "https://coderabbit.ai/?utm_source=heroui&utm_marketing=oss",
|
||||
logo: <CodeRabbitLogo />,
|
||||
},
|
||||
{
|
||||
name: "Mochii.AI",
|
||||
href: "https://www.mochii.ai/?utm_source=heroui&utm_marketing=oss",
|
||||
logo: <MochiiAILogo />,
|
||||
},
|
||||
];
|
||||
|
||||
export const Sponsors = () => {
|
||||
|
||||
@ -1,18 +1,39 @@
|
||||
import {Tooltip} from "@heroui/react";
|
||||
import {clsx} from "@heroui/shared-utils";
|
||||
|
||||
import {CircleInfo} from "@/components/icons";
|
||||
|
||||
interface ConfigurationSectionProps {
|
||||
children: React.ReactNode;
|
||||
id?: string;
|
||||
title: string;
|
||||
icon?: React.ReactNode;
|
||||
visualPurposeOnly?: boolean;
|
||||
}
|
||||
|
||||
export function ConfigSection({children, id, title, icon}: ConfigurationSectionProps) {
|
||||
export function ConfigSection({
|
||||
children,
|
||||
id,
|
||||
title,
|
||||
icon,
|
||||
visualPurposeOnly,
|
||||
}: ConfigurationSectionProps) {
|
||||
return (
|
||||
<div id={id}>
|
||||
<div className="text-[#71717A] dark:text-[#A1A1AA] text-md font-medium leading-7 flex gap-1.5 items-center">
|
||||
<div>{icon}</div>
|
||||
<div>{title}</div>
|
||||
{visualPurposeOnly && (
|
||||
<Tooltip
|
||||
classNames={{content: "text-tiny text-default-600"}}
|
||||
content="For visual purpose only"
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<CircleInfo className="h-4 w-4 opacity-80 dark:opacity-60" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className={clsx("flex flex-wrap gap-2 mt-3")}>{children}</div>
|
||||
</div>
|
||||
|
||||
@ -15,7 +15,7 @@ export function BorderWidths() {
|
||||
const {borderWidthValue, setBorderWidthValue} = useThemeBuilder();
|
||||
|
||||
return (
|
||||
<ConfigSection icon={<Crop className="w-4 h-4" />} title="Border width">
|
||||
<ConfigSection visualPurposeOnly icon={<Crop className="w-4 h-4" />} title="Border width">
|
||||
{BORDER_WIDTHS.map(({title, className}) => (
|
||||
<EditableButton
|
||||
key={title}
|
||||
|
||||
@ -9,7 +9,7 @@ export function Fonts() {
|
||||
const {font, setFont} = useThemeBuilder();
|
||||
|
||||
return (
|
||||
<ConfigSection icon={<TextSquare className="h-4 w-4" />} title="Font Family">
|
||||
<ConfigSection visualPurposeOnly icon={<TextSquare className="h-4 w-4" />} title="Font Family">
|
||||
<FontButton className="rounded-tl-none" setValue={setFont} title="Inter" value={font} />
|
||||
<FontButton className="rounded-tl-sm" setValue={setFont} title="Roboto" value={font} />
|
||||
<FontButton className="rounded-tl-md" setValue={setFont} title="Outfit" value={font} />
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
ScrollShadow,
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
cn,
|
||||
} from "@heroui/react";
|
||||
import {useTheme} from "next-themes";
|
||||
import {useLocalStorage} from "usehooks-ts";
|
||||
@ -54,7 +55,11 @@ export default function Configuration() {
|
||||
setRadiusValue,
|
||||
setBorderWidthValue,
|
||||
} = useThemeBuilder();
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(null);
|
||||
|
||||
const [lsConfig] = useLocalStorage<Config>(configKey, initialConfig);
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(
|
||||
templates.filter((t) => t.name === lsConfig.name)[0],
|
||||
);
|
||||
const themeProps = useTheme();
|
||||
const theme = themeProps.theme as ThemeType;
|
||||
const prevTheme = usePrevious(theme);
|
||||
@ -78,21 +83,10 @@ export default function Configuration() {
|
||||
|
||||
// Set the configuration in the local storage when the theme changes
|
||||
if (prevTheme === theme) {
|
||||
setLsConfig(config);
|
||||
setLsConfig({...config});
|
||||
}
|
||||
}, [config, theme, prevTheme]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
const template = templates[0];
|
||||
|
||||
setConfiguration(template.value, theme, syncThemes);
|
||||
setAllCssVars(template.value, theme);
|
||||
setSelectedTemplate(template);
|
||||
setTemplateTheme(template.name);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setRadiusValue(templateTheme === "elegant" ? "none" : "md");
|
||||
setBorderWidthValue(templateTheme === "elegant" ? "thin" : "medium");
|
||||
@ -110,7 +104,7 @@ export default function Configuration() {
|
||||
|
||||
setAllCssVars(config, theme);
|
||||
}
|
||||
setLsConfig(config);
|
||||
setLsConfig({...config});
|
||||
}
|
||||
|
||||
function handleCopy() {
|
||||
@ -203,7 +197,7 @@ export default function Configuration() {
|
||||
<Button
|
||||
disableRipple
|
||||
isIconOnly
|
||||
className="dark:bg-[#18181B] bg-[#d4d4d8] group hover:text-default-600 text-default-400 left-1/2 transform -translate-x-1/2 w-full flex-col"
|
||||
className="dark:bg-[#18181B] bg-[#d4d4d8] group hover:text-default-600 text-default-400 left-1/2 transform -translate-x-1/2 w-full flex-col h-6"
|
||||
onPress={() => {
|
||||
setIsDrawerOpen(!isDrawerOpen);
|
||||
}}
|
||||
@ -221,26 +215,29 @@ export default function Configuration() {
|
||||
setIsDrawerOpen(false);
|
||||
}}
|
||||
>
|
||||
<DrawerContent className="backdrop-blur-2xl dark:bg-[#18181B] bg-[#ffffff] max-h-[56rem]">
|
||||
<DrawerContent className="bg-transparent backdrop-blur-xl max-h-[56rem]">
|
||||
<div className="p-4 pt-8 flex flex-col gap-y-4">
|
||||
<Button
|
||||
isIconOnly
|
||||
className="group fixed top-0 right-0 dark:bg-white/10 bg-[#d4d4d8] data-[hover=true]:bg-black/30 dark:data-[hover=true]:bg-white/20 z-50 min-w-8 w-8 h-8 rounded-full m-1"
|
||||
className="group fixed top-1 right-1 dark:bg-white/10 bg-[#d4d4d8] data-[hover=true]:bg-black/30 dark:data-[hover=true]:bg-white/20 z-50 min-w-4 w-4 h-4 rounded-full p-0.5"
|
||||
onPress={() => {
|
||||
setIsDrawerOpen(false);
|
||||
setSelectedSection("none");
|
||||
}}
|
||||
>
|
||||
<CloseIcon className="h-4 w-4" />
|
||||
<CloseIcon className="h-3 w-3" />
|
||||
</Button>
|
||||
{selectedSection === "none" && (
|
||||
<div className="flex w-full flex-start overflow-x-scroll scrollbar-hide py-6 px-4 h-30 fixed top-5">
|
||||
<div className="flex w-full flex-start overflow-x-scroll scrollbar-hide h-30 gap-x-4">
|
||||
{templates.map((template) => {
|
||||
return (
|
||||
<div key={template.name} className="flex flex-col items-center px-2">
|
||||
<div key={template.name} className="flex flex-col items-center">
|
||||
<Button
|
||||
className={clsx(
|
||||
"p-0 min-w-0 w-auto h-12 border border-black/5 gap-0",
|
||||
templateTheme === template.name ? "outline-2 outline-foreground-800" : "",
|
||||
"p-0 min-w-0 w-auto h-10 border border-black/5 gap-0 rounded-sm overflow-hidden m-[3px]",
|
||||
templateTheme === template.name
|
||||
? "outline-1 outline-foreground-800"
|
||||
: "",
|
||||
)}
|
||||
onPress={() => {
|
||||
setConfiguration(template.value, theme, syncThemes);
|
||||
@ -262,91 +259,108 @@ export default function Configuration() {
|
||||
...template.value.light.baseColor,
|
||||
}
|
||||
}
|
||||
innerClassName="w-4"
|
||||
innerClassName="w-2.5"
|
||||
/>
|
||||
</Button>
|
||||
<div className="text-sm dark:text-white/60 text-black/60 my-1">
|
||||
{template.name}
|
||||
<div className="text-tiny text-foreground my-1 font-medium">
|
||||
{template.label}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className="overflow-x-scroll scrollbar-hide p-2 px-4 pt-16">
|
||||
<div className="overflow-x-scroll scrollbar-hide">
|
||||
<ScrollShadow orientation="vertical">
|
||||
<div className="flex flex-col items-center gap-y-8">
|
||||
{selectedSection === "none" && (
|
||||
<>
|
||||
<div className="w-full grid grid-cols-4 gap-4 flex-wrap items-center justify-around pt-20">
|
||||
<div className="grid grid-cols-4 sm:grid-cols-6 gap-x-3 gap-y-4 w-full">
|
||||
<Button
|
||||
className="col-span-2 h-14 flex items-center justify-center sm:justify-around gap-x-3 dark:bg-[#3f3f46] bg-[#d4d4d8] dark:text-white"
|
||||
className="py-2 px-3 h-auto col-span-2 w-full"
|
||||
onPress={() => {
|
||||
setSelectedSection("color");
|
||||
}}
|
||||
>
|
||||
<Filters className="h-4 w-4 hidden sm:flex" />
|
||||
<span className="mx-2 w-14 text-sm sm:text-base">Colors</span>{" "}
|
||||
<ChevronIcon className="h-5 w-5 rotate-180" />
|
||||
<div className="flex gap-x-2 justity-start items-center px-1.5 pb-0.5 h-9">
|
||||
<Filters className="h-5 w-5" />
|
||||
<span className="mx-2 w-14 text-sm text-foreground">Colors</span>{" "}
|
||||
</div>
|
||||
<ChevronIcon className="h-4 w-4 rotate-180" />
|
||||
</Button>
|
||||
<Button
|
||||
className="col-span-2 h-14 flex items-center justify-center sm:justify-around gap-x-3 dark:bg-[#3f3f46] bg-[#d4d4d8] dark:text-white"
|
||||
className="py-2 px-3 h-auto col-span-2 w-full"
|
||||
onPress={() => {
|
||||
setSelectedSection("radius");
|
||||
}}
|
||||
>
|
||||
<Crop className="h-4 w-4 hidden sm:flex" />
|
||||
<span className="mx-2 w-14 text-sm sm:text-base">Radius</span>{" "}
|
||||
<ChevronIcon className="h-5 w-5 rotate-180" />
|
||||
<div className="flex gap-x-2 justity-start items-center px-1.5 pb-0.5 h-9">
|
||||
<Crop className="h-5 w-5" />
|
||||
<span className="mx-2 w-14 text-sm text-foreground">Radius</span>{" "}
|
||||
</div>
|
||||
<ChevronIcon className="h-4 w-4 rotate-180" />
|
||||
</Button>
|
||||
<Button
|
||||
className="col-span-2 h-14 text-lg flex items-center justify-center sm:justify-around gap-x-3 dark:bg-[#3f3f46] bg-[#d4d4d8] dark:text-white"
|
||||
className="py-2 px-3 h-auto col-span-2 w-full"
|
||||
onPress={() => {
|
||||
setSelectedSection("borderWidths");
|
||||
}}
|
||||
>
|
||||
<CropMinimalistic className="h-4 w-4 hidden sm:flex" />
|
||||
<span className="mx-2 w-14 text-sm sm:text-base">Border</span>{" "}
|
||||
<ChevronIcon className="h-5 w-5 rotate-180" />
|
||||
<div className="flex gap-x-2 justity-start items-center px-1.5 pb-0.5 h-9">
|
||||
<CropMinimalistic className="h-5 w-5" />
|
||||
<span className="mx-2 w-14 text-sm text-foreground">Border</span>{" "}
|
||||
</div>
|
||||
<ChevronIcon className="h-4 w-4 rotate-180" />
|
||||
</Button>
|
||||
<Button
|
||||
className="col-span-2 h-14 text-lg flex items-center justify-center sm:justify-around gap-x-3 dark:bg-[#3f3f46] bg-[#d4d4d8] dark:text-white"
|
||||
className="py-2 px-3 h-auto col-span-2 w-full"
|
||||
onPress={() => {
|
||||
setSelectedSection("opacity");
|
||||
}}
|
||||
>
|
||||
<RadialBlur className="h-4 w-4 hidden sm:flex" />
|
||||
<span className="mx-2 w-14 text-sm sm:text-base">Opacity</span>{" "}
|
||||
<ChevronIcon className="h-5 w-5 rotate-180" />
|
||||
<div className="flex gap-x-2 justity-start items-center px-1.5 pb-0.5 h-9">
|
||||
<RadialBlur className="h-5 w-5" />
|
||||
<span className="mx-2 w-14 text-sm text-foreground">
|
||||
Opacity
|
||||
</span>{" "}
|
||||
</div>
|
||||
<ChevronIcon className="h-4 w-4 rotate-180" />
|
||||
</Button>
|
||||
<Button
|
||||
className="col-span-2 h-14 text-lg flex items-center justify-center sm:justify-around gap-x-3 dark:bg-[#3f3f46] bg-[#d4d4d8] dark:text-white"
|
||||
className="py-2 px-3 h-auto col-span-2 w-full"
|
||||
onPress={() => {
|
||||
setSelectedSection("font");
|
||||
}}
|
||||
>
|
||||
<RadialBlur className="h-4 w-4 hidden sm:flex" />
|
||||
<span className="mx-2 w-14 text-sm sm:text-base">Font</span>{" "}
|
||||
<ChevronIcon className="h-5 w-5 rotate-180" />
|
||||
<div className="flex gap-x-2 justity-start items-center px-1.5 pb-0.5 h-9">
|
||||
<RadialBlur className="h-5 w-5" />
|
||||
<span className="mx-2 w-14 text-sm text-foreground">Font</span>{" "}
|
||||
</div>
|
||||
<ChevronIcon className="h-4 w-4 rotate-180" />
|
||||
</Button>
|
||||
<Button
|
||||
className="col-span-2 h-14 text-lg flex items-center justify-center sm:justify-around gap-x-3 dark:bg-[#3f3f46] bg-[#d4d4d8] dark:text-white"
|
||||
className="py-2 px-3 h-auto col-span-2 w-full"
|
||||
onPress={() => {
|
||||
setSelectedSection("scaling");
|
||||
}}
|
||||
>
|
||||
<ScalingIcon className="h-6 w-6 hidden sm:flex" />
|
||||
<span className="mx-2 w-14 text-sm sm:text-base">Scaling</span>{" "}
|
||||
<ChevronIcon className="h-5 w-5 rotate-180" />
|
||||
<div className="flex gap-x-2 justity-start items-center px-1.5 pb-0.5 h-9">
|
||||
<ScalingIcon className="h-5 w-5" />
|
||||
<span className="mx-2 w-14 text-sm text-foreground">
|
||||
Scaling
|
||||
</span>{" "}
|
||||
</div>
|
||||
<ChevronIcon className="h-4 w-4 rotate-180" />
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{selectedSection === "color" && (
|
||||
<div className="w-full h-auto">
|
||||
<div className="w-full h-auto flex flex-col gap-y-4">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<Button
|
||||
isIconOnly
|
||||
className="absolute left-3 top-1 text-black/60 dark:text-white/60 dark:data-[hover=true]:bg-white/20 data-[hover=true]:bg-black/10 cursor-pointer"
|
||||
className="text-default-500 bg-transparent data-[hover=true]:bg-transparent data-[hover=true]:text-default-700 min-w-fit w-fit"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
setSelectedSection("none");
|
||||
@ -354,7 +368,9 @@ export default function Configuration() {
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5" strokeWidth={2} />
|
||||
</Button>
|
||||
<div className="flex flex-col gap-y-4 h-auto p-4">
|
||||
<div className="text-2xl font-medium">Color</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-4 h-auto">
|
||||
<DefaultColors config={config} theme={theme} />
|
||||
<BaseColors
|
||||
config={config}
|
||||
@ -368,10 +384,11 @@ export default function Configuration() {
|
||||
</div>
|
||||
)}
|
||||
{selectedSection === "radius" && (
|
||||
<div className="w-full h-full">
|
||||
<div className="w-full h-auto flex flex-col gap-y-4">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<Button
|
||||
isIconOnly
|
||||
className="absolute left-3 top-1 text-black/60 dark:text-white/60 dark:data-[hover=true]:bg-white/20 data-[hover=true]:bg-black/10 cursor-pointer"
|
||||
className="text-default-500 bg-transparent data-[hover=true]:bg-transparent data-[hover=true]:text-default-700 min-w-fit w-fit"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
setSelectedSection("none");
|
||||
@ -379,16 +396,19 @@ export default function Configuration() {
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5" strokeWidth={2} />
|
||||
</Button>
|
||||
<div className="p-4">
|
||||
<div className="text-2xl font-medium">Radius</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-4 h-auto">
|
||||
<Radiuses />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{selectedSection === "borderWidths" && (
|
||||
<div className="w-full h-full">
|
||||
<div className="w-full h-auto flex flex-col gap-y-4">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<Button
|
||||
isIconOnly
|
||||
className="absolute left-3 top-1 text-black/60 dark:text-white/60 dark:data-[hover=true]:bg-white/20 data-[hover=true]:bg-black/10 cursor-pointer"
|
||||
className="text-default-500 bg-transparent data-[hover=true]:bg-transparent data-[hover=true]:text-default-700 min-w-fit w-fit"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
setSelectedSection("none");
|
||||
@ -396,33 +416,19 @@ export default function Configuration() {
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5" strokeWidth={2} />
|
||||
</Button>
|
||||
<div className="p-4">
|
||||
<div className="text-2xl font-medium">Border Width</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-4 h-auto">
|
||||
<BorderWidths />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{selectedSection === "font" && (
|
||||
<div className="w-full h-full">
|
||||
<Button
|
||||
isIconOnly
|
||||
className="absolute left-3 top-1 text-black/60 dark:text-white/60 dark:data-[hover=true]:bg-white/20 data-[hover=true]:bg-black/10 cursor-pointer"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
setSelectedSection("none");
|
||||
}}
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5" strokeWidth={2} />
|
||||
</Button>
|
||||
<div className="p-4">
|
||||
<Fonts />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{selectedSection === "opacity" && (
|
||||
<div className="w-full h-full">
|
||||
<div className="w-full h-auto flex flex-col gap-y-4">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<Button
|
||||
isIconOnly
|
||||
className="absolute left-3 top-1 text-black/60 dark:text-white/60 dark:data-[hover=true]:bg-white/20 data-[hover=true]:bg-black/10 cursor-pointer"
|
||||
className="text-default-500 bg-transparent data-[hover=true]:bg-transparent data-[hover=true]:text-default-700 min-w-fit w-fit"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
setSelectedSection("none");
|
||||
@ -430,16 +436,19 @@ export default function Configuration() {
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5" strokeWidth={2} />
|
||||
</Button>
|
||||
<div className="p-4">
|
||||
<div className="text-2xl font-medium">Opacity</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-4 h-auto">
|
||||
<DisableOpacity config={config} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{selectedSection === "scaling" && (
|
||||
<div className="w-full h-full">
|
||||
{selectedSection === "font" && (
|
||||
<div className="w-full h-auto flex flex-col gap-y-4">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<Button
|
||||
isIconOnly
|
||||
className="absolute left-3 top-1 text-black/60 dark:text-white/60 dark:data-[hover=true]:bg-white/20 data-[hover=true]:bg-black/10 cursor-pointer"
|
||||
className="text-default-500 bg-transparent data-[hover=true]:bg-transparent data-[hover=true]:text-default-700 min-w-fit w-fit"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
setSelectedSection("none");
|
||||
@ -447,7 +456,29 @@ export default function Configuration() {
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5" strokeWidth={2} />
|
||||
</Button>
|
||||
<div className="p-4">
|
||||
<div className="text-2xl font-medium">Font Family</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-4 h-auto">
|
||||
<Fonts />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{selectedSection === "scaling" && (
|
||||
<div className="w-full h-auto flex flex-col gap-y-4">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<Button
|
||||
isIconOnly
|
||||
className="text-default-500 bg-transparent data-[hover=true]:bg-transparent data-[hover=true]:text-default-700 min-w-fit w-fit"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
setSelectedSection("none");
|
||||
}}
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5" strokeWidth={2} />
|
||||
</Button>
|
||||
<div className="text-2xl font-medium">Scaling</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-4 h-auto">
|
||||
<Scaling />
|
||||
</div>
|
||||
</div>
|
||||
@ -455,11 +486,25 @@ export default function Configuration() {
|
||||
</div>
|
||||
</ScrollShadow>
|
||||
</div>
|
||||
<Divider className="my-2 p-0" />
|
||||
<div className="flex flex-col items-center px-8 pb-4">
|
||||
</div>
|
||||
<Divider className={cn("my-2 p-0", {hidden: selectedSection != "none"})} />
|
||||
<div
|
||||
className={cn("flex flex-col items-center px-4 pb-4 gap-y-2", {
|
||||
hidden: selectedSection != "none",
|
||||
})}
|
||||
>
|
||||
<Button fullWidth className="text-white bg-blue-500" onPress={handleCopy}>
|
||||
Copy Theme
|
||||
</Button>
|
||||
<div className="text-tiny text-default-500">
|
||||
Learn how to setup your theme{" "}
|
||||
<Link
|
||||
className="text-default-700 text-tiny underline cursor-pointer"
|
||||
href="/docs/customization/theme"
|
||||
>
|
||||
here
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
@ -9,7 +9,7 @@ export function Radiuses() {
|
||||
const {radiusValue, setRadiusValue} = useThemeBuilder();
|
||||
|
||||
return (
|
||||
<ConfigSection icon={<CropMinimalistic className="h-4 w-4" />} title="Radius">
|
||||
<ConfigSection visualPurposeOnly icon={<CropMinimalistic className="h-4 w-4" />} title="Radius">
|
||||
<EditableButton
|
||||
aria-label="No border radius"
|
||||
className="rounded-tl-none"
|
||||
|
||||
@ -10,7 +10,7 @@ export function Scaling() {
|
||||
const scaleValues = [90, 95, 100, 105, 110];
|
||||
|
||||
return (
|
||||
<ConfigSection icon={<ScalingIcon className="h-4 w-4" />} title="Scaling">
|
||||
<ConfigSection visualPurposeOnly icon={<ScalingIcon className="h-4 w-4" />} title="Scaling">
|
||||
{scaleValues.map((value) => (
|
||||
<ValueButton
|
||||
key={value}
|
||||
|
||||
@ -105,6 +105,7 @@ export const initialLayout: ConfigLayout = {
|
||||
};
|
||||
|
||||
export const initialConfig: Config = {
|
||||
name: "heroui",
|
||||
light: initialLightTheme,
|
||||
dark: initialDarkTheme,
|
||||
layout: initialLayout,
|
||||
|
||||
@ -100,6 +100,16 @@ export default function ThemeBuilderProvider({children}: ThemeBuilderProviderPro
|
||||
);
|
||||
};
|
||||
|
||||
const setTemplate = (template: TemplateType) => {
|
||||
setTemplateTheme(template);
|
||||
setConfig((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
name: template,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const resetConfig = (theme: ThemeType, sync: boolean) => {
|
||||
let newConfig = initialConfig;
|
||||
|
||||
@ -216,14 +226,14 @@ export default function ThemeBuilderProvider({children}: ThemeBuilderProviderPro
|
||||
...prev,
|
||||
light: {
|
||||
...prev.light,
|
||||
otherColor: {
|
||||
layoutColor: {
|
||||
...prev.light.layoutColor,
|
||||
...newConfig,
|
||||
},
|
||||
},
|
||||
dark: {
|
||||
...prev.dark,
|
||||
otherColor: {
|
||||
layoutColor: {
|
||||
...prev.dark.layoutColor,
|
||||
...newConfig,
|
||||
},
|
||||
@ -233,7 +243,7 @@ export default function ThemeBuilderProvider({children}: ThemeBuilderProviderPro
|
||||
...prev,
|
||||
[theme]: {
|
||||
...prev[theme],
|
||||
otherColor: {
|
||||
layoutColor: {
|
||||
...prev[theme].layoutColor,
|
||||
...newConfig,
|
||||
},
|
||||
@ -324,7 +334,7 @@ export default function ThemeBuilderProvider({children}: ThemeBuilderProviderPro
|
||||
setContentColor,
|
||||
setRadiusValue,
|
||||
setBorderWidthValue,
|
||||
setTemplateTheme,
|
||||
setTemplateTheme: setTemplate,
|
||||
setFont,
|
||||
setScaling,
|
||||
}}
|
||||
|
||||
@ -57,6 +57,7 @@ export interface ThemeColor extends ColorShades {
|
||||
|
||||
// Configuration
|
||||
export interface Config {
|
||||
name: TemplateType;
|
||||
light: ConfigColors;
|
||||
dark: ConfigColors;
|
||||
layout: ConfigLayout;
|
||||
|
||||
@ -19,7 +19,7 @@ function generateThemeColorsConfig(config: Config, theme: ThemeType) {
|
||||
warning: generateThemeColor(config[theme].baseColor.warning, "warning", "light"),
|
||||
danger: generateThemeColor(config[theme].baseColor.danger, "danger", "light"),
|
||||
background: config[theme].layoutColor.background,
|
||||
foreground: generateThemeColor(config[theme].layoutColor.foreground, "foreground", "light"),
|
||||
foreground: config[theme].layoutColor.foreground,
|
||||
content1: {
|
||||
DEFAULT: config[theme].contentColor.content1,
|
||||
foreground: readableColor(config[theme].contentColor.content1),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: "HeroUI v2.7.0"
|
||||
description: "New Toast component, NumberInput, Theme Generator, and lots of bug fixes and improvements."
|
||||
date: "2025-02-19"
|
||||
date: "2025-02-18"
|
||||
image: "/blog/v2.7.0.jpg"
|
||||
tags: ["heroui", "v2.7.0", "release", "toast", "improvements", "theme"]
|
||||
author:
|
||||
@ -31,7 +31,7 @@ HeroUI version **v2.7.0** introduces the highly anticipated Toast component, alo
|
||||
## What's New in v2.7.0?
|
||||
|
||||
- [Toast Component](#toast-component) - A new toast notification system with rich features
|
||||
- [NumberInput Component](#numberinput-component) - A new input component specifically designed for numerical values
|
||||
- [NumberInput Component](#numbaerinput-component) - A new input component specifically designed for numerical values
|
||||
- [New Spinner Variants](#new-spinner-variants) - Enhanced spinner component with new design variants
|
||||
- [Theme Generator](#theme-generator) - A powerful web-based tool for creating and customizing your themes
|
||||
- [Table Virtualization](#table-virtualization) - Performance improvements for large datasets in Table component
|
||||
@ -114,9 +114,12 @@ function Example() {
|
||||
}
|
||||
```
|
||||
|
||||
<Spacer y={2} />
|
||||
|
||||
<CodeDemo
|
||||
title="Simple Usage"
|
||||
files={simpleToast}
|
||||
showEditor={false}
|
||||
/>
|
||||
|
||||
|
||||
@ -152,7 +155,7 @@ For more examples and detailed documentation about the Spinner component, visit
|
||||
|
||||
## Theme Generator
|
||||
|
||||
The new Theme Generator is a powerful web-based tool that allows you to create and customize your themes visually. Simply visit our [Theme Generator](/themes) to:
|
||||
The new Theme Generator is a powerful web-based tool that allows you to create and customize your themes visually. Based on the amazing work by [xylish7](https://github.com/xylish7) in the [nextui-theme-generator](https://github.com/xylish7/nextui-theme-generator) project (huge thanks!), our Theme Generator provides a seamless experience for theme customization. Simply visit our [Theme Generator](/themes) to:
|
||||
|
||||
- Create custom color schemes
|
||||
- Preview components with your theme in real-time
|
||||
@ -232,7 +235,7 @@ import {HeroUIProvider} from "@heroui/react";
|
||||
function App() {
|
||||
return (
|
||||
<HeroUIProvider spinnerVariant="simple">
|
||||
{/* All components will use the dots spinner variant by default */}
|
||||
{/* All components will use the "simple" spinner variant by default */}
|
||||
</HeroUIProvider>
|
||||
);
|
||||
}
|
||||
@ -283,8 +286,12 @@ We're building an exciting new application that will revolutionize frontend deve
|
||||
## Breaking Changes
|
||||
|
||||
- Renamed `wrapper` slot to `tabWrapper` in Tabs component
|
||||
- Deprecated `dateInputClassNames` in favor of new styling approach
|
||||
- Replaced directional terms `left` & `right` with `start` & `end` for better RTL support
|
||||
- Deprecated `dateInputClassNames` in favor of new styling approach. The existing styles can be moved to `classNames` instead.
|
||||
- Replaced directional terms `left` & `right` with `start` & `end` for better RTL support.
|
||||
- `ListboxItem`, `SelectItem` & AutocompleteItem no longer accept a `value` prop.
|
||||
- Spinner component is no longer a server component. If you are using global import, you need to add `use client` directive.
|
||||
- For those users using `@internationalized/date`, please bump to `3.7.0` to avoid incompatibility errors.
|
||||
- For those users using `@react-aria/i18n`, please bump to `3.12.5` to avoid incompatibility errors.
|
||||
|
||||
## Release Changes
|
||||
|
||||
@ -353,7 +360,7 @@ We're building an exciting new application that will revolutionize frontend deve
|
||||
- Rebranding by [@jrgarciadev](https://github.com/jrgarciadev), [@macci001](https://github.com/macci001), [@plbstl](https://github.com/plbstl) in [PR #4594](https://github.com/heroui-inc/heroui/pull/4594), [PR #4620](https://github.com/heroui-inc/heroui/pull/4620), [PR #4645](https://github.com/heroui-inc/heroui/pull/4645)
|
||||
- Updated author in package.json by [@wingkwong](https://github.com/wingkwong) in [#4800](https://github.com/heroui-inc/heroui/pull/4800)
|
||||
|
||||
For more details about this release, check out our [GitHub release page](https://github.com/heroui-inc/heroui/releases/tag/v2.7.0).
|
||||
For more details about this release, check out our [GitHub release page](https://github.com/heroui-inc/heroui/releases/tag/%40heroui%2Freact%402.7.0).
|
||||
|
||||
|
||||
Special thanks to HeroUI Team members [@wingkwong](https://github.com/wingkwong), [@macci001](https://github.com/macci001), [@vinroger](https://github.com/vinroger),
|
||||
|
||||
@ -3,16 +3,16 @@ import {addToast, Button} from "@heroui/react";
|
||||
export default function App() {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{["default", "primary", "secondary", "success", "warning", "danger"].map((color) => (
|
||||
{["Default", "Primary", "Secondary", "Success", "Warning", "Danger"].map((color) => (
|
||||
<Button
|
||||
key={color}
|
||||
color={color}
|
||||
color={color.toLowerCase()}
|
||||
variant={"flat"}
|
||||
onPress={() =>
|
||||
addToast({
|
||||
title: "Toast title",
|
||||
description: "Toast displayed successfully",
|
||||
color: color,
|
||||
color: color.toLowerCase(),
|
||||
})
|
||||
}
|
||||
>
|
||||
|
||||
@ -1,25 +1,36 @@
|
||||
import {addToast, Button} from "@heroui/react";
|
||||
import {addToast, ToastProvider, Button} from "@heroui/react";
|
||||
import React from "react";
|
||||
|
||||
export default function App() {
|
||||
const [placement, setPlacement] = React.useState("bottom-right");
|
||||
|
||||
return (
|
||||
<>
|
||||
<ToastProvider placement={placement} toastOffset={placement.includes("top") ? 60 : 0} />
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{["top-left", "top-center", "top-right", "bottom-left", "bottom-center", "bottom-right"].map(
|
||||
(position) => (
|
||||
{[
|
||||
["Top Left", "top-left"],
|
||||
["Top Center", "top-center"],
|
||||
["Top Right", "top-right"],
|
||||
["Bottom Left", "bottom-left"],
|
||||
["Bottom Center", "bottom-center"],
|
||||
["Bottom Right", "bottom-right"],
|
||||
].map((position) => (
|
||||
<Button
|
||||
key={position}
|
||||
key={position[1]}
|
||||
variant={"flat"}
|
||||
onPress={() => {
|
||||
setPlacement(position[1]);
|
||||
addToast({
|
||||
title: "Toast title",
|
||||
description: "Toast displayed successfully",
|
||||
});
|
||||
}}
|
||||
>
|
||||
{position}
|
||||
{position[0]}
|
||||
</Button>
|
||||
),
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -3,20 +3,26 @@ import {addToast, Button} from "@heroui/react";
|
||||
export default function App() {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{["none", "sm", "md", "lg", "full"].map((radius) => (
|
||||
{[
|
||||
["None", "none"],
|
||||
["Small", "sm"],
|
||||
["Medium", "md"],
|
||||
["Large", "lg"],
|
||||
["Full", "full"],
|
||||
].map((radius) => (
|
||||
<Button
|
||||
key={radius}
|
||||
radius={radius}
|
||||
key={radius[1]}
|
||||
radius={radius[1]}
|
||||
variant={"flat"}
|
||||
onPress={() =>
|
||||
addToast({
|
||||
title: "Toast title",
|
||||
description: "Toast displayed successfully",
|
||||
radius: radius,
|
||||
radius: radius[1],
|
||||
})
|
||||
}
|
||||
>
|
||||
{radius}
|
||||
{radius[0]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import {addToast, Button} from "@heroui/react";
|
||||
import {addToast, Button, ToastProvider} from "@heroui/react";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
<ToastProvider />
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button
|
||||
onPress={() => {
|
||||
@ -14,5 +16,6 @@ export default function App() {
|
||||
Show Toast
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -4,9 +4,9 @@ export default function App() {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{[
|
||||
["solid", "solid"],
|
||||
["bordered", "bordered"],
|
||||
["flat", "faded"],
|
||||
["Solid", "solid"],
|
||||
["Bordered", "bordered"],
|
||||
["Flat", "faded"],
|
||||
].map((variant) => (
|
||||
<Button
|
||||
key={variant[0]}
|
||||
@ -17,7 +17,7 @@ export default function App() {
|
||||
title: "Toast title",
|
||||
description: "Toast displayed successfully",
|
||||
// @ts-ignore
|
||||
variant: variant[0],
|
||||
variant: variant[0].toLowerCase(),
|
||||
color: "secondary",
|
||||
})
|
||||
}
|
||||
|
||||
@ -299,11 +299,11 @@ Toast has the following slots:
|
||||
attribute: "maxVisibleToasts",
|
||||
type: "number",
|
||||
description: "Maximum toasts which will be visible",
|
||||
default: "5"
|
||||
default: "3"
|
||||
},
|
||||
{
|
||||
attribute: "placement",
|
||||
type: "bottom-right" | "bottom-left" | "bottom-center" | "top-right" | "top-left" | "top-center",
|
||||
type: "bottom-right | bottom-left | bottom-center | top-right | top-left | top-center",
|
||||
description: "The placement of the toast.",
|
||||
default: "bottom-right"
|
||||
},
|
||||
|
||||
BIN
apps/docs/public/sponsors/000000.webp
Normal file
BIN
apps/docs/public/sponsors/000000.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
@ -6,7 +6,19 @@ import fs from "fs";
|
||||
*/
|
||||
export function getAllSponsors() {
|
||||
const sponsorsRcPath = path.resolve(".sponsorsrc");
|
||||
const sponsors = JSON.parse(fs.readFileSync(sponsorsRcPath, "utf-8"));
|
||||
const openCollectiveSponsors = JSON.parse(fs.readFileSync(sponsorsRcPath, "utf-8"));
|
||||
const patreonSponsors = [
|
||||
{
|
||||
MemberId: "000000",
|
||||
tier: "Gold Sponsor 🥇",
|
||||
currency: "USD",
|
||||
lastTransactionAt: "2025-02-15 00:00",
|
||||
lastTransactionAmount: 100,
|
||||
name: "Mochii.AI",
|
||||
image: "/sponsors/000000.webp",
|
||||
website: "https://www.mochii.ai",
|
||||
},
|
||||
];
|
||||
|
||||
return sponsors;
|
||||
return [...openCollectiveSponsors, ...patreonSponsors];
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user