Walk Create Community through the Figma screens and restore a chosen logo after reload, so a guest can leave without saving until they reach the email step.

This commit is contained in:
adilallo committed 2026-11-05 16:14:04 -07:00
1 parent ca1f58a50c
commit 2348a9e94f
61 files changed
+1110 -421

No files matched your search

@@ -18,12 +18,17 @@ const UploadContainer = memo<UploadProps>(
label,
showHelpIcon = true,
hintText,
buttonLabel,
previewSrc,
previewAlt,
fileName,
onClick,
className = "",
}) => {
const t = useTranslation("controlsChrome");
const resolvedState: UploadStateValue =
state ?? (active ? "default" : "disabled");
const uploadButtonLabel = buttonLabel ?? t("uploadButton");
return (
<UploadView
@@ -32,8 +37,11 @@ const UploadContainer = memo<UploadProps>(
label={label}
showHelpIcon={showHelpIcon}
hintText={hintText ?? t("uploadHintDefault")}
uploadButtonLabel={t("uploadButton")}
uploadAriaLabel={t("uploadAriaLabel")}
uploadButtonLabel={uploadButtonLabel}
uploadAriaLabel={uploadButtonLabel}
previewSrc={previewSrc}
previewAlt={previewAlt ?? t("uploadAriaLabel")}
fileName={fileName}
onClick={onClick}
className={className}
/>
@@ -32,6 +32,17 @@ export interface UploadProps {
* @default "Add image from your device"
*/
hintText?: string;
/**
* Label on the upload control. Defaults to the chrome “Upload” string.
* Pass “Replace” for the uploaded state.
*/
buttonLabel?: string;
/**
* Round preview of the selected file (Figma Has Preview).
*/
previewSrc?: string;
previewAlt?: string;
fileName?: string;
/**
* Callback when upload button is clicked
*/
@@ -50,6 +61,9 @@ export interface UploadViewProps {
hintText: string;
uploadButtonLabel: string;
uploadAriaLabel: string;
previewSrc?: string;
previewAlt: string;
fileName?: string;
onClick?: () => void;
className: string;
}
+62 -47
View File
@@ -12,13 +12,17 @@ function UploadView({
hintText,
uploadButtonLabel,
uploadAriaLabel,
previewSrc,
previewAlt,
fileName,
onClick,
className = "",
}: UploadViewProps) {
const isActive = state !== "disabled";
const isDisabled = state === "disabled";
const hasPreview =
typeof previewSrc === "string" && previewSrc.length > 0;
// Button styles based on active state
const buttonBgClass = isActive
? "bg-[var(--color-surface-invert-primary)]"
: "bg-[var(--color-surface-default-secondary)]";
@@ -27,12 +31,10 @@ function UploadView({
? "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)]";
@@ -41,7 +43,6 @@ function UploadView({
<div
className={`flex flex-col gap-[var(--space-300)] items-start relative w-full ${className}`}
>
{/* Label using InputLabel component */}
{hasLabel && label ? (
<InputLabel
label={label}
@@ -53,15 +54,27 @@ function UploadView({
/>
) : 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)]"
? "border-2 border-[var(--color-border-default-negative-primary)]"
: ""
} ${state === "focus" ? "shadow-[var(--shadow-focus-default)]" : ""}`}
>
{/* Upload button */}
{hasPreview ? (
<div
className="relative size-[80px] shrink-0 overflow-hidden rounded-full bg-[var(--color-surface-invert-brand-teal)]"
aria-hidden={false}
>
{/* eslint-disable-next-line @next/next/no-img-element -- user/device file or same-origin upload URL */}
<img
src={previewSrc}
alt={previewAlt}
className="h-full w-full object-cover opacity-70 mix-blend-color-burn"
/>
</div>
) : null}
<button
type="button"
onClick={onClick}
@@ -71,43 +84,43 @@ function UploadView({
} ${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 */}
{hasPreview ? null : (
<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>
)}
<div
className={`flex flex-col font-medium justify-center leading-[0] relative shrink-0 text-[length:var(--sizing-400)] whitespace-nowrap ${buttonTextColor}`}
>
@@ -115,11 +128,13 @@ function UploadView({
</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}`}
className={`flex flex-[1_0_0] flex-col font-normal min-h-[32px] justify-center leading-[0] min-w-px relative text-[length:var(--sizing-350)] ${descriptionTextColor}`}
role={state === "error" ? "alert" : undefined}
>
<p className="leading-[20px] whitespace-pre-wrap">{hintText}</p>
<p className="leading-[20px] whitespace-pre-wrap">
{hasPreview && fileName ? fileName : hintText}
</p>
</div>
</div>
</div>