feat(website): rework the product-stepper Layout visual (#22249)
## What Reworks the **"Layout" step** visual of the product-page stepper (the floating record-layout-editor scene) to match the Figma references and read as a premium, layered composition. Data is unchanged — this is purely the look. ## Figma alignment - **Fields editor** — the inline-edit field row now keeps the field icon + a bordered input + blue **Done** + the eye / ⋮ (instead of a floating box); **"New fields"** renders as a uniform field row; section headers get an overflow menu; field types read `Boolean` / `Date & Time`. Dropped the redundant "Fields widget" header label. - **"General" widget** — header chevron, the real `anonymousFelix` avatar on Account Owner (reusing the shared asset the other product-feature visuals use), a **Revenue** row, and a money-bag icon for the currency field. ## Premium composition - The nav, record, and Fields editor read as one elevated **z-stack** (back → front): the nav is pushed right so its edge tucks under the record (lowest z-index), the record sits above it, and the editor stays in front — each casting a progressively stronger shadow so the depth ordering is unmistakable. - The **"New record / Enrich / Edit actions"** bar is centered over the nav–record seam (`translateX(-50%)`) to tie the layered stack together at the top. ## Testing - typecheck · oxfmt · oxlint · check-conventions — green. - Verified visually with headless Playwright on `/product` (Layout step). <img width="697" height="734" alt="image" src="https://github.com/user-attachments/assets/58ae7ffb-13d1-4310-bbdc-864589f8bc43" />
This commit is contained in:
+90
-56
@@ -8,6 +8,7 @@ import {
|
||||
type PointerEvent as ReactPointerEvent,
|
||||
} from 'react';
|
||||
|
||||
import { sharedAssetUrls } from '@/app-preview/data/shared-asset-urls';
|
||||
import { getElementScale } from '@/platform/motion';
|
||||
import { PRODUCT_STEPPER_SCENE } from '@/tokens/feature-scenes/product-stepper-scene';
|
||||
|
||||
@@ -17,6 +18,7 @@ import { LAYOUT_CHROME } from './components/layout-chrome';
|
||||
import { LAYOUT_EDITOR_CONTENT } from './data/layout-data';
|
||||
|
||||
const {
|
||||
ChevronDown: ChevronDownGlyph,
|
||||
ChevronLeft: ChevronLeftGlyph,
|
||||
Dots: DotsGlyph,
|
||||
Eye: EyeGlyph,
|
||||
@@ -24,8 +26,8 @@ const {
|
||||
Grip: GripGlyph,
|
||||
List: ListGlyph,
|
||||
Nav: NavGlyph,
|
||||
NewFields: NewFieldsGlyph,
|
||||
NewSection: NewSectionGlyph,
|
||||
Plus: PlusGlyph,
|
||||
Spark: SparkGlyph,
|
||||
} = LAYOUT_GLYPHS;
|
||||
|
||||
@@ -36,8 +38,8 @@ const {
|
||||
AddSectionRow,
|
||||
AddText,
|
||||
DoneButton,
|
||||
EditableRow,
|
||||
EditableText,
|
||||
EditField,
|
||||
EditGroup,
|
||||
FieldDot,
|
||||
FieldIconBox,
|
||||
FieldLabels,
|
||||
@@ -51,10 +53,6 @@ const {
|
||||
NavPanel,
|
||||
NavSectionLabel,
|
||||
NavSubItem,
|
||||
NewFieldsColumn,
|
||||
NewFieldsDescription,
|
||||
NewFieldsRow,
|
||||
NewFieldsTitle,
|
||||
PanelActionButton,
|
||||
PanelBackButton,
|
||||
PanelFields,
|
||||
@@ -64,10 +62,10 @@ const {
|
||||
PanelSubLabel,
|
||||
PanelTitleBold,
|
||||
PanelTitleGroup,
|
||||
PanelTitleSub,
|
||||
RightPanel,
|
||||
SectionName,
|
||||
SectionRow,
|
||||
WidgetAvatar,
|
||||
WidgetChip,
|
||||
WidgetIcon,
|
||||
WidgetInner,
|
||||
@@ -158,7 +156,10 @@ export function LayoutVisual({ active }: { active: boolean }) {
|
||||
>
|
||||
<WidgetPanel>
|
||||
<WidgetInner>
|
||||
<WidgetSectionLabel>{i18n._(msg`General`)}</WidgetSectionLabel>
|
||||
<WidgetSectionLabel>
|
||||
{i18n._(msg`General`)}
|
||||
<ChevronDownGlyph />
|
||||
</WidgetSectionLabel>
|
||||
<WidgetRow>
|
||||
<WidgetIcon>
|
||||
<FieldGlyph type="link" />
|
||||
@@ -171,7 +172,14 @@ export function LayoutVisual({ active }: { active: boolean }) {
|
||||
<FieldGlyph type="user" />
|
||||
</WidgetIcon>
|
||||
<WidgetLabel>{i18n._(msg`Account Owner`)}</WidgetLabel>
|
||||
<WidgetValue>Félix Malfait</WidgetValue>
|
||||
<WidgetValue>
|
||||
<WidgetAvatar
|
||||
alt=""
|
||||
fetchPriority="low"
|
||||
src={sharedAssetUrls.peopleAvatars.anonymousFelix}
|
||||
/>
|
||||
Félix Malfait
|
||||
</WidgetValue>
|
||||
</WidgetRow>
|
||||
<WidgetRow>
|
||||
<WidgetIcon>
|
||||
@@ -187,6 +195,13 @@ export function LayoutVisual({ active }: { active: boolean }) {
|
||||
<WidgetLabel>{i18n._(msg`ICP`)}</WidgetLabel>
|
||||
<WidgetValue>✓ True</WidgetValue>
|
||||
</WidgetRow>
|
||||
<WidgetRow>
|
||||
<WidgetIcon>
|
||||
<FieldGlyph type="money" />
|
||||
</WidgetIcon>
|
||||
<WidgetLabel>{i18n._(msg`Revenue`)}</WidgetLabel>
|
||||
<WidgetValue>$500,000</WidgetValue>
|
||||
</WidgetRow>
|
||||
</WidgetInner>
|
||||
</WidgetPanel>
|
||||
|
||||
@@ -253,7 +268,6 @@ export function LayoutVisual({ active }: { active: boolean }) {
|
||||
</PanelIconBox>
|
||||
<PanelTitleGroup>
|
||||
<PanelTitleBold>{i18n._(msg`Fields`)}</PanelTitleBold>
|
||||
<PanelTitleSub>{i18n._(msg`Fields widget`)}</PanelTitleSub>
|
||||
</PanelTitleGroup>
|
||||
<PanelActionButton>
|
||||
<SparkGlyph />
|
||||
@@ -275,46 +289,59 @@ export function LayoutVisual({ active }: { active: boolean }) {
|
||||
<SectionName>
|
||||
{i18n._(LAYOUT_EDITOR_CONTENT.sectionLabels[section])}
|
||||
</SectionName>
|
||||
<PanelActionButton>
|
||||
<DotsGlyph />
|
||||
</PanelActionButton>
|
||||
</SectionRow>
|
||||
|
||||
{sectionNumber === 0 ? (
|
||||
<EditableRow>
|
||||
<EditableText>{i18n._(msg`Industry`)}</EditableText>
|
||||
<DoneButton>{i18n._(msg`Done`)}</DoneButton>
|
||||
</EditableRow>
|
||||
) : null}
|
||||
|
||||
{fields
|
||||
.filter((field) => field.section === section)
|
||||
.map((field) => (
|
||||
<FieldRow
|
||||
data-dragging={draggingId === field.id ? '' : undefined}
|
||||
key={field.id}
|
||||
onPointerDown={(event) =>
|
||||
handleDragStart(field.id, event)
|
||||
}
|
||||
>
|
||||
<FieldIconBox>
|
||||
<FieldGlyph type={field.icon} />
|
||||
</FieldIconBox>
|
||||
<FieldLabels>
|
||||
<FieldName>{i18n._(field.label)}</FieldName>
|
||||
<FieldDot>·</FieldDot>
|
||||
<FieldType>{i18n._(field.type)}</FieldType>
|
||||
</FieldLabels>
|
||||
<PanelActionButton
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
toggleVisibility(field.id);
|
||||
}}
|
||||
.map((field, fieldNumber) => {
|
||||
const isEditing =
|
||||
sectionNumber === 0 && fieldNumber === 0;
|
||||
|
||||
return (
|
||||
<FieldRow
|
||||
data-dragging={
|
||||
draggingId === field.id ? '' : undefined
|
||||
}
|
||||
data-editing={isEditing ? '' : undefined}
|
||||
key={field.id}
|
||||
onPointerDown={
|
||||
isEditing
|
||||
? undefined
|
||||
: (event) => handleDragStart(field.id, event)
|
||||
}
|
||||
>
|
||||
<EyeGlyph visible={field.visible} />
|
||||
</PanelActionButton>
|
||||
<PanelActionButton>
|
||||
<DotsGlyph />
|
||||
</PanelActionButton>
|
||||
</FieldRow>
|
||||
))}
|
||||
<FieldIconBox>
|
||||
<FieldGlyph type={field.icon} />
|
||||
</FieldIconBox>
|
||||
{isEditing ? (
|
||||
<EditGroup>
|
||||
<EditField>{i18n._(msg`General`)}</EditField>
|
||||
<DoneButton>{i18n._(msg`Done`)}</DoneButton>
|
||||
</EditGroup>
|
||||
) : (
|
||||
<FieldLabels>
|
||||
<FieldName>{i18n._(field.label)}</FieldName>
|
||||
<FieldDot>·</FieldDot>
|
||||
<FieldType>{i18n._(field.type)}</FieldType>
|
||||
</FieldLabels>
|
||||
)}
|
||||
<PanelActionButton
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
toggleVisibility(field.id);
|
||||
}}
|
||||
>
|
||||
<EyeGlyph visible={field.visible} />
|
||||
</PanelActionButton>
|
||||
<PanelActionButton>
|
||||
<DotsGlyph />
|
||||
</PanelActionButton>
|
||||
</FieldRow>
|
||||
);
|
||||
})}
|
||||
|
||||
{sectionNumber > 0 && sectionNumber < sections.length - 1 ? (
|
||||
<AddSectionRow>
|
||||
@@ -327,17 +354,24 @@ export function LayoutVisual({ active }: { active: boolean }) {
|
||||
</div>
|
||||
))}
|
||||
|
||||
<NewFieldsRow>
|
||||
<AddIconBox>
|
||||
<PlusGlyph />
|
||||
</AddIconBox>
|
||||
<NewFieldsColumn>
|
||||
<NewFieldsTitle>{i18n._(msg`New fields`)}</NewFieldsTitle>
|
||||
<NewFieldsDescription>
|
||||
<FieldRow data-static="">
|
||||
<FieldIconBox>
|
||||
<NewFieldsGlyph />
|
||||
</FieldIconBox>
|
||||
<FieldLabels>
|
||||
<FieldName>{i18n._(msg`New fields`)}</FieldName>
|
||||
<FieldDot>·</FieldDot>
|
||||
<FieldType>
|
||||
{i18n._(msg`Default position/visibility for field…`)}
|
||||
</NewFieldsDescription>
|
||||
</NewFieldsColumn>
|
||||
</NewFieldsRow>
|
||||
</FieldType>
|
||||
</FieldLabels>
|
||||
<PanelActionButton>
|
||||
<EyeGlyph visible />
|
||||
</PanelActionButton>
|
||||
<PanelActionButton>
|
||||
<DotsGlyph />
|
||||
</PanelActionButton>
|
||||
</FieldRow>
|
||||
|
||||
<AddSectionRow>
|
||||
<AddIconBox>
|
||||
|
||||
+14
-7
@@ -2,8 +2,8 @@ import {
|
||||
IconBuildingSkyscraper,
|
||||
IconCalendar,
|
||||
IconCheckbox,
|
||||
IconChevronDown,
|
||||
IconChevronLeft,
|
||||
IconCurrencyDollar,
|
||||
IconDotsVertical,
|
||||
IconEye,
|
||||
IconEyeOff,
|
||||
@@ -13,8 +13,10 @@ import {
|
||||
IconLink,
|
||||
IconList,
|
||||
IconMapPin,
|
||||
IconMoneybag,
|
||||
IconNewSection,
|
||||
IconNotes,
|
||||
IconPlus,
|
||||
IconRowInsertBottom,
|
||||
IconSettingsAutomation,
|
||||
IconSparkles,
|
||||
IconTargetArrow,
|
||||
@@ -35,7 +37,7 @@ const FIELD_ICONS: Record<LayoutFieldIconType, typeof IconLink> = {
|
||||
calendar: IconCalendar,
|
||||
link: IconLink,
|
||||
map: IconMapPin,
|
||||
money: IconCurrencyDollar,
|
||||
money: IconMoneybag,
|
||||
target: IconTargetArrow,
|
||||
user: IconUserCircle,
|
||||
users: IconUsers,
|
||||
@@ -71,6 +73,10 @@ function EyeGlyph({ visible }: { visible: boolean }) {
|
||||
);
|
||||
}
|
||||
|
||||
function ChevronDownGlyph() {
|
||||
return <IconChevronDown color={inks.eyeInk} size={10} stroke={1.6} />;
|
||||
}
|
||||
|
||||
function ChevronLeftGlyph() {
|
||||
return <IconChevronLeft color={inks.eyeInk} size={12} stroke={1.6} />;
|
||||
}
|
||||
@@ -92,14 +98,15 @@ function SparkGlyph() {
|
||||
}
|
||||
|
||||
function NewSectionGlyph() {
|
||||
return <IconPlus color={inks.fieldInk} size={11} stroke={1.6} />;
|
||||
return <IconNewSection color={inks.fieldInk} size={11} stroke={1.6} />;
|
||||
}
|
||||
|
||||
function PlusGlyph() {
|
||||
return <IconPlus color={inks.fieldInk} size={11} stroke={1.6} />;
|
||||
function NewFieldsGlyph() {
|
||||
return <IconRowInsertBottom color={inks.fieldInk} size={11} stroke={1.6} />;
|
||||
}
|
||||
|
||||
export const LAYOUT_GLYPHS = {
|
||||
ChevronDown: ChevronDownGlyph,
|
||||
ChevronLeft: ChevronLeftGlyph,
|
||||
Dots: DotsGlyph,
|
||||
Eye: EyeGlyph,
|
||||
@@ -107,7 +114,7 @@ export const LAYOUT_GLYPHS = {
|
||||
Grip: GripGlyph,
|
||||
List: ListGlyph,
|
||||
Nav: NavGlyph,
|
||||
NewFields: NewFieldsGlyph,
|
||||
NewSection: NewSectionGlyph,
|
||||
Plus: PlusGlyph,
|
||||
Spark: SparkGlyph,
|
||||
};
|
||||
|
||||
+51
-53
@@ -7,18 +7,26 @@ const layout = PRODUCT_STEPPER_SCENE.layout;
|
||||
|
||||
const PANEL_RADIUS = '3px';
|
||||
|
||||
const PANEL_SHADOW = layout.panelShadow;
|
||||
|
||||
const PANEL_SHADOW_MEDIUM = layout.panelShadowMedium;
|
||||
|
||||
const PANEL_SHADOW_ELEVATED = layout.panelShadowElevated;
|
||||
|
||||
const WidgetPanel = styled.div`
|
||||
backdrop-filter: blur(5px);
|
||||
background: ${shell.cardBackground};
|
||||
border: 0.8px solid ${layout.accent};
|
||||
border-radius: ${PANEL_RADIUS};
|
||||
left: 48%;
|
||||
box-shadow: ${PANEL_SHADOW_MEDIUM};
|
||||
left: 42%;
|
||||
max-height: 36%;
|
||||
overflow: hidden;
|
||||
padding: 6px;
|
||||
position: absolute;
|
||||
top: 13%;
|
||||
width: 38%;
|
||||
z-index: 2;
|
||||
`;
|
||||
|
||||
const WidgetInner = styled.div`
|
||||
@@ -28,9 +36,12 @@ const WidgetInner = styled.div`
|
||||
`;
|
||||
|
||||
const WidgetSectionLabel = styled.div`
|
||||
align-items: center;
|
||||
color: ${shell.textTertiary};
|
||||
display: flex;
|
||||
font-size: 7px;
|
||||
font-weight: 600;
|
||||
justify-content: space-between;
|
||||
padding: 0 3px;
|
||||
`;
|
||||
|
||||
@@ -72,6 +83,15 @@ const WidgetValue = styled.span`
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
const WidgetAvatar = styled.img`
|
||||
border-radius: 50%;
|
||||
height: 12px;
|
||||
margin-right: 4px;
|
||||
object-fit: cover;
|
||||
vertical-align: middle;
|
||||
width: 12px;
|
||||
`;
|
||||
|
||||
const WidgetChip = styled.span`
|
||||
background: ${layout.chipWash};
|
||||
border: 0.5px solid ${shell.borderStrong};
|
||||
@@ -86,13 +106,15 @@ const NavPanel = styled.div`
|
||||
background: ${shell.cardBackground};
|
||||
border: 0.8px solid ${layout.accent};
|
||||
border-radius: ${PANEL_RADIUS};
|
||||
left: 8%;
|
||||
box-shadow: ${PANEL_SHADOW};
|
||||
left: 14%;
|
||||
max-height: 68%;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
top: 13%;
|
||||
width: 30%;
|
||||
z-index: 1;
|
||||
`;
|
||||
|
||||
const NavSectionLabel = styled.div`
|
||||
@@ -163,12 +185,14 @@ const ActionsBar = styled.div`
|
||||
background: ${shell.cardBackground};
|
||||
border: 0.8px solid ${layout.accent};
|
||||
border-radius: ${PANEL_RADIUS};
|
||||
box-shadow: ${PANEL_SHADOW};
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
left: 46%;
|
||||
left: 44%;
|
||||
padding: 5px 6px;
|
||||
position: absolute;
|
||||
top: 6%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 3;
|
||||
`;
|
||||
|
||||
@@ -187,12 +211,13 @@ const RightPanel = styled.div`
|
||||
border: 0.8px solid ${layout.panelAccent};
|
||||
border-radius: ${PANEL_RADIUS};
|
||||
bottom: 3%;
|
||||
box-shadow: ${PANEL_SHADOW_ELEVATED};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
left: 42%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 36%;
|
||||
top: 38%;
|
||||
width: 54%;
|
||||
z-index: 4;
|
||||
`;
|
||||
@@ -240,14 +265,6 @@ const PanelTitleBold = styled.span`
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
const PanelTitleSub = styled.span`
|
||||
color: ${shell.textTertiary};
|
||||
font-size: 8px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
const PanelSubBar = styled.div`
|
||||
align-items: center;
|
||||
border-bottom: 0.8px solid ${shell.borderLight};
|
||||
@@ -285,21 +302,25 @@ const SectionName = styled.span`
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
const EditableRow = styled.div`
|
||||
const EditGroup = styled.span`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-right: auto;
|
||||
min-width: 0;
|
||||
`;
|
||||
|
||||
const EditField = styled.span`
|
||||
background: white;
|
||||
border: 1px solid ${layout.accent};
|
||||
border-radius: ${PANEL_RADIUS};
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin: 2px 0 4px;
|
||||
padding: 4px 6px;
|
||||
`;
|
||||
|
||||
const EditableText = styled.span`
|
||||
color: ${shell.text};
|
||||
flex: 1;
|
||||
font-size: 9px;
|
||||
font-size: 8px;
|
||||
overflow: hidden;
|
||||
padding: 3px 6px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 120px;
|
||||
`;
|
||||
|
||||
const DoneButton = styled.span`
|
||||
@@ -329,6 +350,11 @@ const FieldRow = styled.div`
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
&[data-editing],
|
||||
&[data-static] {
|
||||
cursor: default;
|
||||
}
|
||||
`;
|
||||
|
||||
const FieldIconBox = styled.span`
|
||||
@@ -396,30 +422,6 @@ const AddText = styled.span`
|
||||
font-size: 8px;
|
||||
`;
|
||||
|
||||
const NewFieldsRow = styled.div`
|
||||
align-items: center;
|
||||
border-top: 0.8px solid ${shell.borderMedium};
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
margin-top: 4px;
|
||||
padding: 6px 3px 3px;
|
||||
`;
|
||||
|
||||
const NewFieldsColumn = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const NewFieldsTitle = styled.span`
|
||||
color: ${shell.textSecondary};
|
||||
font-size: 8px;
|
||||
`;
|
||||
|
||||
const NewFieldsDescription = styled.span`
|
||||
color: ${shell.textTertiary};
|
||||
font-size: 7px;
|
||||
`;
|
||||
|
||||
export const LAYOUT_CHROME = {
|
||||
ActionButton,
|
||||
ActionsBar,
|
||||
@@ -427,8 +429,8 @@ export const LAYOUT_CHROME = {
|
||||
AddSectionRow,
|
||||
AddText,
|
||||
DoneButton,
|
||||
EditableRow,
|
||||
EditableText,
|
||||
EditField,
|
||||
EditGroup,
|
||||
FieldDot,
|
||||
FieldIconBox,
|
||||
FieldLabels,
|
||||
@@ -442,10 +444,6 @@ export const LAYOUT_CHROME = {
|
||||
NavPanel,
|
||||
NavSectionLabel,
|
||||
NavSubItem,
|
||||
NewFieldsColumn,
|
||||
NewFieldsDescription,
|
||||
NewFieldsRow,
|
||||
NewFieldsTitle,
|
||||
PanelActionButton,
|
||||
PanelBackButton,
|
||||
PanelFields,
|
||||
@@ -455,10 +453,10 @@ export const LAYOUT_CHROME = {
|
||||
PanelSubLabel,
|
||||
PanelTitleBold,
|
||||
PanelTitleGroup,
|
||||
PanelTitleSub,
|
||||
RightPanel,
|
||||
SectionName,
|
||||
SectionRow,
|
||||
WidgetAvatar,
|
||||
WidgetChip,
|
||||
WidgetIcon,
|
||||
WidgetInner,
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ export const LAYOUT_EDITOR_CONTENT: {
|
||||
id: 'icp',
|
||||
icon: 'target',
|
||||
label: msg`ICP`,
|
||||
type: msg`True/False`,
|
||||
type: msg`Boolean`,
|
||||
section: 'Additional',
|
||||
visible: false,
|
||||
},
|
||||
@@ -62,7 +62,7 @@ export const LAYOUT_EDITOR_CONTENT: {
|
||||
id: 'creation-date',
|
||||
icon: 'calendar',
|
||||
label: msg`Creation date`,
|
||||
type: msg`Date and Time`,
|
||||
type: msg`Date & Time`,
|
||||
section: 'Other',
|
||||
visible: true,
|
||||
},
|
||||
|
||||
@@ -63,6 +63,10 @@ export const PRODUCT_STEPPER_SCENE = {
|
||||
fieldInk: FICTION_PALETTE.inkMuted,
|
||||
eyeInk: FICTION_PALETTE.inkFaint,
|
||||
eyeHiddenInk: FICTION_PALETTE.inkDisabled,
|
||||
panelShadow: '0 4px 16px rgba(0, 0, 0, 0.32)',
|
||||
panelShadowMedium: '0 8px 28px rgba(0, 0, 0, 0.42)',
|
||||
panelShadowElevated:
|
||||
'0 12px 44px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3)',
|
||||
},
|
||||
cardShadow: '0 0 2px rgba(0, 0, 0, 0.08), 0 2px 2px rgba(0, 0, 0, 0.04)',
|
||||
nodeShadow: '0 0 2px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04)',
|
||||
|
||||
Reference in New Issue
Block a user