breadcrumbs.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import { findInTreeOrThrow } from '@/features/file-tree/util/find-in-tree'
  2. import { useFileTreeOpenContext } from '@/features/ide-react/context/file-tree-open-context'
  3. import { useOutlineContext } from '@/features/ide-react/context/outline-context'
  4. import useNestedOutline from '@/features/outline/hooks/use-nested-outline'
  5. import getChildrenLines from '@/features/outline/util/get-children-lines'
  6. import MaterialIcon from '@/shared/components/material-icon'
  7. import { useFileTreeData } from '@/shared/context/file-tree-data-context'
  8. import { Fragment, useMemo } from 'react'
  9. import { Outline } from '@/features/source-editor/utils/tree-operations/outline'
  10. const constructOutlineHierarchy = (
  11. items: Outline[],
  12. highlightedLine: number,
  13. outlineHierarchy: Outline[] = []
  14. ) => {
  15. for (const item of items) {
  16. if (item.line === highlightedLine) {
  17. outlineHierarchy.push(item)
  18. return outlineHierarchy
  19. }
  20. const childLines = getChildrenLines(item.children)
  21. if (childLines.includes(highlightedLine)) {
  22. outlineHierarchy.push(item)
  23. return constructOutlineHierarchy(
  24. item.children as Outline[],
  25. highlightedLine,
  26. outlineHierarchy
  27. )
  28. }
  29. }
  30. return outlineHierarchy
  31. }
  32. export default function Breadcrumbs() {
  33. const { openEntity } = useFileTreeOpenContext()
  34. const { fileTreeData } = useFileTreeData()
  35. const outline = useNestedOutline()
  36. const { highlightedLine, canShowOutline } = useOutlineContext()
  37. const folderHierarchy = useMemo(() => {
  38. if (!openEntity || !fileTreeData) {
  39. return []
  40. }
  41. return openEntity.path
  42. .filter(id => id !== fileTreeData._id) // Filter out the root folder
  43. .map(id => {
  44. return findInTreeOrThrow(fileTreeData, id)?.entity
  45. })
  46. }, [openEntity, fileTreeData])
  47. const outlineHierarchy = useMemo(() => {
  48. if (!canShowOutline || !outline) {
  49. return []
  50. }
  51. return constructOutlineHierarchy(outline.items, highlightedLine)
  52. }, [outline, highlightedLine, canShowOutline])
  53. if (!openEntity || !fileTreeData) {
  54. return null
  55. }
  56. const numOutlineItems = outlineHierarchy.length
  57. return (
  58. <div className="ol-cm-breadcrumbs">
  59. {folderHierarchy.map(folder => (
  60. <Fragment key={folder._id}>
  61. <div>{folder.name}</div>
  62. <Chevron />
  63. </Fragment>
  64. ))}
  65. <MaterialIcon unfilled type="description" />
  66. <div>{openEntity.entity.name}</div>
  67. {numOutlineItems > 0 && <Chevron />}
  68. {outlineHierarchy.map((section, idx) => (
  69. <Fragment key={section.line}>
  70. <div>{section.title}</div>
  71. {idx < numOutlineItems - 1 && <Chevron />}
  72. </Fragment>
  73. ))}
  74. </div>
  75. )
  76. }
  77. const Chevron = () => (
  78. <MaterialIcon className="ol-cm-breadcrumb-chevron" type="chevron_right" />
  79. )