From c7db48e3a2cbec26c6e1af44e5829bd01e37dcd1 Mon Sep 17 00:00:00 2001 From: Emir Karabeg <78010029+emir-karabeg@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:04:06 -0800 Subject: [PATCH] fix(landing): ui (#2979) --- .../components/hero/components/index.ts | 4 +- .../landing-block/landing-block.tsx | 45 ++++++++-------- .../landing-block/landing-node.tsx | 39 +++++++------- .../landing-block/loop-block.tsx | 29 ++++++----- .../landing-canvas/landing-block/tag.tsx | 51 ++++++++++++++----- .../landing-canvas/landing-canvas.tsx | 5 +- .../landing-edge/landing-edge.tsx | 28 +++++----- .../app/(landing)/components/hero/hero.tsx | 41 ++++----------- .../landing-pricing/landing-pricing.tsx | 2 +- apps/sim/app/(landing)/components/nav/nav.tsx | 2 +- 10 files changed, 130 insertions(+), 116 deletions(-) diff --git a/apps/sim/app/(landing)/components/hero/components/index.ts b/apps/sim/app/(landing)/components/hero/components/index.ts index 6bda3e756..198822ec7 100644 --- a/apps/sim/app/(landing)/components/hero/components/index.ts +++ b/apps/sim/app/(landing)/components/hero/components/index.ts @@ -10,8 +10,8 @@ export { LandingLoopNode } from './landing-canvas/landing-block/landing-loop-nod export { LandingNode } from './landing-canvas/landing-block/landing-node' export type { LoopBlockProps } from './landing-canvas/landing-block/loop-block' export { LoopBlock } from './landing-canvas/landing-block/loop-block' -export type { TagProps } from './landing-canvas/landing-block/tag' -export { Tag } from './landing-canvas/landing-block/tag' +export type { SubBlockRowProps, TagProps } from './landing-canvas/landing-block/tag' +export { SubBlockRow, Tag } from './landing-canvas/landing-block/tag' export type { LandingBlockNode, LandingCanvasProps, diff --git a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-block.tsx b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-block.tsx index 7233eeed3..78f188447 100644 --- a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-block.tsx +++ b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-block.tsx @@ -1,12 +1,12 @@ import React from 'react' -import { BookIcon } from 'lucide-react' import { - Tag, - type TagProps, + SubBlockRow, + type SubBlockRowProps, } from '@/app/(landing)/components/hero/components/landing-canvas/landing-block/tag' /** * Data structure for a landing card component + * Matches the workflow block structure from the application */ export interface LandingCardData { /** Icon element to display in the card header */ @@ -15,8 +15,8 @@ export interface LandingCardData { color: string | '#f6f6f6' /** Name/title of the card */ name: string - /** Optional tags to display at the bottom of the card */ - tags?: TagProps[] + /** Optional subblock rows to display below the header */ + tags?: SubBlockRowProps[] } /** @@ -28,7 +28,8 @@ export interface LandingBlockProps extends LandingCardData { } /** - * Landing block component that displays a card with icon, name, and optional tags + * Landing block component that displays a card with icon, name, and optional subblock rows + * Styled to match the application's workflow blocks * @param props - Component properties including icon, color, name, tags, and className * @returns A styled block card component */ @@ -39,33 +40,37 @@ export const LandingBlock = React.memo(function LandingBlock({ tags, className, }: LandingBlockProps) { + const hasContentBelowHeader = tags && tags.length > 0 + return (
-
-
+ {/* Header - matches workflow-block.tsx header styling */} +
+
{icon}
-

{name}

+ + {name} +
-
- {tags && tags.length > 0 ? ( -
+ {/* Content - SubBlock Rows matching workflow-block.tsx */} + {hasContentBelowHeader && ( +
{tags.map((tag) => ( - + ))}
- ) : null} + )}
) }) diff --git a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx index 3ef3eb987..0d92b9672 100644 --- a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx +++ b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx @@ -7,9 +7,14 @@ import { type LandingCardData, } from '@/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-block' +/** + * Handle Y offset from block top - matches HANDLE_POSITIONS.DEFAULT_Y_OFFSET + */ +const HANDLE_Y_OFFSET = 20 + /** * React Flow node component for the landing canvas - * Includes CSS animations and connection handles + * Styled to match the application's workflow blocks * @param props - Component properties containing node data * @returns A React Flow compatible node component */ @@ -41,15 +46,15 @@ export const LandingNode = React.memo(function LandingNode({ data }: { data: Lan type='target' position={Position.Left} style={{ - width: '12px', - height: '12px', - background: '#FEFEFE', - border: '1px solid #E5E5E5', - borderRadius: '50%', - top: '50%', - left: '-20px', + width: '7px', + height: '20px', + background: '#D1D1D1', + border: 'none', + borderRadius: '2px 0 0 2px', + top: `${HANDLE_Y_OFFSET}px`, + left: '-7px', transform: 'translateY(-50%)', - zIndex: 2, + zIndex: 10, }} isConnectable={false} /> @@ -59,15 +64,15 @@ export const LandingNode = React.memo(function LandingNode({ data }: { data: Lan type='source' position={Position.Right} style={{ - width: '12px', - height: '12px', - background: '#FEFEFE', - border: '1px solid #E5E5E5', - borderRadius: '50%', - top: '50%', - right: '-20px', + width: '7px', + height: '20px', + background: '#D1D1D1', + border: 'none', + borderRadius: '0 2px 2px 0', + top: `${HANDLE_Y_OFFSET}px`, + right: '-7px', transform: 'translateY(-50%)', - zIndex: 2, + zIndex: 10, }} isConnectable={false} /> diff --git a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/loop-block.tsx b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/loop-block.tsx index 53e5538f0..cab66dac4 100644 --- a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/loop-block.tsx +++ b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/loop-block.tsx @@ -15,6 +15,7 @@ export interface LoopBlockProps { /** * Loop block container component that provides a styled container * for grouping related elements with a dashed border + * Styled to match the application's subflow containers * @param props - Component properties including children and styling * @returns A styled loop container component */ @@ -29,33 +30,33 @@ export const LoopBlock = React.memo(function LoopBlock({ style={{ width: '1198px', height: '528px', - borderRadius: '14px', - background: 'rgba(59, 130, 246, 0.10)', + borderRadius: '8px', + background: 'rgba(59, 130, 246, 0.08)', position: 'relative', ...style, }} > - {/* Custom dashed border with SVG */} + {/* Custom dashed border with SVG - 8px border radius to match blocks */} diff --git a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/tag.tsx b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/tag.tsx index 644e8a242..655a8b3a9 100644 --- a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/tag.tsx +++ b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/tag.tsx @@ -1,25 +1,52 @@ import React from 'react' /** - * Properties for a tag component + * Properties for a subblock row component + * Matches the SubBlockRow pattern from workflow-block.tsx */ -export interface TagProps { - /** Icon element to display in the tag */ - icon: React.ReactNode - /** Text label for the tag */ +export interface SubBlockRowProps { + /** Icon element to display (optional, for visual context) */ + icon?: React.ReactNode + /** Text label for the row title */ label: string + /** Optional value to display on the right side */ + value?: string } /** - * Tag component for displaying labeled icons in a compact format - * @param props - Tag properties including icon and label - * @returns A styled tag component + * Kept for backwards compatibility */ -export const Tag = React.memo(function Tag({ icon, label }: TagProps) { +export type TagProps = SubBlockRowProps + +/** + * SubBlockRow component matching the workflow block's subblock row style + * @param props - Row properties including label and optional value + * @returns A styled row component + */ +export const SubBlockRow = React.memo(function SubBlockRow({ label, value }: SubBlockRowProps) { + // Split label by colon to separate title and value if present + const [title, displayValue] = label.includes(':') + ? label.split(':').map((s) => s.trim()) + : [label, value] + return ( -
-
{icon}
-

{label}

+
+ + {title} + + {displayValue && ( + + {displayValue} + + )}
) }) + +/** + * Tag component - alias for SubBlockRow for backwards compatibility + */ +export const Tag = SubBlockRow diff --git a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-canvas.tsx b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-canvas.tsx index 0cb2f41e1..f3bcd0f52 100644 --- a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-canvas.tsx +++ b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-canvas.tsx @@ -9,9 +9,10 @@ import { LandingFlow } from '@/app/(landing)/components/hero/components/landing- /** * Visual constants for landing node dimensions + * Matches BLOCK_DIMENSIONS from the application */ -export const CARD_WIDTH = 256 -export const CARD_HEIGHT = 92 +export const CARD_WIDTH = 250 +export const CARD_HEIGHT = 100 /** * Landing block node with positioning information diff --git a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx index cdf68e01b..65c48f33e 100644 --- a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx +++ b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx @@ -4,33 +4,29 @@ import React from 'react' import { type EdgeProps, getSmoothStepPath, Position } from 'reactflow' /** - * Custom edge component with animated dotted line that floats between handles + * Custom edge component with animated dashed line + * Styled to match the application's workflow edges with rectangular handles * @param props - React Flow edge properties - * @returns An animated dotted edge component + * @returns An animated dashed edge component */ export const LandingEdge = React.memo(function LandingEdge(props: EdgeProps) { - const { id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, data } = - props + const { id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style } = props - // Adjust the connection points to create floating effect - // Account for handle size (12px) and additional spacing - const handleRadius = 6 // Half of handle width (12px) - const floatingGap = 1 // Additional gap for floating effect - - // Calculate adjusted positions based on edge direction + // Adjust the connection points to connect flush with rectangular handles + // Handle width is 7px, positioned at -7px from edge let adjustedSourceX = sourceX let adjustedTargetX = targetX if (sourcePosition === Position.Right) { - adjustedSourceX = sourceX + handleRadius + floatingGap + adjustedSourceX = sourceX + 1 } else if (sourcePosition === Position.Left) { - adjustedSourceX = sourceX - handleRadius - floatingGap + adjustedSourceX = sourceX - 1 } if (targetPosition === Position.Left) { - adjustedTargetX = targetX - handleRadius - floatingGap + adjustedTargetX = targetX - 1 } else if (targetPosition === Position.Right) { - adjustedTargetX = targetX + handleRadius + floatingGap + adjustedTargetX = targetX + 1 } const [path] = getSmoothStepPath({ @@ -40,8 +36,8 @@ export const LandingEdge = React.memo(function LandingEdge(props: EdgeProps) { targetY, sourcePosition, targetPosition, - borderRadius: 20, - offset: 10, + borderRadius: 8, + offset: 16, }) return ( diff --git a/apps/sim/app/(landing)/components/hero/hero.tsx b/apps/sim/app/(landing)/components/hero/hero.tsx index 7c94b011e..546dc4762 100644 --- a/apps/sim/app/(landing)/components/hero/hero.tsx +++ b/apps/sim/app/(landing)/components/hero/hero.tsx @@ -1,16 +1,7 @@ 'use client' import React from 'react' -import { - ArrowUp, - BinaryIcon, - BookIcon, - CalendarIcon, - CodeIcon, - Globe2Icon, - MessageSquareIcon, - VariableIcon, -} from 'lucide-react' +import { ArrowUp, CodeIcon } from 'lucide-react' import { useRouter } from 'next/navigation' import { type Edge, type Node, Position } from 'reactflow' import { @@ -23,7 +14,6 @@ import { JiraIcon, LinearIcon, NotionIcon, - OpenAIIcon, OutlookIcon, PackageSearchIcon, PineconeIcon, @@ -65,67 +55,56 @@ const SERVICE_TEMPLATES = { /** * Landing blocks for the canvas preview + * Styled to match the application's workflow blocks with subblock rows */ const LANDING_BLOCKS: LandingManualBlock[] = [ { id: 'schedule', name: 'Schedule', color: '#7B68EE', - icon: , + icon: , positions: { mobile: { x: 8, y: 60 }, tablet: { x: 40, y: 120 }, desktop: { x: 60, y: 180 }, }, - tags: [ - { icon: , label: '09:00AM Daily' }, - { icon: , label: 'PST' }, - ], + tags: [{ label: 'Time: 09:00AM Daily' }, { label: 'Timezone: PST' }], }, { id: 'knowledge', name: 'Knowledge', color: '#00B0B0', - icon: , + icon: , positions: { mobile: { x: 120, y: 140 }, tablet: { x: 220, y: 200 }, desktop: { x: 420, y: 241 }, }, - tags: [ - { icon: , label: 'Product Vector DB' }, - { icon: , label: 'Limit: 10' }, - ], + tags: [{ label: 'Source: Product Vector DB' }, { label: 'Limit: 10' }], }, { id: 'agent', name: 'Agent', color: '#802FFF', - icon: , + icon: , positions: { mobile: { x: 340, y: 60 }, tablet: { x: 540, y: 120 }, desktop: { x: 880, y: 142 }, }, - tags: [ - { icon: , label: 'gpt-5' }, - { icon: , label: 'You are a support ag...' }, - ], + tags: [{ label: 'Model: gpt-5' }, { label: 'Prompt: You are a support ag...' }], }, { id: 'function', name: 'Function', color: '#FF402F', - icon: , + icon: , positions: { mobile: { x: 480, y: 220 }, tablet: { x: 740, y: 280 }, desktop: { x: 880, y: 340 }, }, - tags: [ - { icon: , label: 'Python' }, - { icon: , label: 'time = "2025-09-01...' }, - ], + tags: [{ label: 'Language: Python' }, { label: 'Code: time = "2025-09-01...' }], }, ] diff --git a/apps/sim/app/(landing)/components/landing-pricing/landing-pricing.tsx b/apps/sim/app/(landing)/components/landing-pricing/landing-pricing.tsx index 2cc62e986..e6aa6d6f8 100644 --- a/apps/sim/app/(landing)/components/landing-pricing/landing-pricing.tsx +++ b/apps/sim/app/(landing)/components/landing-pricing/landing-pricing.tsx @@ -229,7 +229,7 @@ function PricingCard({ */ export default function LandingPricing() { return ( -
+

Pricing Plans

diff --git a/apps/sim/app/(landing)/components/nav/nav.tsx b/apps/sim/app/(landing)/components/nav/nav.tsx index ff9e8787e..0a72d5b49 100644 --- a/apps/sim/app/(landing)/components/nav/nav.tsx +++ b/apps/sim/app/(landing)/components/nav/nav.tsx @@ -21,7 +21,7 @@ interface NavProps { } export default function Nav({ hideAuthButtons = false, variant = 'landing' }: NavProps = {}) { - const [githubStars, setGithubStars] = useState('25.8k') + const [githubStars, setGithubStars] = useState('26.1k') const [isHovered, setIsHovered] = useState(false) const [isLoginHovered, setIsLoginHovered] = useState(false) const router = useRouter()