diff --git a/frontend/app/block/block.less b/frontend/app/block/block.less index bc13f890a..b214012f5 100644 --- a/frontend/app/block/block.less +++ b/frontend/app/block/block.less @@ -287,39 +287,95 @@ .connstatus-overlay { position: absolute; - top: var(--header-height); - left: 2px; - right: 2px; - background-color: rgba(0, 0, 0, 0.3); + top: calc(var(--header-height) + 6px); + left: 6px; + right: 6px; z-index: var(--zindex-block-mask-inner); display: flex; align-items: center; justify-content: flex-start; flex-direction: column; overflow: hidden; + background: rgba(230, 186, 30, 0.2); + backdrop-filter: blur(50px); + border-radius: 6px; + box-shadow: 0px 13px 16px 0px rgba(0, 0, 0, 0.4); - .connstatus-mainelem { + .connstatus-content { display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 20px; + flex-direction: row; + justify-content: space-between; + padding: 10px 8px 10px 12px; width: 100%; - background-color: rgba(60, 60, 60, 0.65); - backdrop-filter: blur(3px); font: var(--base-font); color: var(--secondary-text-color); + gap: 12px; - .connstatus-error { - color: var(--error-color); + .connstatus-status-icon-wrapper { + display: flex; + flex-direction: row; + align-items: center; + gap: 12px; + flex-grow: 1; + min-width: 0; + + &.has-error { + align-items: flex-start; + } + + > i { + color: #e6ba1e; + font-size: 16px; + } + + .connstatus-status { + .ellipsis(); + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + flex-grow: 1; + width: 100%; + + .connstatus-status-text { + .ellipsis(); + max-width: 100%; + font-size: 11px; + font-style: normal; + font-weight: 600; + line-height: 16px; + letter-spacing: 0.11px; + color: white; + } + + .connstatus-error { + .ellipsis(); + width: 94%; + font-size: 11px; + font-style: normal; + font-weight: 400; + line-height: 15px; + letter-spacing: 0.11px; + } + } } .connstatus-actions { - margin-top: 10px; display: flex; - gap: 5px; - flex-direction: row; - flex-wrap: wrap; + align-items: flex-start; + justify-content: center; + gap: 6px; + + button { + i { + font-size: 11px; + opacity: 0.7; + } + } + + .button:last-child { + margin-top: 1.5px; + } } } } diff --git a/frontend/app/block/blockframe.tsx b/frontend/app/block/blockframe.tsx index f522cfb95..3ef1a5cc0 100644 --- a/frontend/app/block/blockframe.tsx +++ b/frontend/app/block/blockframe.tsx @@ -1,6 +1,7 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { BlockComponentModel } from "@/app/block/blocktypes"; import { blockViewToIcon, blockViewToName, @@ -12,6 +13,7 @@ import { Input, } from "@/app/block/blockutil"; import { Button } from "@/app/element/button"; +import { useWidth } from "@/app/hook/useWidth"; import { TypeAheadModal } from "@/app/modals/typeaheadmodal"; import { ContextMenuModel } from "@/app/store/contextmenu"; import { @@ -264,52 +266,76 @@ function renderHeaderElements(headerTextUnion: HeaderElem[], preview: boolean): const ConnStatusOverlay = React.memo( ({ + blockModel, nodeModel, viewModel, changeConnModalAtom, }: { + blockModel: BlockComponentModel; nodeModel: NodeModel; viewModel: ViewModel; changeConnModalAtom: jotai.PrimitiveAtom; }) => { const [blockData] = WOS.useWaveObjectValue(WOS.makeORef("block", nodeModel.blockId)); - const [connModalOpen, setConnModalOpen] = jotai.useAtom(changeConnModalAtom); + const [connModalOpen] = jotai.useAtom(changeConnModalAtom); const connName = blockData.meta?.connection; const connStatus = jotai.useAtomValue(getConnStatusAtom(connName)); const isLayoutMode = jotai.useAtomValue(atoms.controlShiftDelayAtom); + const width = useWidth(blockModel?.blockRef); + const [showError, setShowError] = React.useState(false); + + React.useEffect(() => { + if (width) { + const hasError = !util.isBlank(connStatus.error); + const showError = hasError && width >= 250 && connStatus.status != "connecting"; + setShowError(showError); + } + }, [width, connStatus, setShowError]); + const handleTryReconnect = React.useCallback(() => { const prtn = WshServer.ConnConnectCommand(connName, { timeout: 60000 }); prtn.catch((e) => console.log("error reconnecting", connName, e)); }, [connName]); - const handleSwitchConnection = React.useCallback(() => { - setConnModalOpen(true); - }, [setConnModalOpen]); - if (isLayoutMode || connStatus.status == "connected" || connModalOpen) { - return null; - } + let statusText = `Disconnected from "${connName}"`; let showReconnect = true; if (connStatus.status == "connecting") { statusText = `Connecting to "${connName}"...`; showReconnect = false; } + let reconDisplay = null; + let reconClassName = "outlined"; + if (width && width < 350) { + reconDisplay = ; + reconClassName = clsx(reconClassName, "font-size-12 vertical-padding-5 horizontal-padding-6"); + } else { + reconDisplay = "Reconnect"; + reconClassName = clsx(reconClassName, "font-size-11 vertical-padding-3 horizontal-padding-7"); + } + const showIcon = connStatus.status != "connecting"; + + if (isLayoutMode || connStatus.status == "connected" || connModalOpen) { + return null; + } + return (
-
-
{statusText}
- {!util.isBlank(connStatus.error) ? ( -
error: {connStatus.error}
- ) : null} +
+
+ {showIcon && } +
+
{statusText}
+ {showError ?
error: {connStatus.error}
: null} +
+
{showReconnect ? (
- - + {/* */}
) : null}
@@ -417,7 +443,12 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => { ref={blockModel?.blockRef} > - +
{preview ? previewElem : children} diff --git a/frontend/app/element/button.less b/frontend/app/element/button.less index dffa5a895..2973a2594 100644 --- a/frontend/app/element/button.less +++ b/frontend/app/element/button.less @@ -17,7 +17,10 @@ cursor: pointer; outline: inherit; display: flex; - padding: 8px 20px; + padding-top: 8px; + padding-bottom: 8px; + padding-left: 20px; + padding-right: 20px; align-items: center; gap: 4px; border-radius: 6px; @@ -79,6 +82,11 @@ color: var(--error-color); } + &.outlined { + background: none; + border: 1px solid rgba(255, 255, 255, 0.5); + } + &.disabled { opacity: 0.5; } @@ -96,6 +104,86 @@ padding-bottom: 2px; } + .vertical-padding-3 { + padding-top: 3px; + padding-bottom: 3px; + } + + .vertical-padding-4 { + padding-top: 4px; + padding-bottom: 4px; + } + + .vertical-padding-5 { + padding-top: 5px; + padding-bottom: 5px; + } + + .vertical-padding-6 { + padding-top: 6px; + padding-bottom: 6px; + } + + .vertical-padding-7 { + padding-top: 7px; + padding-bottom: 7px; + } + + .vertical-padding-8 { + padding-top: 8px; + padding-bottom: 8px; + } + + .vertical-padding-9 { + padding-top: 9px; + padding-bottom: 9px; + } + + .vertical-padding-10 { + padding-top: 10px; + padding-bottom: 10px; + } + + .horizontal-padding-2 { + padding-left: 2px; + padding-right: 2px; + } + + .horizontal-padding-3 { + padding-left: 3px; + padding-right: 3px; + } + + .horizontal-padding-4 { + padding-left: 4px; + padding-right: 4px; + } + + .horizontal-padding-5 { + padding-left: 5px; + padding-right: 5px; + } + + .horizontal-padding-6 { + padding-left: 6px; + padding-right: 6px; + } + + .horizontal-padding-7 { + padding-left: 7px; + padding-right: 7px; + } + + .horizontal-padding-8 { + padding-left: 8px; + padding-right: 8px; + } + + .horizontal-padding-9 { + padding-left: 9px; + padding-right: 9px; + } + .horizontal-padding-10 { padding-left: 10px; padding-right: 10px;