Pin the review card description under the sections and tint the card from the uploaded logo.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
2653ae4602
commit
56adcd59fd
10 files changed
+508
-42
No files matched your search
@@ -49,6 +49,8 @@ const RuleContainer = memo<RuleProps>(
|
||||
recommended = false,
|
||||
templateGridFigmaShell = false,
|
||||
fluidWidth = false,
|
||||
descriptionAtBottom = false,
|
||||
surfaceColor,
|
||||
}) => {
|
||||
const size = sizeProp ?? "L";
|
||||
const t = useTranslation("ruleCard");
|
||||
@@ -112,6 +114,8 @@ const RuleContainer = memo<RuleProps>(
|
||||
recommended={recommended}
|
||||
templateGridFigmaShell={templateGridFigmaShell}
|
||||
fluidWidth={fluidWidth}
|
||||
descriptionAtBottom={descriptionAtBottom}
|
||||
surfaceColor={surfaceColor}
|
||||
cardAriaLabel={cardAriaLabel}
|
||||
recommendedLabel={recommendedLabel}
|
||||
/>
|
||||
|
||||
@@ -84,6 +84,16 @@ export interface RuleProps {
|
||||
templateGridFigmaShell?: boolean;
|
||||
/** When true, expanded cards fill their container instead of a fixed Figma width. */
|
||||
fluidWidth?: boolean;
|
||||
/**
|
||||
* Expanded cards: pin the description under the category rows (review preview).
|
||||
* Default keeps the description between the header and the categories.
|
||||
*/
|
||||
descriptionAtBottom?: boolean;
|
||||
/**
|
||||
* Runtime CSS color for the card fill. When set, it overrides
|
||||
* {@link backgroundColor}.
|
||||
*/
|
||||
surfaceColor?: string;
|
||||
}
|
||||
|
||||
export interface RuleViewProps {
|
||||
@@ -113,6 +123,8 @@ export interface RuleViewProps {
|
||||
recommended?: boolean;
|
||||
templateGridFigmaShell?: boolean;
|
||||
fluidWidth?: boolean;
|
||||
descriptionAtBottom?: boolean;
|
||||
surfaceColor?: string;
|
||||
/** Interactive card aria-label; supplied by the container from `ruleCard` messages. */
|
||||
cardAriaLabel: string;
|
||||
recommendedLabel: string;
|
||||
|
||||
@@ -35,6 +35,8 @@ export function RuleView({
|
||||
recommended = false,
|
||||
templateGridFigmaShell = false,
|
||||
fluidWidth = false,
|
||||
descriptionAtBottom = false,
|
||||
surfaceColor,
|
||||
cardAriaLabel,
|
||||
recommendedLabel,
|
||||
}: RuleViewProps) {
|
||||
@@ -267,8 +269,58 @@ export function RuleView({
|
||||
}
|
||||
|
||||
const cardClassName = `${backgroundColor} ${cardPadding} ${cardGap} ${borderRadiusClass} shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] ${interactiveCard ? "hover:shadow-[0px_0px_64px_0px_rgba(0,0,0,0.15)] transition-shadow duration-200" : ""} flex flex-col items-start justify-center relative ${cardWidth || "w-full"} ${href ? "no-underline text-inherit" : ""} ${className || ""}`;
|
||||
const surfaceStyle = surfaceColor
|
||||
? { backgroundColor: surfaceColor }
|
||||
: undefined;
|
||||
const isLinkCard = Boolean(href) && interactiveCard;
|
||||
|
||||
const hasCategories = Boolean(categories && categories.length > 0);
|
||||
const expandedDescriptionFrameClass = [
|
||||
"relative w-full shrink-0",
|
||||
hasCategories
|
||||
? descriptionAtBottom
|
||||
? "border-t border-solid border-[var(--color-content-invert-primary)] pt-[16px]"
|
||||
: "border-b border-solid border-[var(--color-content-invert-primary)] pb-[16px]"
|
||||
: "",
|
||||
isLarge || isMedium ? "px-0" : "px-[12px]",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
const showExpandedDescription = Boolean(
|
||||
description ||
|
||||
(onDescriptionClick && typeof descriptionEmptyHint === "string"),
|
||||
);
|
||||
const expandedDescription = showExpandedDescription ? (
|
||||
<div className={expandedDescriptionFrameClass}>
|
||||
{onDescriptionClick ? (
|
||||
<InlineTextButton
|
||||
type="button"
|
||||
underline={false}
|
||||
data-testid="rule-description-edit"
|
||||
ariaLabel={descriptionEditAriaLabel}
|
||||
className={`${descriptionClass} w-full min-w-0 cursor-pointer whitespace-pre-wrap text-left text-[var(--color-content-invert-primary)] hover:!opacity-100 ${
|
||||
!description && descriptionEmptyHint ? "opacity-70" : ""
|
||||
}`.trim()}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDescriptionClick();
|
||||
}}
|
||||
>
|
||||
{description ?? descriptionEmptyHint ?? ""}
|
||||
</InlineTextButton>
|
||||
) : (
|
||||
description && (
|
||||
<p
|
||||
className={`${descriptionClass} cursor-inherit text-[var(--color-content-invert-primary)]`}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
const cardBody = (
|
||||
<>
|
||||
{/* Figma: Header = `border-b` row, `gap-px`, icon `pl-1 pr-2 py-2` + `border-l` on title. */}
|
||||
@@ -382,43 +434,7 @@ export function RuleView({
|
||||
</div>
|
||||
) : expanded ? (
|
||||
<>
|
||||
{(description ||
|
||||
(onDescriptionClick &&
|
||||
typeof descriptionEmptyHint === "string")) && (
|
||||
<div
|
||||
className={`relative w-full shrink-0 ${
|
||||
categories && categories.length > 0
|
||||
? "border-b border-solid border-[var(--color-content-invert-primary)] pb-[16px]"
|
||||
: ""
|
||||
} ${expanded && (isLarge || isMedium) ? "px-0" : "px-[12px]"}`}
|
||||
>
|
||||
{onDescriptionClick ? (
|
||||
<InlineTextButton
|
||||
type="button"
|
||||
underline={false}
|
||||
data-testid="rule-description-edit"
|
||||
ariaLabel={descriptionEditAriaLabel}
|
||||
className={`${descriptionClass} w-full min-w-0 cursor-pointer whitespace-pre-wrap text-left text-[var(--color-content-invert-primary)] hover:!opacity-100 ${
|
||||
!description && descriptionEmptyHint ? "opacity-70" : ""
|
||||
}`.trim()}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDescriptionClick();
|
||||
}}
|
||||
>
|
||||
{description ?? descriptionEmptyHint ?? ""}
|
||||
</InlineTextButton>
|
||||
) : (
|
||||
description && (
|
||||
<p
|
||||
className={`${descriptionClass} cursor-inherit text-[var(--color-content-invert-primary)]`}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{descriptionAtBottom ? null : expandedDescription}
|
||||
{/* Categories Section - Using MultiSelect */}
|
||||
{categories && categories.length > 0 && (
|
||||
<div
|
||||
@@ -459,6 +475,7 @@ export function RuleView({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{descriptionAtBottom ? expandedDescription : null}
|
||||
</>
|
||||
) : (
|
||||
/* Collapsed State: Description */
|
||||
@@ -488,6 +505,7 @@ export function RuleView({
|
||||
<NextLink
|
||||
href={href}
|
||||
className={cardClassName}
|
||||
style={surfaceStyle}
|
||||
aria-label={ariaLabel}
|
||||
onClick={onClick}
|
||||
>
|
||||
@@ -499,6 +517,7 @@ export function RuleView({
|
||||
return (
|
||||
<div
|
||||
className={cardClassName}
|
||||
style={surfaceStyle}
|
||||
tabIndex={interactiveCard ? 0 : undefined}
|
||||
role={interactiveCard ? "button" : "article"}
|
||||
aria-label={ariaLabel}
|
||||
@@ -510,4 +529,3 @@ export function RuleView({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user