Files
community-rule/app/components/controls/Upload/Upload.view.tsx
T
adilallo ca928e306b Match the 3 Nov color ramps and size-based strokes, and replace leftover palette hex with tokens.
Drop Cookies Settings from the footer, link the Home features that already have pages, and give leftover routes their own descriptions.
2026-11-05 15:37:55 -07:00

132 lines
4.3 KiB
TypeScript

"use client";
import { memo } from "react";
import InputLabel from "../../type/InputLabel";
import type { UploadViewProps } from "./Upload.types";
function UploadView({
state,
hasLabel,
label,
showHelpIcon = true,
hintText,
uploadButtonLabel,
uploadAriaLabel,
onClick,
className = "",
}: UploadViewProps) {
const isActive = state !== "disabled";
const isDisabled = state === "disabled";
// Button styles based on active state
const buttonBgClass = isActive
? "bg-[var(--color-surface-invert-primary)]"
: "bg-[var(--color-surface-default-secondary)]";
const buttonTextColor = isActive
? "text-[color:var(--color-content-invert-primary)]"
: "text-[color:var(--color-content-invert-tertiary)]";
// Description text color based on active state
const descriptionTextColor = isActive
? "text-[color:var(--color-content-default-primary)]"
: "text-[color:var(--color-content-default-tertiary)]";
// Icon color based on active state
const iconColor = isActive
? "text-[color:var(--color-content-invert-primary)]"
: "text-[color:var(--color-content-invert-tertiary)]";
return (
<div
className={`flex flex-col gap-[var(--space-300)] items-start relative w-full ${className}`}
>
{/* Label using InputLabel component */}
{hasLabel && label ? (
<InputLabel
label={label}
helpIcon={showHelpIcon}
asterisk={false}
helperText={false}
size="s"
palette="default"
/>
) : null}
{/* Upload container — max width per create-flow spec */}
<div
className={`bg-[var(--color-surface-default-secondary)] mx-auto flex w-full max-w-[474px] shrink-0 items-center justify-center gap-[24px] rounded-[var(--radius-200)] px-[var(--space-600)] py-[var(--space-1200)] ${
state === "error"
? "border border-[var(--color-border-default-utility-negative)]"
: ""
} ${state === "focus" ? "shadow-[var(--shadow-focus-default)]" : ""}`}
>
{/* Upload button */}
<button
type="button"
onClick={onClick}
disabled={isDisabled}
className={`${buttonBgClass} flex gap-[var(--space-150)] items-center justify-center overflow-clip px-[var(--space-400)] py-[var(--space-300)] rounded-[var(--radius-full)] shrink-0 hover:opacity-80 transition-opacity ${
state === "hover" ? "opacity-80" : ""
} ${state === "active" ? "scale-[0.98]" : ""}`}
aria-label={uploadAriaLabel}
>
{/* Upload icon */}
<div className={`relative shrink-0 size-[20px] ${iconColor}`}>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="size-full"
>
<path
d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<polyline
points="17 8 12 3 7 8"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<line
x1="12"
y1="3"
x2="12"
y2="15"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
{/* Button text */}
<div
className={`flex flex-col font-medium justify-center leading-[0] relative shrink-0 text-[length:var(--sizing-400)] whitespace-nowrap ${buttonTextColor}`}
>
<p className="leading-[20px]">{uploadButtonLabel}</p>
</div>
</button>
{/* Description text */}
<div
className={`flex flex-[1_0_0] flex-col font-normal h-[32px] justify-center leading-[0] min-h-px min-w-px relative text-[length:var(--sizing-350)] ${descriptionTextColor}`}
>
<p className="leading-[20px] whitespace-pre-wrap">{hintText}</p>
</div>
</div>
</div>
);
}
UploadView.displayName = "UploadView";
export default memo(UploadView);