diff --git a/src/components/connectionstatus/ConnectionStatus.tsx b/src/components/connectionstatus/ConnectionStatus.tsx new file mode 100644 index 0000000..c0822c9 --- /dev/null +++ b/src/components/connectionstatus/ConnectionStatus.tsx @@ -0,0 +1,223 @@ +import { Component, Show, createMemo, splitProps } from "solid-js"; +import { twMerge } from "tailwind-merge"; +import Badge from "../badge"; +import Button from "../button"; +import Flex from "../flex"; +import Tooltip from "../tooltip"; +import type { ComponentColor, IComponentBaseProps } from "../types"; + +export type ConnectionState = + | "connecting" + | "connected" + | "disconnected" + | "error"; + +export interface ConnectionStatusProps extends IComponentBaseProps { + /** + * Current connection state + */ + state: ConnectionState; + + /** + * Error message to display when state is "error" + */ + errorMessage?: string; + + /** + * Service name to display + */ + serviceName?: string; + + /** + * URL to display + */ + url?: string; + + /** + * Whether the URL is custom (will be indicated in the tooltip) + */ + isCustomUrl?: boolean; + + /** + * Whether to show detailed information + */ + showDetails?: boolean; + + /** + * Whether to show the URL + */ + showUrl?: boolean; + + /** + * Whether to show the reconnect button when disconnected or error + */ + showReconnectButton?: boolean; + + /** + * Callback when reconnect button is clicked + */ + onReconnect?: () => void | Promise; + + /** + * Custom class name + */ + class?: string; + + /** + * Custom class name (alias) + */ + className?: string; + + /** + * Custom style + */ + style?: any; + + /** + * Data theme + */ + dataTheme?: string; +} + +export const ConnectionStatus: Component = (props) => { + const [local, others] = splitProps(props, [ + "state", + "errorMessage", + "serviceName", + "url", + "isCustomUrl", + "showDetails", + "showUrl", + "showReconnectButton", + "onReconnect", + "class", + "className", + "style", + "dataTheme", + ]); + + const containerClasses = createMemo(() => + twMerge(local.class, local.className) + ); + + const getBadgeColor = createMemo((): ComponentColor => { + switch (local.state) { + case "connected": + return "success"; + case "connecting": + return "warning"; + case "error": + return "error"; + default: + return "neutral"; + } + }); + + const getStatusText = createMemo(() => { + switch (local.state) { + case "connected": + return "Connected"; + case "connecting": + return "Connecting..."; + case "error": + return local.errorMessage ? `Error: ${local.errorMessage}` : "Error"; + default: + return "Disconnected"; + } + }); + + const formatUrl = (url: string) => { + if (!url) return ""; + + try { + const urlObj = new URL(url); + return urlObj.hostname + (urlObj.port ? `:${urlObj.port}` : ""); + } catch { + return url; + } + }; + + const getTooltipText = createMemo(() => { + let tooltip = `Status: ${getStatusText()}`; + + if (local.url) { + tooltip += `\nURL: ${local.url}`; + + if (local.isCustomUrl) { + tooltip += " (Custom)"; + } + } + + if (local.serviceName) { + tooltip += `\nService: ${local.serviceName}`; + } + + return tooltip; + }); + + const handleReconnect = async () => { + if (local.onReconnect) { + await local.onReconnect(); + } + }; + + const shouldShowReconnectButton = createMemo( + () => + local.showReconnectButton && + (local.state === "disconnected" || local.state === "error") + ); + + const displayUrl = createMemo(() => (local.url ? formatUrl(local.url) : "")); + + return ( + + + + + + + {getStatusText()} + + + + {local.serviceName} + + + + + {displayUrl()} + + + + + + + {getStatusText()} + + + + + + + + + + ); +}; + +export default ConnectionStatus; diff --git a/src/components/connectionstatus/index.ts b/src/components/connectionstatus/index.ts new file mode 100644 index 0000000..13f1c3f --- /dev/null +++ b/src/components/connectionstatus/index.ts @@ -0,0 +1,5 @@ +export { default } from "./ConnectionStatus"; +export { + type ConnectionState, + type ConnectionStatusProps, +} from "./ConnectionStatus"; diff --git a/src/index.ts b/src/index.ts index 0c4a876..8af08f7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,6 +24,11 @@ export { CollapseTitle, Summary, } from "./components/collapse"; +export { default as ConnectionStatus } from "./components/connectionstatus"; +export type { + ConnectionState, + ConnectionStatusProps, +} from "./components/connectionstatus"; export { default as CopyButton } from "./components/copy-button"; export { default as Countdown } from "./components/countdown"; export { default as Diff } from "./components/diff"; @@ -122,3 +127,4 @@ export { default as WindowMockup, type WindowMockupProps, } from "./components/windowmockup"; +export { default } from "./components/connectionstatus"; \ No newline at end of file