fix web style

This commit is contained in:
hjlarry 2026-01-17 22:10:10 +08:00
parent 03cc196965
commit 434f7f3bcb
20 changed files with 127 additions and 118 deletions

View File

@ -1,36 +1,36 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "16",
"height": "16",
"viewBox": "0 0 16 16",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M0 4C0 1.79086 1.79086 0 4 0H12C14.2091 0 16 1.79086 16 4V12C16 14.2091 14.2091 16 12 16H4C1.79086 16 0 14.2091 0 12V4Z",
"fill": "white",
"fill-opacity": "0.12"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M3.42756 8.7358V7.62784H10.8764C11.2003 7.62784 11.4957 7.5483 11.7628 7.3892C12.0298 7.23011 12.2415 7.01705 12.3977 6.75C12.5568 6.48295 12.6364 6.1875 12.6364 5.86364C12.6364 5.53977 12.5568 5.24574 12.3977 4.98153C12.2386 4.71449 12.0256 4.50142 11.7585 4.34233C11.4943 4.18324 11.2003 4.10369 10.8764 4.10369H10.3991V3H10.8764C11.4048 3 11.8849 3.12926 12.3168 3.38778C12.7486 3.64631 13.0938 3.99148 13.3523 4.4233C13.6108 4.85511 13.7401 5.33523 13.7401 5.86364C13.7401 6.25852 13.6648 6.62926 13.5142 6.97585C13.3665 7.32244 13.1619 7.62784 12.9006 7.89205C12.6392 8.15625 12.3352 8.36364 11.9886 8.5142C11.642 8.66193 11.2713 8.7358 10.8764 8.7358H3.42756ZM6.16761 12.0554L2.29403 8.18182L6.16761 4.30824L6.9304 5.07102L3.81534 8.18182L6.9304 11.2926L6.16761 12.0554Z",
"fill": "white"
},
"children": []
}
]
},
"name": "EnterKey"
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "16",
"height": "16",
"viewBox": "0 0 16 16",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M0 4C0 1.79086 1.79086 0 4 0H12C14.2091 0 16 1.79086 16 4V12C16 14.2091 14.2091 16 12 16H4C1.79086 16 0 14.2091 0 12V4Z",
"fill": "white",
"fill-opacity": "0.12"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M3.42756 8.7358V7.62784H10.8764C11.2003 7.62784 11.4957 7.5483 11.7628 7.3892C12.0298 7.23011 12.2415 7.01705 12.3977 6.75C12.5568 6.48295 12.6364 6.1875 12.6364 5.86364C12.6364 5.53977 12.5568 5.24574 12.3977 4.98153C12.2386 4.71449 12.0256 4.50142 11.7585 4.34233C11.4943 4.18324 11.2003 4.10369 10.8764 4.10369H10.3991V3H10.8764C11.4048 3 11.8849 3.12926 12.3168 3.38778C12.7486 3.64631 13.0938 3.99148 13.3523 4.4233C13.6108 4.85511 13.7401 5.33523 13.7401 5.86364C13.7401 6.25852 13.6648 6.62926 13.5142 6.97585C13.3665 7.32244 13.1619 7.62784 12.9006 7.89205C12.6392 8.15625 12.3352 8.36364 11.9886 8.5142C11.642 8.66193 11.2713 8.7358 10.8764 8.7358H3.42756ZM6.16761 12.0554L2.29403 8.18182L6.16761 4.30824L6.9304 5.07102L3.81534 8.18182L6.9304 11.2926L6.16761 12.0554Z",
"fill": "white"
},
"children": []
}
]
},
"name": "EnterKey"
}

View File

@ -1,17 +1,17 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './EnterKey.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
import * as React from 'react'
import IconBase from '@/app/components/base/icons/IconBase'
import data from './EnterKey.json'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>
},
) => <IconBase {...props} ref={ref} data={data as IconData} />

View File

@ -1,26 +1,26 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"xmlns": "http://www.w3.org/2000/svg",
"width": "14",
"height": "12",
"viewBox": "0 0 14 12",
"fill": "none"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M12.3334 4C12.3334 2.52725 11.1395 1.33333 9.66671 1.33333H4.33337C2.86062 1.33333 1.66671 2.52724 1.66671 4V10.6667H9.66671C11.1395 10.6667 12.3334 9.47274 12.3334 8V4ZM7.66671 6.66667V8H4.33337V6.66667H7.66671ZM9.66671 4V5.33333H4.33337V4H9.66671ZM13.6667 8C13.6667 10.2091 11.8758 12 9.66671 12H0.333374V4C0.333374 1.79086 2.12424 0 4.33337 0H9.66671C11.8758 0 13.6667 1.79086 13.6667 4V8Z",
"fill": "currentColor"
},
"children": []
}
]
},
"name": "Comment"
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"xmlns": "http://www.w3.org/2000/svg",
"width": "14",
"height": "12",
"viewBox": "0 0 14 12",
"fill": "none"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M12.3334 4C12.3334 2.52725 11.1395 1.33333 9.66671 1.33333H4.33337C2.86062 1.33333 1.66671 2.52724 1.66671 4V10.6667H9.66671C11.1395 10.6667 12.3334 9.47274 12.3334 8V4ZM7.66671 6.66667V8H4.33337V6.66667H7.66671ZM9.66671 4V5.33333H4.33337V4H9.66671ZM13.6667 8C13.6667 10.2091 11.8758 12 9.66671 12H0.333374V4C0.333374 1.79086 2.12424 0 4.33337 0H9.66671C11.8758 0 13.6667 1.79086 13.6667 4V8Z",
"fill": "currentColor"
},
"children": []
}
]
},
"name": "Comment"
}

View File

@ -1,17 +1,17 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Comment.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
import * as React from 'react'
import IconBase from '@/app/components/base/icons/IconBase'
import data from './Comment.json'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>
},
) => <IconBase {...props} ref={ref} data={data as IconData} />

View File

@ -1,8 +1,8 @@
import type { FC } from 'react'
import { memo } from 'react'
import Avatar from '@/app/components/base/avatar'
import { getUserColor } from '@/app/components/workflow/collaboration/utils/user-color'
import { useAppContext } from '@/context/app-context'
import Avatar from '@/app/components/base/avatar'
type User = {
id: string
@ -26,7 +26,8 @@ export const UserAvatarList: FC<UserAvatarListProps> = memo(({
showCount = true,
}) => {
const { userProfile } = useAppContext()
if (!users.length) return null
if (!users.length)
return null
const shouldShowCount = showCount && users.length > maxVisible
const actualMaxVisible = shouldShowCount ? Math.max(1, maxVisible - 1) : maxVisible
@ -43,14 +44,14 @@ export const UserAvatarList: FC<UserAvatarListProps> = memo(({
return (
<div
key={`${user.id}-${index}`}
className='relative'
className="relative"
style={{ zIndex: visibleUsers.length - index }}
>
<Avatar
name={user.name}
avatar={user.avatar_url || null}
size={size}
className='ring-2 ring-components-panel-bg'
className="ring-2 ring-components-panel-bg"
backgroundColor={userColor}
/>
</div>
@ -60,14 +61,15 @@ export const UserAvatarList: FC<UserAvatarListProps> = memo(({
)}
{shouldShowCount && remainingCount > 0 && (
<div
className={'flex items-center justify-center rounded-full bg-gray-500 text-[10px] leading-none text-white ring-2 ring-components-panel-bg'}
className="flex items-center justify-center rounded-full bg-gray-500 text-[10px] leading-none text-white ring-2 ring-components-panel-bg"
style={{
zIndex: 0,
width: size,
height: size,
}}
>
+{remainingCount}
+
{remainingCount}
</div>
)}
</div>

View File

@ -1,6 +1,6 @@
import type { FC } from 'react'
import { useViewport } from 'reactflow'
import type { CursorPosition, OnlineUser } from '@/app/components/workflow/collaboration/types'
import { useViewport } from 'reactflow'
import { getUserColor } from '../utils/user-color'
type UserCursorsProps = {

View File

@ -13,7 +13,8 @@ export class EventEmitter {
}
off<T = any>(event: string, handler?: EventHandler<T>): void {
if (!this.events.has(event)) return
if (!this.events.has(event))
return
const handlers = this.events.get(event)!
if (handler)
@ -26,7 +27,8 @@ export class EventEmitter {
}
emit<T = any>(event: string, data: T): void {
if (!this.events.has(event)) return
if (!this.events.has(event))
return
const handlers = this.events.get(event)!
handlers.forEach((handler) => {

View File

@ -1,7 +1,7 @@
import type { Socket } from 'socket.io-client'
import type { DebugInfo, WebSocketConfig } from '../types/websocket'
import { io } from 'socket.io-client'
import { ACCESS_TOKEN_LOCAL_STORAGE_NAME } from '@/config'
import type { DebugInfo, WebSocketConfig } from '../types/websocket'
const isUnauthorizedAck = (...ackArgs: any[]): boolean => {
const [first, second] = ackArgs

View File

@ -1,10 +1,10 @@
import { useEffect, useRef, useState } from 'react'
import type { ReactFlowInstance } from 'reactflow'
import type { CollaborationState } from '../types/collaboration'
import { useEffect, useRef, useState } from 'react'
import Toast from '@/app/components/base/toast'
import { useGlobalPublicStore } from '@/context/global-public-context'
import { collaborationManager } from '../core/collaboration-manager'
import { CursorService } from '../services/cursor-service'
import type { CollaborationState } from '../types/collaboration'
import { useGlobalPublicStore } from '@/context/global-public-context'
import Toast from '@/app/components/base/toast'
export function useCollaboration(appId: string, reactFlowStore?: any) {
const [state, setState] = useState<Partial<CollaborationState & { isLeader: boolean }>>({

View File

@ -1,5 +1,5 @@
export { collaborationManager } from './core/collaboration-manager'
export { webSocketClient } from './core/websocket-manager'
export { CursorService } from './services/cursor-service'
export { useCollaboration } from './hooks/use-collaboration'
export { CursorService } from './services/cursor-service'
export * from './types'

View File

@ -1,6 +1,6 @@
import type { RefObject } from 'react'
import type { CursorPosition } from '../types/collaboration'
import type { ReactFlowInstance } from 'reactflow'
import type { CursorPosition } from '../types/collaboration'
const CURSOR_MIN_MOVE_DISTANCE = 10
const CURSOR_THROTTLE_MS = 300
@ -12,14 +12,15 @@ export class CursorService {
private onCursorUpdate: ((cursors: Record<string, CursorPosition>) => void) | null = null
private onEmitPosition: ((position: CursorPosition) => void) | null = null
private lastEmitTime = 0
private lastPosition: { x: number; y: number } | null = null
private lastPosition: { x: number, y: number } | null = null
startTracking(
containerRef: RefObject<HTMLElement>,
onEmitPosition: (position: CursorPosition) => void,
reactFlowInstance?: ReactFlowInstance,
): void {
if (this.isTracking) this.stopTracking()
if (this.isTracking)
this.stopTracking()
this.containerRef = containerRef
this.onEmitPosition = onEmitPosition
@ -51,7 +52,8 @@ export class CursorService {
}
private handleMouseMove = (event: MouseEvent): void => {
if (!this.containerRef?.current || !this.onEmitPosition) return
if (!this.containerRef?.current || !this.onEmitPosition)
return
const rect = this.containerRef.current.getBoundingClientRect()
let x = event.clientX - rect.left

View File

@ -51,16 +51,16 @@ export type GraphSyncData = {
export type CollaborationEventType
= | 'mouse_move'
| 'vars_and_features_update'
| 'sync_request'
| 'app_state_update'
| 'app_meta_update'
| 'mcp_server_update'
| 'workflow_update'
| 'comments_update'
| 'node_panel_presence'
| 'app_publish_update'
| 'graph_resync_request'
| 'vars_and_features_update'
| 'sync_request'
| 'app_state_update'
| 'app_meta_update'
| 'mcp_server_update'
| 'workflow_update'
| 'comments_update'
| 'node_panel_presence'
| 'app_publish_update'
| 'graph_resync_request'
export type CollaborationUpdate = {
type: CollaborationEventType

View File

@ -1,3 +1,3 @@
export * from './websocket'
export * from './collaboration'
export * from './events'
export * from './websocket'

View File

@ -1,6 +1,6 @@
import { useEventListener } from 'ahooks'
import { useWorkflowStore } from './store'
import { useWorkflowComment } from './hooks/use-workflow-comment'
import { useWorkflowStore } from './store'
const CommentManager = () => {
const workflowStore = useWorkflowStore()

View File

@ -1,18 +1,18 @@
'use client'
import type { FC, PointerEvent as ReactPointerEvent } from 'react'
import type { WorkflowCommentList } from '@/service/workflow-comment'
import { memo, useCallback, useMemo, useRef, useState } from 'react'
import { useReactFlow, useViewport } from 'reactflow'
import { UserAvatarList } from '@/app/components/base/user-avatar-list'
import CommentPreview from './comment-preview'
import type { WorkflowCommentList } from '@/service/workflow-comment'
import { useAppContext } from '@/context/app-context'
import CommentPreview from './comment-preview'
type CommentIconProps = {
comment: WorkflowCommentList
onClick: () => void
isActive?: boolean
onPositionUpdate?: (position: { x: number; y: number }) => void
onPositionUpdate?: (position: { x: number, y: number }) => void
}
export const CommentIcon: FC<CommentIconProps> = memo(({ comment, onClick, isActive = false, onPositionUpdate }) => {
@ -21,7 +21,7 @@ export const CommentIcon: FC<CommentIconProps> = memo(({ comment, onClick, isAct
const { userProfile } = useAppContext()
const isAuthor = comment.created_by_account?.id === userProfile?.id
const [showPreview, setShowPreview] = useState(false)
const [dragPosition, setDragPosition] = useState<{ x: number; y: number } | null>(null)
const [dragPosition, setDragPosition] = useState<{ x: number, y: number } | null>(null)
const [isDragging, setIsDragging] = useState(false)
const dragStateRef = useRef<{
offsetX: number
@ -181,8 +181,7 @@ export const CommentIcon: FC<CommentIconProps> = memo(({ comment, onClick, isAct
// Width calculation: first avatar + (additional avatars * (size - spacing)) + padding
const dynamicWidth = Math.max(40, // minimum width
8 + avatarSize + Math.max(0, (showCount ? 2 : maxVisible - 1)) * (avatarSize - avatarSpacing) + 8,
)
8 + avatarSize + Math.max(0, (showCount ? 2 : maxVisible - 1)) * (avatarSize - avatarSpacing) + 8)
const pointerEventHandlers = useMemo(() => ({
onPointerDown: handlePointerDown,
@ -200,7 +199,7 @@ export const CommentIcon: FC<CommentIconProps> = memo(({ comment, onClick, isAct
top: canvasPosition.y,
transform: 'translate(-50%, -50%)',
}}
data-role='comment-marker'
data-role="comment-marker"
{...pointerEventHandlers}
>
<div
@ -209,14 +208,15 @@ export const CommentIcon: FC<CommentIconProps> = memo(({ comment, onClick, isAct
onMouseLeave={handleMouseLeave}
>
<div
className={'relative h-10 rounded-br-full rounded-tl-full rounded-tr-full'}
className="relative h-10 rounded-br-full rounded-tl-full rounded-tr-full"
style={{ width: dynamicWidth }}
>
<div className={`absolute inset-[6px] overflow-hidden rounded-br-full rounded-tl-full rounded-tr-full border bg-components-panel-bg transition-shadow ${
isActive
? 'border-primary-500 ring-1 ring-primary-500'
: 'border-components-panel-border'
}`}>
}`}
>
<div className="flex h-full w-full items-center justify-center px-1">
<UserAvatarList
users={participants}
@ -238,15 +238,18 @@ export const CommentIcon: FC<CommentIconProps> = memo(({ comment, onClick, isAct
top: (effectiveScreenPosition.y - containerTop) + 20,
transform: 'translateY(-100%)',
}}
data-role='comment-preview'
data-role="comment-preview"
{...pointerEventHandlers}
onMouseEnter={() => setShowPreview(true)}
onMouseLeave={() => setShowPreview(false)}
>
<CommentPreview comment={comment} onClick={() => {
setShowPreview(false)
onClick()
}} />
<CommentPreview
comment={comment}
onClick={() => {
setShowPreview(false)
onClick()
}}
/>
</div>
)}
</>

View File

@ -1,9 +1,9 @@
'use client'
import type { FC } from 'react'
import type { WorkflowCommentList } from '@/service/workflow-comment'
import { memo, useEffect, useMemo } from 'react'
import { UserAvatarList } from '@/app/components/base/user-avatar-list'
import type { WorkflowCommentList } from '@/service/workflow-comment'
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
import { useStore } from '../store'

View File

@ -1,8 +1,8 @@
import type { FC } from 'react'
import { memo } from 'react'
import { Comment } from '@/app/components/base/icons/src/public/other'
import { useStore } from '../store'
import { ControlMode } from '../types'
import { Comment } from '@/app/components/base/icons/src/public/other'
export const CommentCursor: FC = memo(() => {
const controlMode = useStore(s => s.controlMode)

View File

@ -1,5 +1,5 @@
export { CommentCursor } from './cursor'
export { CommentInput } from './comment-input'
export { CommentIcon } from './comment-icon'
export { CommentThread } from './thread'
export { CommentInput } from './comment-input'
export { CommentCursor } from './cursor'
export { MentionInput } from './mention-input'
export { CommentThread } from './thread'

View File

@ -1,6 +1,6 @@
import type { Edge, Node } from '../types'
import { useCallback } from 'react'
import { useStoreApi } from 'reactflow'
import type { Edge, Node } from '../types'
import { collaborationManager } from '../collaboration/core/collaboration-manager'
const sanitizeNodeForBroadcast = (node: Node): Node => {

View File

@ -1,5 +1,5 @@
import { del, get, post, put } from './base'
import type { CommonResponse } from '@/models/common'
import { del, get, post, put } from './base'
export type UserProfile = {
id: string