TabNavbar.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
  2. import React, { useState } from "react"
  3. export const TAB_NAVBAR_HEIGHT = 24
  4. const BUTTON_MARGIN_RIGHT = "3px"
  5. const LAST_BUTTON_MARGIN_RIGHT = "13px"
  6. type TabNavbarProps = {
  7. onPlusClick: () => void
  8. onHistoryClick: () => void
  9. onSettingsClick: () => void
  10. }
  11. type TooltipProps = {
  12. text: string
  13. isVisible: boolean
  14. position: { x: number; y: number }
  15. align?: "left" | "center" | "right"
  16. }
  17. const Tooltip: React.FC<TooltipProps> = ({ text, isVisible, position, align = "center" }) => {
  18. let leftPosition = position.x
  19. let triangleStyle: React.CSSProperties = {
  20. left: "50%",
  21. marginLeft: "-5px",
  22. }
  23. if (align === "right") {
  24. leftPosition = position.x - 10 // Adjust this value as needed
  25. triangleStyle = {
  26. right: "10px", // Adjust this value to match the tooltip's right padding
  27. marginLeft: "0",
  28. }
  29. } else if (align === "left") {
  30. leftPosition = position.x + 10 // Adjust this value as needed
  31. triangleStyle = {
  32. left: "10px", // Adjust this value to match the tooltip's left padding
  33. marginLeft: "0",
  34. }
  35. }
  36. return (
  37. <div
  38. style={{
  39. position: "fixed",
  40. top: `${position.y}px`,
  41. left: align === "center" ? leftPosition + "px" : "auto",
  42. right: align === "right" ? "10px" : "auto", // Ensure 10px from screen edge
  43. transform: align === "center" ? "translateX(-50%)" : "none",
  44. opacity: isVisible ? 1 : 0,
  45. visibility: isVisible ? "visible" : "hidden",
  46. transition: "opacity 0.1s ease-out 0.1s, visibility 0.1s ease-out 0.1s",
  47. backgroundColor: "var(--vscode-editorHoverWidget-background)",
  48. color: "var(--vscode-editorHoverWidget-foreground)",
  49. padding: "4px 8px",
  50. borderRadius: "3px",
  51. fontSize: "12px",
  52. pointerEvents: "none",
  53. zIndex: 1000,
  54. boxShadow: "0 2px 8px var(--vscode-widget-shadow)",
  55. border: "1px solid var(--vscode-editorHoverWidget-border)",
  56. textAlign: "center",
  57. whiteSpace: "nowrap",
  58. }}>
  59. <div
  60. style={{
  61. position: "absolute",
  62. top: "-5px",
  63. ...triangleStyle,
  64. borderLeft: "5px solid transparent",
  65. borderRight: "5px solid transparent",
  66. borderBottom: "5px solid var(--vscode-editorHoverWidget-border)",
  67. }}
  68. />
  69. <div
  70. style={{
  71. position: "absolute",
  72. top: "-4px",
  73. ...triangleStyle,
  74. borderLeft: "5px solid transparent",
  75. borderRight: "5px solid transparent",
  76. borderBottom: "5px solid var(--vscode-editorHoverWidget-background)",
  77. }}
  78. />
  79. {text}
  80. </div>
  81. )
  82. }
  83. const TabNavbar = ({ onPlusClick, onHistoryClick, onSettingsClick }: TabNavbarProps) => {
  84. const [tooltip, setTooltip] = useState<TooltipProps>({
  85. text: "",
  86. isVisible: false,
  87. position: { x: 0, y: 0 },
  88. align: "center",
  89. })
  90. const showTooltip = (text: string, event: React.MouseEvent, align: "left" | "center" | "right" = "center") => {
  91. const rect = event.currentTarget.getBoundingClientRect()
  92. setTooltip({
  93. text,
  94. isVisible: true,
  95. position: { x: rect.left + rect.width / 2, y: rect.bottom + 7 },
  96. align,
  97. })
  98. }
  99. const hideTooltip = () => {
  100. setTooltip((prev) => ({ ...prev, isVisible: false }))
  101. }
  102. const buttonStyle = {
  103. marginRight: BUTTON_MARGIN_RIGHT,
  104. }
  105. const lastButtonStyle = {
  106. ...buttonStyle,
  107. marginRight: LAST_BUTTON_MARGIN_RIGHT,
  108. }
  109. return (
  110. <>
  111. <div
  112. style={{
  113. position: "absolute",
  114. top: 4,
  115. right: 0,
  116. left: 0,
  117. height: TAB_NAVBAR_HEIGHT,
  118. display: "flex",
  119. justifyContent: "flex-end",
  120. alignItems: "center",
  121. }}>
  122. <VSCodeButton
  123. appearance="icon"
  124. onClick={onPlusClick}
  125. style={buttonStyle}
  126. onMouseEnter={(e) => showTooltip("New Chat", e, "center")}
  127. onMouseLeave={hideTooltip}
  128. onMouseMove={(e) => showTooltip("New Chat", e, "center")}>
  129. <span className="codicon codicon-add"></span>
  130. </VSCodeButton>
  131. <VSCodeButton
  132. appearance="icon"
  133. onClick={onHistoryClick}
  134. style={buttonStyle}
  135. onMouseEnter={(e) => showTooltip("History", e, "center")}
  136. onMouseLeave={hideTooltip}
  137. onMouseMove={(e) => showTooltip("History", e, "center")}>
  138. <span className="codicon codicon-history"></span>
  139. </VSCodeButton>
  140. <VSCodeButton
  141. appearance="icon"
  142. onClick={onSettingsClick}
  143. style={lastButtonStyle}
  144. onMouseEnter={(e) => showTooltip("Settings", e, "right")}
  145. onMouseLeave={hideTooltip}
  146. onMouseMove={(e) => showTooltip("Settings", e, "right")}>
  147. <span className="codicon codicon-settings-gear"></span>
  148. </VSCodeButton>
  149. </div>
  150. <Tooltip {...tooltip} />
  151. </>
  152. )
  153. }
  154. export default TabNavbar