diff --git a/assets/stylesheets/App.css b/assets/stylesheets/App.css
index 8591ab5f..ef43de58 100644
--- a/assets/stylesheets/App.css
+++ b/assets/stylesheets/App.css
@@ -357,8 +357,83 @@ code {
padding: 0 !important;
}
-.ant-popover-inner:has(.keyboard-shortcut-tooltip) {
- padding: 8px !important;
+:root,
+.light-mode,
+html:has(.light-mode) {
+ --kbd-color: #363636;
+ --kbd-bg: #efefef;
+ --kbd-inset: #e8e8e8;
+ --kbd-edge: #c3c3c3;
+ --kbd-ridge: #c9c9c9;
+ --kbd-drop-shadow: #333333;
+ --kbd-text-shadow: #f6f6f6;
+}
+
+.dark-mode,
+html:has(.dark-mode) {
+ --kbd-color: #ececec;
+ --kbd-bg: #3a3a3a;
+ --kbd-inset: #323232;
+ --kbd-edge: #1c1c1c;
+ --kbd-ridge: #141414;
+ --kbd-drop-shadow: #000000;
+ --kbd-text-shadow: #111111;
+}
+
+.keyboard-key {
+ display: inline-block;
+ color: var(--kbd-color);
+ text-decoration: none;
+ text-align: center;
+ background: var(--kbd-bg);
+ padding: 3px 7px;
+ margin: 5px 3px;
+ border-radius: 4px;
+ box-shadow:
+ inset 0 0 25px var(--kbd-inset),
+ 0 1px 0 var(--kbd-edge),
+ 0 2px 0 var(--kbd-ridge),
+ 0 2px 3px var(--kbd-drop-shadow);
+ text-shadow: 0 1px 0 var(--kbd-text-shadow);
+}
+
+.keyboard-key-md {
+ padding: 4.5px 10.5px;
+ margin: 7.5px 3.5px;
+ font-size: 110%;
+ border-radius: 6px;
+ box-shadow:
+ inset 0 0 37.5px var(--kbd-inset),
+ 0 1.5px 0 var(--kbd-edge),
+ 0 3px 0 var(--kbd-ridge),
+ 0 3px 4.5px var(--kbd-drop-shadow);
+ text-shadow: 0 1.5px 0 var(--kbd-text-shadow);
+}
+
+.keyboard-key-lg {
+ padding: 6px 14px;
+ margin: 10px 6px;
+ font-size: 200%;
+ border-radius: 8px;
+ box-shadow:
+ inset 0 0 50px var(--kbd-inset),
+ 0 2px 0 var(--kbd-edge),
+ 0 4px 0 var(--kbd-ridge),
+ 0 4px 6px var(--kbd-drop-shadow);
+ text-shadow: 0 2px 0 var(--kbd-text-shadow);
+}
+
+.keyboard-key-xl {
+ padding: 9px 21px;
+ margin: 15px 9px;
+ font-size: 300%;
+ border-radius: 12px;
+ box-shadow:
+ inset 0 0 75px var(--kbd-inset),
+ 0 3px 0 var(--kbd-edge),
+ 0 6px 0 var(--kbd-ridge),
+ 0 6px 9px var(--kbd-drop-shadow);
+ text-shadow: 0 3px 0 var(--kbd-text-shadow);
}
.cursor-tooltip {
diff --git a/src/components/Dashboard/common/CursorTooltip.jsx b/src/components/Dashboard/common/CursorTooltip.jsx
index 70fb736c..5fa760e7 100644
--- a/src/components/Dashboard/common/CursorTooltip.jsx
+++ b/src/components/Dashboard/common/CursorTooltip.jsx
@@ -15,17 +15,19 @@ const getTooltipRoot = () => {
return root
}
-const CursorTooltip = ({ content, visible, pointRef }) => {
+const CursorTooltip = ({ content, visible, pointRef, hideBorder = false }) => {
const tooltipRef = useRef(null)
const sizeRef = useRef({ width: 0, height: 0 })
const frameRef = useRef(null)
const contentRef = useRef(content)
const lastContentRef = useRef(content)
+ const lastHideBorderRef = useRef(hideBorder)
const [root, setRoot] = useState(null)
contentRef.current = content
if (content != null && content !== false && content !== '') {
lastContentRef.current = content
+ lastHideBorderRef.current = hideBorder
}
const applyPosition = useCallback(() => {
@@ -96,10 +98,28 @@ const CursorTooltip = ({ content, visible, pointRef }) => {
if (!root) return null
+ const tooltipContent = lastHideBorderRef.current ? (
+ lastContentRef.current
+ ) : (
+
+ {lastContentRef.current}
+
+ )
+
return createPortal(
{
willChange: 'transform, opacity'
}}
>
-
- {lastContentRef.current}
-
+ {tooltipContent}
,
root
)
@@ -128,6 +138,7 @@ const CursorTooltip = ({ content, visible, pointRef }) => {
CursorTooltip.propTypes = {
content: PropTypes.node,
visible: PropTypes.bool,
+ hideBorder: PropTypes.bool,
pointRef: PropTypes.shape({
current: PropTypes.shape({
x: PropTypes.number,
diff --git a/src/components/Dashboard/common/DashboardSidebar.jsx b/src/components/Dashboard/common/DashboardSidebar.jsx
index b88c9b32..46ed81a5 100644
--- a/src/components/Dashboard/common/DashboardSidebar.jsx
+++ b/src/components/Dashboard/common/DashboardSidebar.jsx
@@ -19,6 +19,7 @@ import SimpleBar from 'simplebar-react'
import { useThemeContext } from '../context/ThemeContext'
import { filterSidebarItemsByListPermission } from '../../../database/Sidebars'
import Tooltip from './Tooltip'
+import KeyboardShortcut from './KeyboardShortcut'
const { Sider } = Layout
const CollapsedItemIcon = ({ className, icon, title }) => {
@@ -158,13 +159,21 @@ const DashboardSidebar = ({
- : }
- style={{ flexGrow: 1, width: '100%' }}
- onClick={() => handleCollapse(!collapsed)}
- />
+ handleCollapse(!collapsed)}
+ >
+ :
+ }
+ style={{ flexGrow: 1, width: '100%' }}
+ onClick={() => handleCollapse(!collapsed)}
+ />
+
diff --git a/src/components/Dashboard/common/KeyboardKey.jsx b/src/components/Dashboard/common/KeyboardKey.jsx
new file mode 100644
index 00000000..41e4851d
--- /dev/null
+++ b/src/components/Dashboard/common/KeyboardKey.jsx
@@ -0,0 +1,29 @@
+import PropTypes from 'prop-types'
+
+const SIZE_CLASS = {
+ sm: '',
+ md: 'keyboard-key-md',
+ lg: 'keyboard-key-lg',
+ xl: 'keyboard-key-xl'
+}
+
+const KeyboardKey = ({ children, size = 'sm', className }) => {
+ const sizeClass = SIZE_CLASS[size] ?? ''
+ return (
+
+ {children}
+
+ )
+}
+
+KeyboardKey.propTypes = {
+ children: PropTypes.node.isRequired,
+ size: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
+ className: PropTypes.string
+}
+
+export default KeyboardKey
diff --git a/src/components/Dashboard/common/KeyboardShortcut.jsx b/src/components/Dashboard/common/KeyboardShortcut.jsx
index 182bf36e..c371541e 100644
--- a/src/components/Dashboard/common/KeyboardShortcut.jsx
+++ b/src/components/Dashboard/common/KeyboardShortcut.jsx
@@ -1,8 +1,9 @@
import { useEffect, useRef, cloneElement, useMemo } from 'react'
import PropTypes from 'prop-types'
-import { Popover, Typography } from 'antd'
import loglevel from 'loglevel'
import config from '../../../config'
+import Tooltip from './Tooltip'
+import KeyboardKey from './KeyboardKey'
const logger = loglevel.getLogger('ApiServerContext')
logger.setLevel(config.logLevel)
@@ -42,8 +43,6 @@ function getPressedKey(event) {
return null
}
-const { Text } = Typography
-
const KeyboardShortcut = ({
shortcut,
children,
@@ -98,17 +97,15 @@ const KeyboardShortcut = ({
const element = cloneElement(children, { ref: childRef })
if (hint) {
+ var osSpecificHint = hint.replaceAll('ALT', '⌥')
+
return (
-
- {hint}
-
- }
- arrow={false}
+ {osSpecificHint}}
>
{element}
-
+
)
}
return element
diff --git a/src/components/Dashboard/common/Tooltip.jsx b/src/components/Dashboard/common/Tooltip.jsx
index e435d3ce..da126863 100644
--- a/src/components/Dashboard/common/Tooltip.jsx
+++ b/src/components/Dashboard/common/Tooltip.jsx
@@ -1,10 +1,4 @@
-import {
- cloneElement,
- isValidElement,
- useEffect,
- useId,
- useRef
-} from 'react'
+import { cloneElement, isValidElement, useEffect, useId, useRef } from 'react'
import PropTypes from 'prop-types'
import { useTooltipContext } from '../context/TooltipContext'
@@ -13,7 +7,13 @@ const mergeHandler = (original, next) => (event) => {
original?.(event)
}
-const Tooltip = ({ children, title, content, listenParents = 0 }) => {
+const Tooltip = ({
+ children,
+ title,
+ content,
+ listenParents = 0,
+ hideBorder = false
+}) => {
const { showTooltip, hideTooltip } = useTooltipContext()
const id = useId()
const tooltipContent = title ?? content
@@ -21,7 +21,9 @@ const Tooltip = ({ children, title, content, listenParents = 0 }) => {
const hoveredTargetsRef = useRef(new Set())
const hoveringRef = useRef(false)
const tooltipContentRef = useRef(tooltipContent)
+ const hideBorderRef = useRef(hideBorder)
tooltipContentRef.current = tooltipContent
+ hideBorderRef.current = hideBorder
useEffect(() => {
return () => hideTooltip(id)
@@ -29,14 +31,20 @@ const Tooltip = ({ children, title, content, listenParents = 0 }) => {
useEffect(() => {
if (hoveringRef.current) {
- showTooltip(id, tooltipContent)
+ showTooltip(id, tooltipContent, undefined, undefined, hideBorder)
}
- }, [id, showTooltip, tooltipContent])
+ }, [id, showTooltip, tooltipContent, hideBorder])
const onMouseEnter = (event) => {
hoveredTargetsRef.current.add(event.currentTarget)
hoveringRef.current = true
- showTooltip(id, tooltipContentRef.current, event.clientX, event.clientY)
+ showTooltip(
+ id,
+ tooltipContentRef.current,
+ event.clientX,
+ event.clientY,
+ hideBorderRef.current
+ )
}
const onMouseLeave = (event) => {
@@ -82,11 +90,7 @@ const Tooltip = ({ children, title, content, listenParents = 0 }) => {
}, [listenParents])
const wrapWithSpan = (node) => (
-
+
{node}
)
@@ -115,7 +119,8 @@ Tooltip.propTypes = {
children: PropTypes.node.isRequired,
title: PropTypes.node,
content: PropTypes.node,
- listenParents: PropTypes.number
+ listenParents: PropTypes.number,
+ hideBorder: PropTypes.bool
}
export default Tooltip
diff --git a/src/components/Dashboard/context/TooltipContext.jsx b/src/components/Dashboard/context/TooltipContext.jsx
index 7f4ea8ee..19e9c344 100644
--- a/src/components/Dashboard/context/TooltipContext.jsx
+++ b/src/components/Dashboard/context/TooltipContext.jsx
@@ -17,6 +17,7 @@ const FADE_OUT_MS = 250
export const TooltipProvider = ({ children }) => {
const [content, setContent] = useState(null)
const [visible, setVisible] = useState(false)
+ const [hideBorder, setHideBorder] = useState(false)
const stackRef = useRef([])
const hideTimerRef = useRef(null)
const fadeTimerRef = useRef(null)
@@ -46,7 +47,7 @@ export const TooltipProvider = ({ children }) => {
}, [])
const showTooltip = useCallback(
- (id, nextContent, x, y) => {
+ (id, nextContent, x, y, nextHideBorder = false) => {
if (nextContent == null || nextContent === false || nextContent === '') {
return
}
@@ -57,11 +58,13 @@ export const TooltipProvider = ({ children }) => {
clearTimers()
+ const hideBorderValue = Boolean(nextHideBorder)
stackRef.current = [
...stackRef.current.filter((entry) => entry.id !== id),
- { id, content: nextContent }
+ { id, content: nextContent, hideBorder: hideBorderValue }
]
setContent(nextContent)
+ setHideBorder(hideBorderValue)
if (!visibleRef.current) {
window.requestAnimationFrame(() => setVisible(true))
@@ -81,6 +84,7 @@ export const TooltipProvider = ({ children }) => {
if (last) {
setContent(last.content)
+ setHideBorder(Boolean(last.hideBorder))
setVisible(true)
return
}
@@ -100,7 +104,12 @@ export const TooltipProvider = ({ children }) => {
return (
{children}
-
+
)
}