ListItem.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /**
  2. * ListItem
  3. * @author: oldj
  4. * @homepage: https://oldj.net
  5. */
  6. import { useModel } from '@@/plugin-model/useModel'
  7. import ItemIcon from '@renderer/components/ItemIcon'
  8. import SwitchButton from '@renderer/components/SwitchButton'
  9. import { agent } from '@renderer/core/agent'
  10. import { PopupMenu } from '@renderer/core/PopupMenu'
  11. import { IHostsListObject } from '@root/common/data'
  12. import { updateOneItem } from '@root/common/hostsFn'
  13. import clsx from 'clsx'
  14. import React, { useEffect, useRef, useState } from 'react'
  15. import { BiEdit } from 'react-icons/bi'
  16. import { Center } from '@chakra-ui/react'
  17. import scrollIntoView from 'smooth-scroll-into-view-if-needed'
  18. import styles from './ListItem.less'
  19. import events from '@root/common/events'
  20. interface Props {
  21. data: IHostsListObject;
  22. is_tray?: boolean;
  23. }
  24. const ListItem = (props: Props) => {
  25. const { data, is_tray } = props
  26. const { lang } = useModel('useI18n')
  27. const { hosts_data, setList, current_hosts, setCurrentHosts } = useModel('useHostsData')
  28. const [ is_collapsed, setIsCollapsed ] = useState(!!data.is_collapsed)
  29. const [ is_on, setIsOn ] = useState(data.on)
  30. const el = useRef<HTMLDivElement>(null)
  31. // const [item_height, setItemHeight] = useState(0)
  32. useEffect(() => {
  33. setIsOn(data.on)
  34. }, [ data ])
  35. useEffect(() => {
  36. const is_selected = data.id === current_hosts?.id
  37. if (is_selected && el.current) {
  38. // el.current.scrollIntoViewIfNeeded()
  39. scrollIntoView(el.current, {
  40. behavior: 'smooth',
  41. scrollMode: 'if-needed',
  42. })
  43. }
  44. }, [ data, current_hosts, el ])
  45. const onSelect = () => {
  46. setCurrentHosts(data.is_sys ? null : data)
  47. }
  48. const toggleIsCollapsed = () => {
  49. if (!is_folder) return
  50. let _is_collapsed = !is_collapsed
  51. setIsCollapsed(_is_collapsed)
  52. setList(updateOneItem(hosts_data.list, { id: data.id, is_collapsed: _is_collapsed }))
  53. .catch(e => console.error(e))
  54. }
  55. const toggleOn = (on?: boolean) => {
  56. on = typeof on === 'boolean' ? on : !is_on
  57. setIsOn(on)
  58. agent.broadcast(events.toggle_item, data.id, on)
  59. }
  60. if (!data) return null
  61. const is_folder = data.type === 'folder'
  62. const is_selected = data.id === current_hosts?.id
  63. const menu = new PopupMenu([
  64. {
  65. label: lang.edit,
  66. click() {
  67. agent.broadcast(events.edit_hosts_info, data)
  68. },
  69. },
  70. {
  71. type: 'separator',
  72. },
  73. {
  74. label: lang.move_to_trashcan,
  75. click() {
  76. agent.broadcast(events.move_to_trashcan, data.id)
  77. },
  78. },
  79. ])
  80. return (
  81. <div
  82. className={clsx(
  83. styles.root,
  84. is_selected && styles.selected,
  85. is_tray && styles.is_tray,
  86. )}
  87. // className={clsx(styles.item, is_selected && styles.selected, is_collapsed && styles.is_collapsed)}
  88. // style={{ paddingLeft: `${1.3 * level}em` }}
  89. onContextMenu={(e) => {
  90. !data.is_sys && !is_tray && menu.show()
  91. e.preventDefault()
  92. e.stopPropagation()
  93. }}
  94. ref={el}
  95. onClick={(e: React.MouseEvent) => {
  96. e.preventDefault()
  97. e.stopPropagation()
  98. }}
  99. >
  100. <div className={styles.title} onClick={onSelect}>
  101. <span
  102. className={clsx(styles.icon, is_folder && styles.folder)}
  103. onClick={toggleIsCollapsed}
  104. >
  105. <ItemIcon type={data.is_sys ? 'system' : data.type} is_collapsed={data.is_collapsed}/>
  106. </span>
  107. {data.title || lang.untitled}
  108. </div>
  109. <div className={styles.status}>
  110. {data.is_sys ? null : (
  111. <>
  112. <div className={styles.edit}>
  113. <Center h="var(--swh-tree-row-height)">
  114. <BiEdit
  115. title={lang.edit}
  116. onClick={() => {
  117. agent.broadcast(events.edit_hosts_info, data)
  118. }}
  119. />
  120. </Center>
  121. </div>
  122. <SwitchButton on={!!is_on} onChange={(on) => toggleOn(on)}/>
  123. </>
  124. )}
  125. </div>
  126. </div>
  127. )
  128. }
  129. export default ListItem