Skip to content

Commit c7db48e

Browse files
authored
fix(landing): ui (#2979)
1 parent 4d84465 commit c7db48e

File tree

10 files changed

+130
-116
lines changed

10 files changed

+130
-116
lines changed

apps/sim/app/(landing)/components/hero/components/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export { LandingLoopNode } from './landing-canvas/landing-block/landing-loop-nod
1010
export { LandingNode } from './landing-canvas/landing-block/landing-node'
1111
export type { LoopBlockProps } from './landing-canvas/landing-block/loop-block'
1212
export { LoopBlock } from './landing-canvas/landing-block/loop-block'
13-
export type { TagProps } from './landing-canvas/landing-block/tag'
14-
export { Tag } from './landing-canvas/landing-block/tag'
13+
export type { SubBlockRowProps, TagProps } from './landing-canvas/landing-block/tag'
14+
export { SubBlockRow, Tag } from './landing-canvas/landing-block/tag'
1515
export type {
1616
LandingBlockNode,
1717
LandingCanvasProps,
Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import React from 'react'
2-
import { BookIcon } from 'lucide-react'
32
import {
4-
Tag,
5-
type TagProps,
3+
SubBlockRow,
4+
type SubBlockRowProps,
65
} from '@/app/(landing)/components/hero/components/landing-canvas/landing-block/tag'
76

87
/**
98
* Data structure for a landing card component
9+
* Matches the workflow block structure from the application
1010
*/
1111
export interface LandingCardData {
1212
/** Icon element to display in the card header */
@@ -15,8 +15,8 @@ export interface LandingCardData {
1515
color: string | '#f6f6f6'
1616
/** Name/title of the card */
1717
name: string
18-
/** Optional tags to display at the bottom of the card */
19-
tags?: TagProps[]
18+
/** Optional subblock rows to display below the header */
19+
tags?: SubBlockRowProps[]
2020
}
2121

2222
/**
@@ -28,7 +28,8 @@ export interface LandingBlockProps extends LandingCardData {
2828
}
2929

3030
/**
31-
* Landing block component that displays a card with icon, name, and optional tags
31+
* Landing block component that displays a card with icon, name, and optional subblock rows
32+
* Styled to match the application's workflow blocks
3233
* @param props - Component properties including icon, color, name, tags, and className
3334
* @returns A styled block card component
3435
*/
@@ -39,33 +40,37 @@ export const LandingBlock = React.memo(function LandingBlock({
3940
tags,
4041
className,
4142
}: LandingBlockProps) {
43+
const hasContentBelowHeader = tags && tags.length > 0
44+
4245
return (
4346
<div
44-
className={`z-10 flex w-64 flex-col items-start gap-3 rounded-[14px] border border-[#E5E5E5] bg-[#FEFEFE] p-3 ${className ?? ''}`}
45-
style={{
46-
boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
47-
}}
47+
className={`z-10 flex w-[250px] flex-col rounded-[8px] border border-[#E5E5E5] bg-white ${className ?? ''}`}
4848
>
49-
<div className='flex w-full items-center justify-between'>
50-
<div className='flex items-center gap-2.5'>
49+
{/* Header - matches workflow-block.tsx header styling */}
50+
<div
51+
className={`flex items-center justify-between p-[8px] ${hasContentBelowHeader ? 'border-[#E5E5E5] border-b' : ''}`}
52+
>
53+
<div className='flex min-w-0 flex-1 items-center gap-[10px]'>
5154
<div
52-
className='flex h-6 w-6 items-center justify-center rounded-[8px] text-white'
53-
style={{ backgroundColor: color as string }}
55+
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
56+
style={{ background: color as string }}
5457
>
5558
{icon}
5659
</div>
57-
<p className='text-base text-card-foreground'>{name}</p>
60+
<span className='truncate font-medium text-[#171717] text-[16px]' title={name}>
61+
{name}
62+
</span>
5863
</div>
59-
<BookIcon className='h-4 w-4 text-muted-foreground' />
6064
</div>
6165

62-
{tags && tags.length > 0 ? (
63-
<div className='flex flex-wrap gap-2'>
66+
{/* Content - SubBlock Rows matching workflow-block.tsx */}
67+
{hasContentBelowHeader && (
68+
<div className='flex flex-col gap-[8px] p-[8px]'>
6469
{tags.map((tag) => (
65-
<Tag key={tag.label} icon={tag.icon} label={tag.label} />
70+
<SubBlockRow key={tag.label} icon={tag.icon} label={tag.label} />
6671
))}
6772
</div>
68-
) : null}
73+
)}
6974
</div>
7075
)
7176
})

apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ import {
77
type LandingCardData,
88
} from '@/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-block'
99

10+
/**
11+
* Handle Y offset from block top - matches HANDLE_POSITIONS.DEFAULT_Y_OFFSET
12+
*/
13+
const HANDLE_Y_OFFSET = 20
14+
1015
/**
1116
* React Flow node component for the landing canvas
12-
* Includes CSS animations and connection handles
17+
* Styled to match the application's workflow blocks
1318
* @param props - Component properties containing node data
1419
* @returns A React Flow compatible node component
1520
*/
@@ -41,15 +46,15 @@ export const LandingNode = React.memo(function LandingNode({ data }: { data: Lan
4146
type='target'
4247
position={Position.Left}
4348
style={{
44-
width: '12px',
45-
height: '12px',
46-
background: '#FEFEFE',
47-
border: '1px solid #E5E5E5',
48-
borderRadius: '50%',
49-
top: '50%',
50-
left: '-20px',
49+
width: '7px',
50+
height: '20px',
51+
background: '#D1D1D1',
52+
border: 'none',
53+
borderRadius: '2px 0 0 2px',
54+
top: `${HANDLE_Y_OFFSET}px`,
55+
left: '-7px',
5156
transform: 'translateY(-50%)',
52-
zIndex: 2,
57+
zIndex: 10,
5358
}}
5459
isConnectable={false}
5560
/>
@@ -59,15 +64,15 @@ export const LandingNode = React.memo(function LandingNode({ data }: { data: Lan
5964
type='source'
6065
position={Position.Right}
6166
style={{
62-
width: '12px',
63-
height: '12px',
64-
background: '#FEFEFE',
65-
border: '1px solid #E5E5E5',
66-
borderRadius: '50%',
67-
top: '50%',
68-
right: '-20px',
67+
width: '7px',
68+
height: '20px',
69+
background: '#D1D1D1',
70+
border: 'none',
71+
borderRadius: '0 2px 2px 0',
72+
top: `${HANDLE_Y_OFFSET}px`,
73+
right: '-7px',
6974
transform: 'translateY(-50%)',
70-
zIndex: 2,
75+
zIndex: 10,
7176
}}
7277
isConnectable={false}
7378
/>

apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/loop-block.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface LoopBlockProps {
1515
/**
1616
* Loop block container component that provides a styled container
1717
* for grouping related elements with a dashed border
18+
* Styled to match the application's subflow containers
1819
* @param props - Component properties including children and styling
1920
* @returns A styled loop container component
2021
*/
@@ -29,33 +30,33 @@ export const LoopBlock = React.memo(function LoopBlock({
2930
style={{
3031
width: '1198px',
3132
height: '528px',
32-
borderRadius: '14px',
33-
background: 'rgba(59, 130, 246, 0.10)',
33+
borderRadius: '8px',
34+
background: 'rgba(59, 130, 246, 0.08)',
3435
position: 'relative',
3536
...style,
3637
}}
3738
>
38-
{/* Custom dashed border with SVG */}
39+
{/* Custom dashed border with SVG - 8px border radius to match blocks */}
3940
<svg
4041
className='pointer-events-none absolute inset-0 h-full w-full'
41-
style={{ borderRadius: '14px' }}
42+
style={{ borderRadius: '8px' }}
4243
preserveAspectRatio='none'
4344
>
4445
<path
4546
className='landing-loop-animated-dash'
46-
d='M 1183.5 527.5
47-
L 14 527.5
48-
A 13.5 13.5 0 0 1 0.5 514
49-
L 0.5 14
50-
A 13.5 13.5 0 0 1 14 0.5
51-
L 1183.5 0.5
52-
A 13.5 13.5 0 0 1 1197 14
53-
L 1197 514
54-
A 13.5 13.5 0 0 1 1183.5 527.5 Z'
47+
d='M 1190 527.5
48+
L 8 527.5
49+
A 7.5 7.5 0 0 1 0.5 520
50+
L 0.5 8
51+
A 7.5 7.5 0 0 1 8 0.5
52+
L 1190 0.5
53+
A 7.5 7.5 0 0 1 1197.5 8
54+
L 1197.5 520
55+
A 7.5 7.5 0 0 1 1190 527.5 Z'
5556
fill='none'
5657
stroke='#3B82F6'
5758
strokeWidth='1'
58-
strokeDasharray='12 12'
59+
strokeDasharray='8 8'
5960
strokeLinecap='round'
6061
/>
6162
</svg>
Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,52 @@
11
import React from 'react'
22

33
/**
4-
* Properties for a tag component
4+
* Properties for a subblock row component
5+
* Matches the SubBlockRow pattern from workflow-block.tsx
56
*/
6-
export interface TagProps {
7-
/** Icon element to display in the tag */
8-
icon: React.ReactNode
9-
/** Text label for the tag */
7+
export interface SubBlockRowProps {
8+
/** Icon element to display (optional, for visual context) */
9+
icon?: React.ReactNode
10+
/** Text label for the row title */
1011
label: string
12+
/** Optional value to display on the right side */
13+
value?: string
1114
}
1215

1316
/**
14-
* Tag component for displaying labeled icons in a compact format
15-
* @param props - Tag properties including icon and label
16-
* @returns A styled tag component
17+
* Kept for backwards compatibility
1718
*/
18-
export const Tag = React.memo(function Tag({ icon, label }: TagProps) {
19+
export type TagProps = SubBlockRowProps
20+
21+
/**
22+
* SubBlockRow component matching the workflow block's subblock row style
23+
* @param props - Row properties including label and optional value
24+
* @returns A styled row component
25+
*/
26+
export const SubBlockRow = React.memo(function SubBlockRow({ label, value }: SubBlockRowProps) {
27+
// Split label by colon to separate title and value if present
28+
const [title, displayValue] = label.includes(':')
29+
? label.split(':').map((s) => s.trim())
30+
: [label, value]
31+
1932
return (
20-
<div className='flex w-fit items-center gap-1 rounded-[8px] border border-gray-300 bg-white px-2 py-0.5'>
21-
<div className='h-3 w-3 text-muted-foreground'>{icon}</div>
22-
<p className='text-muted-foreground text-xs leading-normal'>{label}</p>
33+
<div className='flex items-center gap-[8px]'>
34+
<span className='min-w-0 truncate text-[#888888] text-[14px] capitalize' title={title}>
35+
{title}
36+
</span>
37+
{displayValue && (
38+
<span
39+
className='flex-1 truncate text-right text-[#171717] text-[14px]'
40+
title={displayValue}
41+
>
42+
{displayValue}
43+
</span>
44+
)}
2345
</div>
2446
)
2547
})
48+
49+
/**
50+
* Tag component - alias for SubBlockRow for backwards compatibility
51+
*/
52+
export const Tag = SubBlockRow

apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-canvas.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import { LandingFlow } from '@/app/(landing)/components/hero/components/landing-
99

1010
/**
1111
* Visual constants for landing node dimensions
12+
* Matches BLOCK_DIMENSIONS from the application
1213
*/
13-
export const CARD_WIDTH = 256
14-
export const CARD_HEIGHT = 92
14+
export const CARD_WIDTH = 250
15+
export const CARD_HEIGHT = 100
1516

1617
/**
1718
* Landing block node with positioning information

apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,29 @@ import React from 'react'
44
import { type EdgeProps, getSmoothStepPath, Position } from 'reactflow'
55

66
/**
7-
* Custom edge component with animated dotted line that floats between handles
7+
* Custom edge component with animated dashed line
8+
* Styled to match the application's workflow edges with rectangular handles
89
* @param props - React Flow edge properties
9-
* @returns An animated dotted edge component
10+
* @returns An animated dashed edge component
1011
*/
1112
export const LandingEdge = React.memo(function LandingEdge(props: EdgeProps) {
12-
const { id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, data } =
13-
props
13+
const { id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style } = props
1414

15-
// Adjust the connection points to create floating effect
16-
// Account for handle size (12px) and additional spacing
17-
const handleRadius = 6 // Half of handle width (12px)
18-
const floatingGap = 1 // Additional gap for floating effect
19-
20-
// Calculate adjusted positions based on edge direction
15+
// Adjust the connection points to connect flush with rectangular handles
16+
// Handle width is 7px, positioned at -7px from edge
2117
let adjustedSourceX = sourceX
2218
let adjustedTargetX = targetX
2319

2420
if (sourcePosition === Position.Right) {
25-
adjustedSourceX = sourceX + handleRadius + floatingGap
21+
adjustedSourceX = sourceX + 1
2622
} else if (sourcePosition === Position.Left) {
27-
adjustedSourceX = sourceX - handleRadius - floatingGap
23+
adjustedSourceX = sourceX - 1
2824
}
2925

3026
if (targetPosition === Position.Left) {
31-
adjustedTargetX = targetX - handleRadius - floatingGap
27+
adjustedTargetX = targetX - 1
3228
} else if (targetPosition === Position.Right) {
33-
adjustedTargetX = targetX + handleRadius + floatingGap
29+
adjustedTargetX = targetX + 1
3430
}
3531

3632
const [path] = getSmoothStepPath({
@@ -40,8 +36,8 @@ export const LandingEdge = React.memo(function LandingEdge(props: EdgeProps) {
4036
targetY,
4137
sourcePosition,
4238
targetPosition,
43-
borderRadius: 20,
44-
offset: 10,
39+
borderRadius: 8,
40+
offset: 16,
4541
})
4642

4743
return (

0 commit comments

Comments
 (0)