Compare commits
No commits in common. "e1fbd6070ab567f766b63181b569d72cb8037760" and "2ed961b9ec4941a415720f09c0392e6af81807b2" have entirely different histories.
e1fbd6070a
...
2ed961b9ec
@ -357,83 +357,8 @@ code {
|
||||
padding: 0 !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);
|
||||
.ant-popover-inner:has(.keyboard-shortcut-tooltip) {
|
||||
padding: 8px !important;
|
||||
}
|
||||
|
||||
.cursor-tooltip {
|
||||
@ -507,9 +432,6 @@ body {
|
||||
min-width: 0 !important;
|
||||
max-width: 100% !important;
|
||||
flex: 0 0 100% !important;
|
||||
transition:
|
||||
all 0.3s,
|
||||
background 0s;
|
||||
}
|
||||
|
||||
.dashboard-sider.ant-layout-sider-collapsed {
|
||||
@ -1100,11 +1022,11 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
|
||||
.farmcontrol-splitter.ant-splitter-horizontal.is-size-transitioning
|
||||
.ant-splitter-panel {
|
||||
transition:
|
||||
--dashboard-splitter-sidebar-size 0.3s ease-in-out,
|
||||
flex-basis 0.3s ease-in-out,
|
||||
width 0.3s ease-in-out,
|
||||
min-width 0.3s ease-in-out,
|
||||
max-width 0.3s ease-in-out;
|
||||
--dashboard-splitter-sidebar-size 0.15s ease-in-out,
|
||||
flex-basis 0.15s ease-in-out,
|
||||
width 0.15s ease-in-out,
|
||||
min-width 0.15s ease-in-out,
|
||||
max-width 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
@property --dashboard-splitter-sidebar-size {
|
||||
|
||||
@ -1,102 +0,0 @@
|
||||
/**
|
||||
* G-code command descriptions for hover tooltips.
|
||||
* Adapted from gcode-lang-codemirror (MIT):
|
||||
* https://github.com/oneislandearth/gcode-lang-codemirror
|
||||
*/
|
||||
export const GCodeCommands = {
|
||||
G0: 'Rapid movement',
|
||||
G1: 'Linear movement',
|
||||
G2: 'Clockwise arc movement',
|
||||
G3: 'Counter-clockwise arc movement',
|
||||
G4: 'Dwell (wait P milliseconds or S seconds)',
|
||||
G10: 'Retract (firmware retraction)',
|
||||
G11: 'Recover (firmware retraction)',
|
||||
G20: 'Set units to inches',
|
||||
G21: 'Set units to millimeters',
|
||||
G28: 'Home axes',
|
||||
G29: 'Automatic bed leveling',
|
||||
G80: 'Mesh bed leveling (Prusa) / cancel canned cycle',
|
||||
G90: 'Use absolute positioning',
|
||||
G91: 'Use relative positioning',
|
||||
G92: 'Set current position',
|
||||
M0: 'Stop after the buffer is empty',
|
||||
M17: 'Enable stepper motors',
|
||||
M18: 'Disable stepper motors',
|
||||
M20: 'List SD card files',
|
||||
M21: 'Initialize (mount) SD card',
|
||||
M22: 'Release (unmount) SD card',
|
||||
M23: 'Select SD file for printing',
|
||||
M24: 'Start / resume SD print',
|
||||
M25: 'Pause SD print',
|
||||
M26: 'Set SD position in bytes',
|
||||
M27: 'Report SD print status',
|
||||
M28: 'Start writing to SD card',
|
||||
M29: 'Stop writing to SD card',
|
||||
M40: 'Eject part',
|
||||
M42: 'Set pin state / stop if out of material',
|
||||
M73: 'Set print progress',
|
||||
M80: 'Turn ATX power on',
|
||||
M81: 'Turn ATX power off',
|
||||
M82: 'Extruder absolute mode',
|
||||
M83: 'Extruder relative mode',
|
||||
M84: 'Disable idle hold / steppers',
|
||||
M92: 'Set steps per unit',
|
||||
M104: 'Set extruder temperature',
|
||||
M105: 'Get temperatures',
|
||||
M106: 'Set fan speed',
|
||||
M107: 'Turn fan off',
|
||||
M109: 'Set extruder temperature and wait',
|
||||
M110: 'Set current line number',
|
||||
M112: 'Emergency stop',
|
||||
M114: 'Get current position',
|
||||
M115: 'Get firmware version and capabilities',
|
||||
M117: 'Set LCD / status message',
|
||||
M119: 'Get endstop status',
|
||||
M140: 'Set bed temperature',
|
||||
M141: 'Set chamber temperature',
|
||||
M190: 'Set bed temperature and wait',
|
||||
M191: 'Set chamber temperature and wait',
|
||||
M220: 'Set feedrate percentage',
|
||||
M221: 'Set flow percentage',
|
||||
M300: 'Beep (S Hz for P ms)',
|
||||
M600: 'Filament change',
|
||||
M601: 'Pause print (Prusa)',
|
||||
M862: 'G-code compatibility check (Prusa)',
|
||||
M900: 'Linear / pressure advance (K)',
|
||||
T0: 'Select tool / extruder 0',
|
||||
T1: 'Select tool / extruder 1',
|
||||
X: 'X axis',
|
||||
Y: 'Y axis',
|
||||
Z: 'Z axis',
|
||||
E: 'Extruder axis',
|
||||
A: 'A axis',
|
||||
B: 'B axis',
|
||||
C: 'C axis',
|
||||
F: 'Feedrate',
|
||||
S: 'Speed, temperature, or value',
|
||||
P: 'Parameter / time',
|
||||
I: 'Arc X offset / parameter',
|
||||
J: 'Arc Y offset / parameter',
|
||||
K: 'Arc Z offset / linear advance',
|
||||
R: 'Arc radius / RPM'
|
||||
}
|
||||
|
||||
export function lookupGCodeCommand(word) {
|
||||
const upper = String(word || '').toUpperCase()
|
||||
const commandMatch = upper.match(/^([GMT])0*(\d+)(\.\d+)?/)
|
||||
if (commandMatch) {
|
||||
const base = commandMatch[1] + String(parseInt(commandMatch[2], 10))
|
||||
const canonical = base + (commandMatch[3] || '')
|
||||
return (
|
||||
GCodeCommands[canonical] ||
|
||||
GCodeCommands[base] ||
|
||||
GCodeCommands[upper] ||
|
||||
null
|
||||
)
|
||||
}
|
||||
const axis = upper.charAt(0)
|
||||
if (axis && GCodeCommands[axis]) {
|
||||
return GCodeCommands[axis]
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -1,109 +0,0 @@
|
||||
import {
|
||||
StreamLanguage,
|
||||
LanguageSupport
|
||||
} from '@codemirror/language'
|
||||
import { EditorView, hoverTooltip } from '@codemirror/view'
|
||||
import { lookupGCodeCommand } from './commands.js'
|
||||
|
||||
/**
|
||||
* G-code language support for CodeMirror 6.
|
||||
* Highlighting and command tooltips adapted from gcode-lang-codemirror:
|
||||
* https://github.com/oneislandearth/gcode-lang-codemirror
|
||||
*
|
||||
* Implemented as a StreamLanguage so typical 3D-printer G-code (no `%`
|
||||
* wrappers, E axis, slicer `{placeholders}` / `[placeholders]`) highlights
|
||||
* without the CodeMirror 0.19 dependencies of the original package.
|
||||
*/
|
||||
const wordChar = /[A-Za-z0-9.]/
|
||||
|
||||
function gcodeToken(stream) {
|
||||
if (stream.eatSpace()) return null
|
||||
|
||||
if (stream.eat(';')) {
|
||||
stream.skipToEnd()
|
||||
return 'comment'
|
||||
}
|
||||
|
||||
if (stream.eat('(')) {
|
||||
if (!stream.skipTo(')')) stream.skipToEnd()
|
||||
else stream.eat(')')
|
||||
return 'comment'
|
||||
}
|
||||
|
||||
if (stream.eat('{')) {
|
||||
if (!stream.skipTo('}')) stream.skipToEnd()
|
||||
else stream.eat('}')
|
||||
return 'processingInstruction'
|
||||
}
|
||||
|
||||
if (stream.eat('[')) {
|
||||
if (!stream.skipTo(']')) stream.skipToEnd()
|
||||
else stream.eat(']')
|
||||
return 'processingInstruction'
|
||||
}
|
||||
|
||||
if (stream.match(/^[GgMmTt]\d+(\.\d+)?/)) return 'keyword'
|
||||
if (stream.match(/^[Nn]\d+/)) return 'meta'
|
||||
if (stream.match(/^\*\d+/)) return 'meta'
|
||||
if (stream.eat('%')) return 'meta'
|
||||
|
||||
if (stream.match(/^[A-Za-z]/)) return 'strong'
|
||||
if (stream.match(/^[+-]?(\d+\.?\d*|\.\d+)/)) return 'number'
|
||||
|
||||
stream.next()
|
||||
return null
|
||||
}
|
||||
|
||||
export const gcodeLanguage = StreamLanguage.define({
|
||||
name: 'gcode',
|
||||
token: gcodeToken,
|
||||
languageData: {
|
||||
commentTokens: { line: ';', block: { open: '(', close: ')' } }
|
||||
}
|
||||
})
|
||||
|
||||
export const gcodeCommandTooltips = hoverTooltip((view, pos, side) => {
|
||||
const line = view.state.doc.lineAt(pos)
|
||||
let start = pos
|
||||
let end = pos
|
||||
const charAt = (offset) => line.text.charAt(offset - line.from)
|
||||
|
||||
while (start > line.from && wordChar.test(charAt(start - 1))) start--
|
||||
while (end < line.to && wordChar.test(charAt(end))) end++
|
||||
if ((start === pos && side < 0) || (end === pos && side > 0)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const word = line.text.slice(start - line.from, end - line.from)
|
||||
const description = lookupGCodeCommand(word)
|
||||
if (!description) return null
|
||||
|
||||
return {
|
||||
pos: start,
|
||||
end,
|
||||
above: true,
|
||||
create() {
|
||||
const dom = document.createElement('div')
|
||||
dom.className = 'cm-tooltip-gcode'
|
||||
dom.textContent = description
|
||||
return { dom }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const gcodeTooltipTheme = EditorView.theme({
|
||||
'.cm-tooltip-gcode': {
|
||||
padding: '4px 8px',
|
||||
fontSize: '12px'
|
||||
}
|
||||
})
|
||||
|
||||
export function gcodeLang() {
|
||||
return new LanguageSupport(gcodeLanguage, [
|
||||
gcodeCommandTooltips,
|
||||
gcodeTooltipTheme
|
||||
])
|
||||
}
|
||||
|
||||
export { gcodeLang as GCodeLanguage }
|
||||
export { GCodeCommands, lookupGCodeCommand } from './commands.js'
|
||||
@ -15,19 +15,17 @@ const getTooltipRoot = () => {
|
||||
return root
|
||||
}
|
||||
|
||||
const CursorTooltip = ({ content, visible, pointRef, hideBorder = false }) => {
|
||||
const CursorTooltip = ({ content, visible, pointRef }) => {
|
||||
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(() => {
|
||||
@ -98,9 +96,19 @@ const CursorTooltip = ({ content, visible, pointRef, hideBorder = false }) => {
|
||||
|
||||
if (!root) return null
|
||||
|
||||
const tooltipContent = lastHideBorderRef.current ? (
|
||||
lastContentRef.current
|
||||
) : (
|
||||
return createPortal(
|
||||
<div
|
||||
ref={tooltipRef}
|
||||
className={`cursor-tooltip${visible ? ' is-visible' : ''}`}
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 1100,
|
||||
pointerEvents: 'none',
|
||||
willChange: 'transform, opacity'
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
size='small'
|
||||
styles={{ body: { padding: '4px 10px' } }}
|
||||
@ -112,24 +120,6 @@ const CursorTooltip = ({ content, visible, pointRef, hideBorder = false }) => {
|
||||
>
|
||||
{lastContentRef.current}
|
||||
</Card>
|
||||
)
|
||||
|
||||
return createPortal(
|
||||
<div
|
||||
ref={tooltipRef}
|
||||
className={`cursor-tooltip${visible ? ' is-visible' : ''}${
|
||||
lastHideBorderRef.current ? ' hide-border' : ''
|
||||
}`}
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 1100,
|
||||
pointerEvents: 'none',
|
||||
willChange: 'transform, opacity'
|
||||
}}
|
||||
>
|
||||
{tooltipContent}
|
||||
</div>,
|
||||
root
|
||||
)
|
||||
@ -138,7 +128,6 @@ const CursorTooltip = ({ content, visible, pointRef, hideBorder = false }) => {
|
||||
CursorTooltip.propTypes = {
|
||||
content: PropTypes.node,
|
||||
visible: PropTypes.bool,
|
||||
hideBorder: PropTypes.bool,
|
||||
pointRef: PropTypes.shape({
|
||||
current: PropTypes.shape({
|
||||
x: PropTypes.number,
|
||||
|
||||
@ -19,7 +19,6 @@ 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 }) => {
|
||||
@ -76,19 +75,17 @@ const DashboardSidebar = ({
|
||||
}
|
||||
|
||||
// Recursive function to map items and their children
|
||||
const mapItemsRecursively = (items, showCollapsedTooltip = true) => {
|
||||
const mapItemsRecursively = (items) => {
|
||||
return items.map((item) => {
|
||||
if (item?.type === 'divider') {
|
||||
return item
|
||||
}
|
||||
|
||||
console.log(item)
|
||||
|
||||
const icon = item.icon || getSidebarIconNode(item.iconKey)
|
||||
const mappedItem = {
|
||||
key: item.key,
|
||||
icon:
|
||||
collapsed && !isMobile && showCollapsedTooltip && !item.children ? (
|
||||
collapsed && !isMobile ? (
|
||||
<CollapsedItemIcon title={item.label} icon={icon} />
|
||||
) : (
|
||||
icon
|
||||
@ -103,7 +100,7 @@ const DashboardSidebar = ({
|
||||
|
||||
// Recursively map children if they exist
|
||||
if (item?.children && Array.isArray(item.children)) {
|
||||
mappedItem.children = mapItemsRecursively(item.children, false)
|
||||
mappedItem.children = mapItemsRecursively(item.children)
|
||||
}
|
||||
|
||||
return mappedItem
|
||||
@ -159,21 +156,13 @@ const DashboardSidebar = ({
|
||||
<Flex vertical style={{ width: '100%' }}>
|
||||
<Divider style={{ margin: 0 }} />
|
||||
<Flex style={{ padding: '4px', width: '100%' }}>
|
||||
<KeyboardShortcut
|
||||
shortcut='alt+shift+s'
|
||||
hint='ALT ⇧ S'
|
||||
onTrigger={() => handleCollapse(!collapsed)}
|
||||
>
|
||||
<Button
|
||||
size={isElectron ? 'middle' : 'large'}
|
||||
type='text'
|
||||
icon={
|
||||
collapsed ? <ExpandSidebarIcon /> : <CollapseSidebarIcon />
|
||||
}
|
||||
icon={collapsed ? <ExpandSidebarIcon /> : <CollapseSidebarIcon />}
|
||||
style={{ flexGrow: 1, width: '100%' }}
|
||||
onClick={() => handleCollapse(!collapsed)}
|
||||
/>
|
||||
</KeyboardShortcut>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
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 (
|
||||
<kbd
|
||||
className={['keyboard-key', sizeClass, className]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
{children}
|
||||
</kbd>
|
||||
)
|
||||
}
|
||||
|
||||
KeyboardKey.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
size: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
|
||||
className: PropTypes.string
|
||||
}
|
||||
|
||||
export default KeyboardKey
|
||||
@ -1,9 +1,8 @@
|
||||
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)
|
||||
|
||||
@ -43,6 +42,8 @@ function getPressedKey(event) {
|
||||
return null
|
||||
}
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
const KeyboardShortcut = ({
|
||||
shortcut,
|
||||
children,
|
||||
@ -97,15 +98,17 @@ const KeyboardShortcut = ({
|
||||
const element = cloneElement(children, { ref: childRef })
|
||||
|
||||
if (hint) {
|
||||
var osSpecificHint = hint.replaceAll('ALT', '⌥')
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
hideBorder
|
||||
title={<KeyboardKey size='md'>{osSpecificHint}</KeyboardKey>}
|
||||
<Popover
|
||||
content={
|
||||
<Text keyboard className='keyboard-shortcut-tooltip'>
|
||||
{hint}
|
||||
</Text>
|
||||
}
|
||||
arrow={false}
|
||||
>
|
||||
{element}
|
||||
</Tooltip>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
return element
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
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'
|
||||
|
||||
@ -7,13 +13,7 @@ const mergeHandler = (original, next) => (event) => {
|
||||
original?.(event)
|
||||
}
|
||||
|
||||
const Tooltip = ({
|
||||
children,
|
||||
title,
|
||||
content,
|
||||
listenParents = 0,
|
||||
hideBorder = false
|
||||
}) => {
|
||||
const Tooltip = ({ children, title, content, listenParents = 0 }) => {
|
||||
const { showTooltip, hideTooltip } = useTooltipContext()
|
||||
const id = useId()
|
||||
const tooltipContent = title ?? content
|
||||
@ -21,9 +21,7 @@ const Tooltip = ({
|
||||
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)
|
||||
@ -31,20 +29,14 @@ const Tooltip = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (hoveringRef.current) {
|
||||
showTooltip(id, tooltipContent, undefined, undefined, hideBorder)
|
||||
showTooltip(id, tooltipContent)
|
||||
}
|
||||
}, [id, showTooltip, tooltipContent, hideBorder])
|
||||
}, [id, showTooltip, tooltipContent])
|
||||
|
||||
const onMouseEnter = (event) => {
|
||||
hoveredTargetsRef.current.add(event.currentTarget)
|
||||
hoveringRef.current = true
|
||||
showTooltip(
|
||||
id,
|
||||
tooltipContentRef.current,
|
||||
event.clientX,
|
||||
event.clientY,
|
||||
hideBorderRef.current
|
||||
)
|
||||
showTooltip(id, tooltipContentRef.current, event.clientX, event.clientY)
|
||||
}
|
||||
|
||||
const onMouseLeave = (event) => {
|
||||
@ -90,7 +82,11 @@ const Tooltip = ({
|
||||
}, [listenParents])
|
||||
|
||||
const wrapWithSpan = (node) => (
|
||||
<span ref={spanRef} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
||||
<span
|
||||
ref={spanRef}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
{node}
|
||||
</span>
|
||||
)
|
||||
@ -119,8 +115,7 @@ Tooltip.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
title: PropTypes.node,
|
||||
content: PropTypes.node,
|
||||
listenParents: PropTypes.number,
|
||||
hideBorder: PropTypes.bool
|
||||
listenParents: PropTypes.number
|
||||
}
|
||||
|
||||
export default Tooltip
|
||||
|
||||
@ -13,7 +13,6 @@ import { php } from '@codemirror/lang-php'
|
||||
import { yaml } from '@codemirror/lang-yaml'
|
||||
import { xml } from '@codemirror/lang-xml'
|
||||
import { fcTemplateLang } from '../../../codemirror/fcTemplateLang'
|
||||
import { gcodeLang } from '../../../codemirror/gcodeLang'
|
||||
|
||||
export function toEditorCode(code, language = 'javascript') {
|
||||
if (code == null) return ''
|
||||
@ -68,10 +67,6 @@ export function getCodeLanguageExtension(
|
||||
case 'yaml':
|
||||
case 'yml':
|
||||
return yaml()
|
||||
case 'gcode':
|
||||
case 'g-code':
|
||||
case 'g':
|
||||
return gcodeLang()
|
||||
default:
|
||||
return javascriptLang({ autoCompleteObject })
|
||||
}
|
||||
|
||||
@ -3,8 +3,7 @@ import {
|
||||
useState,
|
||||
useContext,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef
|
||||
useEffect
|
||||
} from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { notification, Drawer } from 'antd'
|
||||
@ -60,13 +59,6 @@ const NotificationProvider = ({ children }) => {
|
||||
}
|
||||
}, [authenticated, fetchNotificationsApi, showError])
|
||||
|
||||
const fetchNotificationsRef = useRef(fetchNotifications)
|
||||
const authenticatedRef = useRef(authenticated)
|
||||
const connectedRef = useRef(connected)
|
||||
fetchNotificationsRef.current = fetchNotifications
|
||||
authenticatedRef.current = authenticated
|
||||
connectedRef.current = connected
|
||||
|
||||
const markNotificationAsRead = useCallback(
|
||||
async (notificationId) => {
|
||||
try {
|
||||
@ -124,15 +116,14 @@ const NotificationProvider = ({ children }) => {
|
||||
// Initial load / when we become authenticated and connected
|
||||
useEffect(() => {
|
||||
if (!authenticated || !connected) return
|
||||
fetchNotificationsRef.current()
|
||||
}, [authenticated, connected])
|
||||
fetchNotifications()
|
||||
}, [authenticated, connected, fetchNotifications])
|
||||
|
||||
// Refresh when the notification center opens
|
||||
useEffect(() => {
|
||||
if (!notificationCenterVisible) return
|
||||
if (!authenticatedRef.current || !connectedRef.current) return
|
||||
fetchNotificationsRef.current()
|
||||
}, [notificationCenterVisible])
|
||||
if (!notificationCenterVisible || !authenticated || !connected) return
|
||||
fetchNotifications()
|
||||
}, [notificationCenterVisible, authenticated, connected, fetchNotifications])
|
||||
|
||||
useEffect(() => {
|
||||
setNotificationCenterVisible(false)
|
||||
|
||||
@ -17,7 +17,6 @@ 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)
|
||||
@ -47,7 +46,7 @@ export const TooltipProvider = ({ children }) => {
|
||||
}, [])
|
||||
|
||||
const showTooltip = useCallback(
|
||||
(id, nextContent, x, y, nextHideBorder = false) => {
|
||||
(id, nextContent, x, y) => {
|
||||
if (nextContent == null || nextContent === false || nextContent === '') {
|
||||
return
|
||||
}
|
||||
@ -58,13 +57,11 @@ export const TooltipProvider = ({ children }) => {
|
||||
|
||||
clearTimers()
|
||||
|
||||
const hideBorderValue = Boolean(nextHideBorder)
|
||||
stackRef.current = [
|
||||
...stackRef.current.filter((entry) => entry.id !== id),
|
||||
{ id, content: nextContent, hideBorder: hideBorderValue }
|
||||
{ id, content: nextContent }
|
||||
]
|
||||
setContent(nextContent)
|
||||
setHideBorder(hideBorderValue)
|
||||
|
||||
if (!visibleRef.current) {
|
||||
window.requestAnimationFrame(() => setVisible(true))
|
||||
@ -84,7 +81,6 @@ export const TooltipProvider = ({ children }) => {
|
||||
|
||||
if (last) {
|
||||
setContent(last.content)
|
||||
setHideBorder(Boolean(last.hideBorder))
|
||||
setVisible(true)
|
||||
return
|
||||
}
|
||||
@ -104,12 +100,7 @@ export const TooltipProvider = ({ children }) => {
|
||||
return (
|
||||
<TooltipContext.Provider value={{ showTooltip, hideTooltip }}>
|
||||
{children}
|
||||
<CursorTooltip
|
||||
content={content}
|
||||
visible={visible}
|
||||
pointRef={pointRef}
|
||||
hideBorder={hideBorder}
|
||||
/>
|
||||
<CursorTooltip content={content} visible={visible} pointRef={pointRef} />
|
||||
</TooltipContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user