v0.10.5 首页 H2 产品线入口 ×6:ImageBoxWidget 重构为 Elementor 忠实 DOM + slim 白名单补齐 + H2 scoped CSS(post-18 对齐,桌面/移动/hover 实测一致)
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* # 组件 shadcn/ui NavigationMenu
|
||||
* 基于 @radix-ui/react-navigation-menu,用于顶部主导航(含巨幕面板)。
|
||||
* 样式对齐原站 Max Mega Menu(megamenu 内联 CSS 实测值):
|
||||
* - 顶级项:高 68px、16px/400/#222,hover/展开仅文字变橙(背景不变);
|
||||
* 指示器为实心三角 ▾(dashicons arrow-down 等价物),展开不旋转、颜色随文字。
|
||||
* - 巨幕/飞出面板:#fcfbfa 底 + 顶部 2px #f5b279 橙线 + 0 10px 30px 阴影,直角。
|
||||
* 切换动效保留 shadcn/ui(tw-animate-css 的 fade/zoom/slide + Radix motion 属性)。
|
||||
*/
|
||||
import * as React from "react";
|
||||
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
/** # 组件 导航菜单根容器 */
|
||||
function NavigationMenu({ className, children, viewportPosition = "inline", ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & { viewportPosition?: "inline" | "full" }) {
|
||||
return (
|
||||
<NavigationMenuPrimitive.Root data-viewport={viewportPosition} className={cn("relative z-[90] flex max-w-max items-center justify-center", className)} {...props}>
|
||||
{children}
|
||||
{viewportPosition === "full" ? <ViewportFullWidth /> : <ViewportCentered />}
|
||||
</NavigationMenuPrimitive.Root>
|
||||
);
|
||||
}
|
||||
|
||||
/** # 组件 导航菜单列表(顶级项容器)
|
||||
* p-0:本项目不引入 Tailwind preflight,需重置 UL 的浏览器默认左内边距。
|
||||
*/
|
||||
function NavigationMenuList({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
|
||||
return <NavigationMenuPrimitive.List className={cn("m-0 flex flex-1 list-none items-center justify-center gap-0.5 p-0", className)} {...props} />;
|
||||
}
|
||||
|
||||
/** # 组件 导航菜单项 */
|
||||
function NavigationMenuItem({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
|
||||
return <NavigationMenuPrimitive.Item className={cn("relative", className)} {...props} />;
|
||||
}
|
||||
|
||||
/** # 类型 NavigationMenuTrigger 属性 */
|
||||
const triggerStyle =
|
||||
"inline-flex h-[68px] w-max cursor-pointer items-center justify-center gap-[6px] rounded-none border-0 bg-transparent py-0 pr-[6px] pl-2 text-[16px] font-normal whitespace-nowrap text-[#222] transition-colors hover:text-brand focus-visible:outline-2 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-brand";
|
||||
|
||||
/** # 组件 导航菜单触发器(顶级可展开项)
|
||||
* chevron=false 时子元素原样透传(asChild 场景:Radix Slot 要求 children 是
|
||||
* 单个 React 元素,不能被 JSX 双槽包装成数组)。
|
||||
*/
|
||||
function NavigationMenuTrigger({ className, children, chevron = true, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger> & { chevron?: boolean }) {
|
||||
const content = chevron ? (
|
||||
<>
|
||||
{children}
|
||||
<CaretDown />
|
||||
</>
|
||||
) : (
|
||||
children
|
||||
);
|
||||
return (
|
||||
<NavigationMenuPrimitive.Trigger className={cn(triggerStyle, "group", className)} {...props}>
|
||||
{content}
|
||||
</NavigationMenuPrimitive.Trigger>
|
||||
);
|
||||
}
|
||||
|
||||
/** # 组件 导航菜单内容面板(下拉/巨幕内容)
|
||||
* data-[motion] 动画类依赖 tw-animate-css(app.css 已引入)。
|
||||
*/
|
||||
function NavigationMenuContent({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
|
||||
return <NavigationMenuPrimitive.Content className={cn("data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion=from-end]:fade-in data-[motion=from-start]:fade-in data-[motion=to-end]:fade-out data-[motion=to-start]:fade-out", className)} {...props} />;
|
||||
}
|
||||
|
||||
/** # 组件 导航菜单链接(无下级的普通链接项) */
|
||||
function NavigationMenuLink({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
|
||||
return <NavigationMenuPrimitive.Link className={cn(triggerStyle, className)} {...props} />;
|
||||
}
|
||||
|
||||
/** # 组件 巨幕面板标题(面板内小标题/副标题) */
|
||||
function NavigationMenuHeading({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return <div className={cn("text-[16px] leading-relaxed font-bold text-[#222]", className)} {...props} />;
|
||||
}
|
||||
|
||||
/** # 组件 实心下三角指示器(等价原站 dashicons arrow-down,展开不旋转,颜色随文字) */
|
||||
function CaretDown() {
|
||||
return (
|
||||
<svg width="10" height="10" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" className="shrink-0">
|
||||
<path d="M4.5 7h11L10 13.5 4.5 7Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
/** # 组件 居中式视口(小尺寸下拉用)
|
||||
* 面板 chrome 对齐原站 flyout:#fcfbfa 底 + 顶部 2px 橙线 + 直角 + 大阴影。
|
||||
*/
|
||||
function ViewportCentered() {
|
||||
return (
|
||||
<div className="absolute top-full left-0 flex w-max justify-center">
|
||||
<NavigationMenuPrimitive.Viewport className="relative mt-0 h-[var(--radix-navigation-menu-viewport-height)] w-[var(--radix-navigation-menu-viewport-width)] origin-top overflow-hidden rounded-none border-t-2 border-panel-line bg-panel shadow-[0_10px_30px_rgba(13,21,46,0.1)] transition-[width,height] duration-300 data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:zoom-in-95" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** # 组件 全宽视口(巨幕面板用:固定在导航条下方、水平居中)
|
||||
* 导航条(topbar 40px + 主导航 68px)sticky 置顶,故固定定位 top-108px 与其底边对齐;
|
||||
* 面板宽度按原站实测 1340px(1436 视口),窄视口收窄到留 16px 边距。
|
||||
*/
|
||||
function ViewportFullWidth() {
|
||||
return (
|
||||
<div className="fixed inset-x-0 top-[108px] z-[90] flex justify-center">
|
||||
<NavigationMenuPrimitive.Viewport className="relative h-[var(--radix-navigation-menu-viewport-height)] w-[calc(100%-32px)] max-w-[1340px] origin-top overflow-visible rounded-none border-t-2 border-panel-line bg-panel shadow-[0_10px_30px_rgba(13,21,46,0.1)] transition-[height] duration-300 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:pointer-events-none data-[state=closed]:slide-out-to-top-2 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:slide-in-from-top-2" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuHeading, CaretDown };
|
||||
Reference in New Issue
Block a user