@likec4/diagram 1.35.0 → 1.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/bundle/{chunk-C0Eg81Gj.js → chunk-7MPUJFHj.js} +315 -311
  2. package/bundle/custom.js +52 -52
  3. package/bundle/index.js +1583 -739
  4. package/dist/LikeC4Diagram.js +6 -6
  5. package/dist/LikeC4Diagram.props.d.ts +2 -3
  6. package/dist/LikeC4ModelProvider.d.ts +3 -3
  7. package/dist/LikeC4ProjectsProvider.d.ts +17 -0
  8. package/dist/LikeC4ProjectsProvider.js +22 -0
  9. package/dist/LikeC4Styles.d.ts +1 -0
  10. package/dist/LikeC4Styles.js +94 -0
  11. package/dist/StaticLikeC4Diagram.d.ts +3 -3
  12. package/dist/base/BaseXYFlow.js +23 -26
  13. package/dist/base/primitives/MarkdownBlock.d.ts +7 -1
  14. package/dist/base/primitives/MarkdownBlock.js +1 -1
  15. package/dist/base/primitives/compound/CompoundActionButton.js +2 -2
  16. package/dist/base/primitives/compound/CompoundDetailsButton.js +2 -2
  17. package/dist/base/primitives/compound/CompoundNodeContainer.css.js +4 -4
  18. package/dist/base/primitives/compound/CompoundNodeContainer.js +1 -4
  19. package/dist/base/primitives/compound/CompoundTitle.js +9 -8
  20. package/dist/base/primitives/compound/actionbtns.css.js +6 -6
  21. package/dist/base/primitives/edge/EdgeActionButton.js +2 -2
  22. package/dist/base/primitives/edge/EdgeContainer.js +4 -7
  23. package/dist/base/primitives/edge/EdgeLabel.css.d.ts +0 -22
  24. package/dist/base/primitives/edge/EdgeLabel.css.js +6 -84
  25. package/dist/base/primitives/edge/EdgeLabel.js +16 -6
  26. package/dist/base/primitives/edge/EdgeLabelContainer.js +1 -6
  27. package/dist/base/primitives/edge/EdgeMarkers.js +3 -3
  28. package/dist/base/primitives/edge/edge.css.d.ts +0 -2
  29. package/dist/base/primitives/edge/edge.css.js +1 -55
  30. package/dist/base/primitives/element/ElementActionButtons.js +2 -2
  31. package/dist/base/primitives/element/ElementDetailsButton.js +8 -7
  32. package/dist/base/primitives/element/ElementNodeContainer.css.js +4 -4
  33. package/dist/base/primitives/element/ElementNodeContainer.js +1 -4
  34. package/dist/base/primitives/element/ElementShape.css.js +11 -11
  35. package/dist/base/primitives/element/ElementTags.d.ts +1 -0
  36. package/dist/base/primitives/element/ElementTags.js +17 -14
  37. package/dist/bundle/LikeC4View.d.ts +1 -1
  38. package/dist/bundle/LikeC4View.js +7 -1
  39. package/dist/bundle/LikeC4View.props.d.ts +1 -2
  40. package/dist/bundle/ReactLikeC4.d.ts +1 -1
  41. package/dist/bundle/ViewNotFound.js +1 -1
  42. package/dist/bundle/index.d.ts +2 -1
  43. package/dist/bundle/index.js +1 -0
  44. package/dist/bundle/styles.css.js +1 -1
  45. package/dist/components/ErrorFallback.js +1 -1
  46. package/dist/components/GithubIcon.d.ts +2 -0
  47. package/dist/components/GithubIcon.js +17 -0
  48. package/dist/components/Link.d.ts +4 -3
  49. package/dist/components/Link.js +84 -87
  50. package/dist/components/NavigationLink.d.ts +2 -2
  51. package/dist/components/SearchControl.css.js +6 -5
  52. package/dist/context/DiagramEventHandlers.d.ts +6 -6
  53. package/dist/context/DiagramEventHandlers.js +4 -7
  54. package/dist/globals.css.js +3 -0
  55. package/dist/hooks/useXYFlow.d.ts +10 -10
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.js +1 -0
  58. package/dist/likec4diagram/custom/edges/NotePopover.css.js +2 -2
  59. package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +2 -2
  60. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +1 -1
  61. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.css.js +7 -7
  62. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +3 -3
  63. package/dist/likec4diagram/custom/edges/edges.css.js +4 -4
  64. package/dist/likec4diagram/custom/index.d.ts +2 -2
  65. package/dist/likec4diagram/custom/nodes/toolbar/CompoundToolbar.js +2 -2
  66. package/dist/likec4diagram/ui/controls/styles.css.js +5 -5
  67. package/dist/likec4diagram/ui/notation/NotationPanel.css.js +11 -11
  68. package/dist/likec4diagram/ui/notation/NotationPanel.js +2 -5
  69. package/dist/likec4diagram/ui/walkthrough/DynamicViewWalkthrough.css.js +10 -10
  70. package/dist/likec4model/LikeC4ProjectsContext.d.ts +7 -0
  71. package/dist/likec4model/LikeC4ProjectsContext.js +5 -0
  72. package/dist/likec4model/index.d.ts +1 -0
  73. package/dist/likec4model/useLikeC4Project.d.ts +22 -0
  74. package/dist/likec4model/useLikeC4Project.js +23 -0
  75. package/dist/navigationpanel/NavigationPanel.js +15 -17
  76. package/dist/navigationpanel/NavigationPanelControls.js +34 -21
  77. package/dist/navigationpanel/NavigationPanelDropdown.js +33 -17
  78. package/dist/navigationpanel/_common.js +4 -1
  79. package/dist/navigationpanel/actor.d.ts +11 -15
  80. package/dist/navigationpanel/actor.js +14 -15
  81. package/dist/navigationpanel/controls/BurgerButton.js +5 -7
  82. package/dist/navigationpanel/controls/NavigationButtons.js +37 -24
  83. package/dist/navigationpanel/controls/OpenSource.js +1 -1
  84. package/dist/navigationpanel/controls/SearchControl.js +6 -4
  85. package/dist/navigationpanel/controls/ToggleReadonly.js +3 -3
  86. package/dist/navigationpanel/controls/ViewDetailsCard.d.ts +2 -0
  87. package/dist/navigationpanel/controls/ViewDetailsCard.js +232 -0
  88. package/dist/navigationpanel/controls/index.d.ts +1 -0
  89. package/dist/navigationpanel/dropdown/ProjectsMenu.d.ts +2 -0
  90. package/dist/navigationpanel/dropdown/ProjectsMenu.js +75 -0
  91. package/dist/navigationpanel/editorpanel/EditorPanel.js +3 -3
  92. package/dist/navigationpanel/editorpanel/ManualLayoutToolsButton.js +19 -20
  93. package/dist/navigationpanel/editorpanel/styles.js +5 -5
  94. package/dist/navigationpanel/hooks.d.ts +2 -2
  95. package/dist/navigationpanel/styles.css.js +0 -2
  96. package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.js +12 -7
  97. package/dist/node_modules/.pnpm/@tabler_icons-react@3.34.1_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconChevronDown.js +14 -0
  98. package/dist/node_modules/.pnpm/@tabler_icons-react@3.34.1_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconLink.js +14 -0
  99. package/dist/overlays/element-details/ElementDetailsCard.css.js +18 -17
  100. package/dist/overlays/element-details/ElementDetailsCard.js +8 -13
  101. package/dist/overlays/element-details/TabPanelDeployments.css.js +5 -4
  102. package/dist/overlays/element-details/TabPanelRelationships.css.js +7 -7
  103. package/dist/overlays/overlay/Overlay.css.d.ts +3 -3
  104. package/dist/overlays/overlay/Overlay.css.js +8 -7
  105. package/dist/overlays/relationship-details/SelectEdge.css.js +8 -8
  106. package/dist/overlays/relationships-browser/SelectElement.css.js +1 -1
  107. package/dist/search/Search.js +6 -6
  108. package/dist/search/components/ElementsColumn.css.js +5 -5
  109. package/dist/search/components/SearchByTags.js +3 -2
  110. package/dist/search/components/ViewsColum.js +1 -1
  111. package/dist/search/components/ViewsColumn.css.js +1 -1
  112. package/dist/search/components/_shared.css.js +3 -3
  113. package/dist/search/components/styles.css.js +5 -5
  114. package/dist/state/DiagramActorProvider.js +34 -15
  115. package/dist/state/diagram-machine.d.ts +29 -247
  116. package/dist/state/diagram-machine.js +16 -16
  117. package/dist/styles-min.css +1 -1
  118. package/dist/styles.css +1 -1
  119. package/dist/styles.css2.js +1 -1
  120. package/package.json +10 -8
  121. package/panda.buildinfo.json +254 -326
  122. package/src/LikeC4Diagram.props.ts +2 -2
  123. package/src/LikeC4Diagram.tsx +2 -2
  124. package/src/LikeC4ModelProvider.tsx +4 -4
  125. package/src/LikeC4ProjectsProvider.tsx +41 -0
  126. package/src/LikeC4Styles.tsx +107 -0
  127. package/src/StaticLikeC4Diagram.tsx +3 -3
  128. package/src/base/BaseXYFlow.tsx +24 -29
  129. package/src/base/primitives/MarkdownBlock.tsx +11 -3
  130. package/src/base/primitives/compound/CompoundActionButton.tsx +2 -2
  131. package/src/base/primitives/compound/CompoundDetailsButton.tsx +2 -2
  132. package/src/base/primitives/compound/CompoundNodeContainer.css.ts +4 -13
  133. package/src/base/primitives/compound/CompoundNodeContainer.tsx +0 -3
  134. package/src/base/primitives/compound/CompoundTitle.tsx +8 -8
  135. package/src/base/primitives/compound/actionbtns.css.ts +6 -6
  136. package/src/base/primitives/edge/EdgeActionButton.tsx +2 -2
  137. package/src/base/primitives/edge/EdgeContainer.tsx +3 -6
  138. package/src/base/primitives/edge/EdgeLabel.css.ts +4 -83
  139. package/src/base/primitives/edge/EdgeLabel.tsx +16 -10
  140. package/src/base/primitives/edge/EdgeLabelContainer.tsx +1 -6
  141. package/src/base/primitives/edge/EdgeMarkers.tsx +3 -3
  142. package/src/base/primitives/edge/edge.css.ts +0 -60
  143. package/src/base/primitives/element/ElementActionButtons.tsx +2 -2
  144. package/src/base/primitives/element/ElementDetailsButton.tsx +7 -7
  145. package/src/base/primitives/element/ElementNodeContainer.css.ts +4 -4
  146. package/src/base/primitives/element/ElementNodeContainer.tsx +0 -3
  147. package/src/base/primitives/element/ElementShape.css.ts +11 -11
  148. package/src/base/primitives/element/ElementTags.tsx +17 -14
  149. package/src/bundle/LikeC4View.props.ts +1 -2
  150. package/src/bundle/LikeC4View.tsx +10 -3
  151. package/src/bundle/ReactLikeC4.tsx +1 -2
  152. package/src/bundle/ViewNotFound.tsx +1 -1
  153. package/src/bundle/index.ts +2 -1
  154. package/src/bundle/styles.css.ts +1 -1
  155. package/src/components/ErrorFallback.tsx +1 -1
  156. package/src/components/GithubIcon.tsx +16 -0
  157. package/src/components/Link.tsx +102 -113
  158. package/src/components/NavigationLink.tsx +2 -1
  159. package/src/components/SearchControl.css.ts +5 -5
  160. package/src/context/DiagramEventHandlers.tsx +12 -12
  161. package/src/globals.css +71 -0
  162. package/src/index.ts +5 -0
  163. package/src/likec4diagram/custom/edges/NotePopover.css.ts +2 -2
  164. package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +1 -1
  165. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.css.ts +7 -7
  166. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +3 -3
  167. package/src/likec4diagram/custom/edges/edges.css.ts +4 -4
  168. package/src/likec4diagram/custom/nodes/toolbar/CompoundToolbar.tsx +2 -2
  169. package/src/likec4diagram/ui/controls/styles.css.ts +5 -5
  170. package/src/likec4diagram/ui/notation/NotationPanel.css.ts +11 -11
  171. package/src/likec4diagram/ui/notation/NotationPanel.tsx +1 -4
  172. package/src/likec4diagram/ui/walkthrough/DynamicViewWalkthrough.css.ts +10 -10
  173. package/src/likec4model/LikeC4ProjectsContext.ts +9 -0
  174. package/src/likec4model/index.ts +8 -0
  175. package/src/likec4model/useLikeC4Project.ts +61 -0
  176. package/src/navigationpanel/NavigationPanel.tsx +16 -17
  177. package/src/navigationpanel/NavigationPanelControls.tsx +24 -46
  178. package/src/navigationpanel/NavigationPanelDropdown.tsx +32 -16
  179. package/src/navigationpanel/_common.tsx +4 -1
  180. package/src/navigationpanel/actor.ts +14 -15
  181. package/src/navigationpanel/controls/BurgerButton.tsx +5 -7
  182. package/src/navigationpanel/controls/NavigationButtons.tsx +9 -1
  183. package/src/navigationpanel/controls/OpenSource.tsx +1 -1
  184. package/src/navigationpanel/controls/SearchControl.tsx +6 -4
  185. package/src/navigationpanel/controls/ToggleReadonly.tsx +3 -3
  186. package/src/navigationpanel/controls/ViewDetailsCard.tsx +244 -0
  187. package/src/navigationpanel/controls/index.ts +1 -0
  188. package/src/navigationpanel/dropdown/ProjectsMenu.tsx +74 -0
  189. package/src/navigationpanel/editorpanel/EditorPanel.tsx +3 -3
  190. package/src/navigationpanel/editorpanel/ManualLayoutToolsButton.tsx +19 -22
  191. package/src/navigationpanel/editorpanel/styles.ts +5 -5
  192. package/src/navigationpanel/hooks.tsx +2 -2
  193. package/src/navigationpanel/styles.css.ts +0 -2
  194. package/src/navigationpanel/walkthrough/ActiveWalkthroughControls.tsx +9 -4
  195. package/src/overlays/element-details/ElementDetailsCard.css.ts +17 -17
  196. package/src/overlays/element-details/ElementDetailsCard.tsx +8 -13
  197. package/src/overlays/element-details/TabPanelDeployments.css.ts +4 -4
  198. package/src/overlays/element-details/TabPanelRelationships.css.ts +7 -7
  199. package/src/overlays/overlay/Overlay.css.ts +7 -7
  200. package/src/overlays/relationship-details/SelectEdge.css.ts +8 -8
  201. package/src/overlays/relationships-browser/SelectElement.css.ts +1 -1
  202. package/src/search/Search.tsx +6 -6
  203. package/src/search/components/ElementsColumn.css.ts +5 -5
  204. package/src/search/components/SearchByTags.tsx +2 -2
  205. package/src/search/components/ViewsColum.tsx +1 -1
  206. package/src/search/components/ViewsColumn.css.ts +1 -1
  207. package/src/search/components/_shared.css.ts +3 -3
  208. package/src/search/components/styles.css.ts +5 -5
  209. package/src/state/DiagramActorProvider.tsx +45 -20
  210. package/src/state/diagram-machine.ts +22 -16
  211. package/dist/LikeC4CustomColors.d.ts +0 -2
  212. package/dist/LikeC4CustomColors.js +0 -45
  213. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +0 -45
  214. package/src/LikeC4CustomColors.tsx +0 -85
@@ -0,0 +1,9 @@
1
+ import type { LikeC4Project, ProjectId } from '@likec4/core/types'
2
+ import { createContext } from 'react'
3
+
4
+ export type LikeC4ProjectsContext = {
5
+ projects: ReadonlyArray<LikeC4Project>
6
+ onProjectChange: (id: ProjectId) => void
7
+ }
8
+
9
+ export const LikeC4ProjectsContext = createContext<LikeC4ProjectsContext | null>(null)
@@ -9,3 +9,11 @@ export {
9
9
  useLikeC4Specification,
10
10
  useLikeC4ViewModel,
11
11
  } from './useLikeC4Model'
12
+
13
+ export {
14
+ useChangeLikeC4Project,
15
+ useHasProjects,
16
+ useLikeC4ProjectId,
17
+ useLikeC4Projects,
18
+ useLikeC4ProjectsContext,
19
+ } from './useLikeC4Project'
@@ -0,0 +1,61 @@
1
+ import { type LikeC4Project, type ProjectId } from '@likec4/core/types'
2
+ import { useContext } from 'react'
3
+ import { LikeC4ModelContext } from './LikeC4ModelContext'
4
+ import { LikeC4ProjectsContext } from './LikeC4ProjectsContext'
5
+
6
+ const emptyProjects: ReadonlyArray<LikeC4Project> = []
7
+ /**
8
+ * @returns The list of available projects, or empty array if no projects are available.
9
+ */
10
+ export function useLikeC4Projects(): ReadonlyArray<LikeC4Project> {
11
+ const ctx = useContext(LikeC4ProjectsContext)
12
+ if (!ctx) {
13
+ return emptyProjects
14
+ }
15
+ return ctx.projects
16
+ }
17
+
18
+ const emptyOnProjectChange: (id: ProjectId) => void = () => {}
19
+ /**
20
+ * @returns The callback to change current project.
21
+ */
22
+ export function useChangeLikeC4Project(): (id: ProjectId) => void {
23
+ const ctx = useContext(LikeC4ProjectsContext)
24
+ if (!ctx) {
25
+ return emptyOnProjectChange
26
+ }
27
+ return ctx.onProjectChange
28
+ }
29
+
30
+ const emptyContext: LikeC4ProjectsContext = {
31
+ projects: emptyProjects,
32
+ onProjectChange: emptyOnProjectChange,
33
+ }
34
+ /**
35
+ * @returns The callback to change current project.
36
+ */
37
+ export function useLikeC4ProjectsContext(): LikeC4ProjectsContext {
38
+ return useContext(LikeC4ProjectsContext) ?? emptyContext
39
+ }
40
+
41
+ /**
42
+ * @returns True if there are more than one project available in the context.
43
+ */
44
+ export function useHasProjects(): boolean {
45
+ const ctx = useContext(LikeC4ProjectsContext)
46
+ if (!ctx) {
47
+ return false
48
+ }
49
+ return ctx.projects.length > 1
50
+ }
51
+
52
+ /**
53
+ * @returns The current project id.
54
+ */
55
+ export function useLikeC4ProjectId(): ProjectId {
56
+ const ctx = useContext(LikeC4ModelContext)
57
+ if (!ctx) {
58
+ throw new Error('No LikeC4ModelContext found')
59
+ }
60
+ return ctx.projectId as ProjectId
61
+ }
@@ -35,7 +35,7 @@ export const NavigationPanel = memo(() => {
35
35
  },
36
36
  )
37
37
  useEffect(() => {
38
- const subscription = actorRef.on('trigger.navigateTo', (event) => {
38
+ const subscription = actorRef.on('navigateTo', (event) => {
39
39
  if (diagramActor.getSnapshot().context.view.id !== event.viewId) {
40
40
  diagramActor.send({ type: 'navigate.to', viewId: event.viewId })
41
41
  }
@@ -52,25 +52,25 @@ export const NavigationPanel = memo(() => {
52
52
  <VStack
53
53
  className="react-flow__panel"
54
54
  css={{
55
- gap: 'sm',
56
- margin: 'sm',
57
55
  alignItems: 'flex-start',
58
56
  pointerEvents: 'none',
59
- top: 0,
60
- left: 0,
57
+
58
+ top: '0',
59
+ left: '0',
60
+ margin: '0',
61
+ width: '100%',
62
+ gap: 'xxs',
61
63
  maxWidth: [
62
- 'calc(100vw - 2 * {spacing.sm})',
63
- 'calc(100cqw - 2 * {spacing.sm})',
64
+ 'calc(100vw)',
65
+ 'calc(100cqw)',
64
66
  ],
65
- width: 'max-content',
66
- overflow: 'hidden',
67
- smDown: {
68
- margin: 0,
69
- width: '100%',
70
- gap: '2xs',
67
+ '@/sm': {
68
+ margin: 'xs',
69
+ gap: 'xs',
70
+ width: 'max-content',
71
71
  maxWidth: [
72
- 'calc(100vw)',
73
- 'calc(100cqw)',
72
+ 'calc(100vw - 2 * {spacing.md})',
73
+ 'calc(100cqw - 2 * {spacing.md})',
74
74
  ],
75
75
  },
76
76
  }}>
@@ -91,11 +91,10 @@ const NavigationPanelImpl = ({ actor }: { actor: NavigationPanelActorRef }) => {
91
91
  return (
92
92
  <Popover
93
93
  offset={{
94
- mainAxis: 4,
94
+ mainAxis: 2,
95
95
  }}
96
96
  middlewares={{ flip: false }}
97
97
  opened={opened}
98
- shadow="md"
99
98
  position="bottom-start"
100
99
  trapFocus
101
100
  {...portalProps}
@@ -10,8 +10,8 @@ import * as m from 'motion/react-m'
10
10
  import { useEnabledFeatures } from '../context/DiagramFeatures'
11
11
  import { BreadcrumbsSeparator } from './_common'
12
12
  import { type NavigationPanelActorSnapshot } from './actor'
13
- import { BurgerButton, NavigationButtons, OpenSource, SearchControl, ToggleReadonly } from './controls'
14
- import { useNavigationActorRef } from './hooks'
13
+ import { BurgerButton, NavigationButtons, OpenSource, SearchControl, ToggleReadonly, ViewDetailsCard } from './controls'
14
+ import { useNavigationActor } from './hooks'
15
15
  import { breadcrumbTitle } from './styles.css'
16
16
  import { StartWalkthroughButton } from './walkthrough'
17
17
 
@@ -25,12 +25,11 @@ const selectBreadcrumbs = ({ context }: NavigationPanelActorSnapshot) => {
25
25
  viewId: context.viewModel.id,
26
26
  viewTitle: context.viewModel.titleOrUntitled,
27
27
  isDynamicView: context.viewModel.isDynamicView(),
28
- hasLinks: context.viewModel.links.length > 0,
29
28
  }
30
29
  }
31
30
 
32
31
  export const NavigationPanelControls = () => {
33
- const actor = useNavigationActorRef()
32
+ const actor = useNavigationActor()
34
33
  const {
35
34
  enableSearch,
36
35
  enableNavigationButtons,
@@ -41,7 +40,7 @@ export const NavigationPanelControls = () => {
41
40
  folders,
42
41
  viewTitle,
43
42
  isDynamicView,
44
- } = useSelector(actor, selectBreadcrumbs, deepEqual)
43
+ } = useSelector(actor.actorRef, selectBreadcrumbs, deepEqual)
45
44
 
46
45
  const folderBreadcrumbs = folders.flatMap(({ folderPath, title }, i) => [
47
46
  <UnstyledButton
@@ -51,10 +50,14 @@ export const NavigationPanelControls = () => {
51
50
  breadcrumbTitle({ dimmed: true, truncate: true }),
52
51
  'mantine-active',
53
52
  css({
53
+ userSelect: 'none',
54
54
  maxWidth: '200px',
55
+ display: {
56
+ base: 'none',
57
+ '@/md': 'block',
58
+ },
55
59
  }),
56
60
  )}
57
- visibleFrom="sm"
58
61
  title={title}
59
62
  onMouseEnter={() => actor.send({ type: 'breadcrumbs.mouseEnter.folder', folderPath })}
60
63
  onMouseLeave={() => actor.send({ type: 'breadcrumbs.mouseLeave.folder', folderPath })}
@@ -75,6 +78,9 @@ export const NavigationPanelControls = () => {
75
78
  className={cx(
76
79
  'mantine-active',
77
80
  breadcrumbTitle({ truncate: true }),
81
+ css({
82
+ userSelect: 'none',
83
+ }),
78
84
  )}
79
85
  title={viewTitle}
80
86
  onMouseEnter={() => actor.send({ type: 'breadcrumbs.mouseEnter.viewtitle' })}
@@ -90,66 +96,38 @@ export const NavigationPanelControls = () => {
90
96
 
91
97
  return (
92
98
  <AnimatePresence propagate>
93
- <BurgerButton />
94
- {enableNavigationButtons && <NavigationButtons />}
99
+ <BurgerButton key="burger-button" />
100
+ {enableNavigationButtons && <NavigationButtons key="nav-buttons" />}
95
101
  <m.div
102
+ key="breadcrumbs"
96
103
  layout="position"
97
104
  className={hstack({
98
- gap: 3,
105
+ gap: '[3px]',
99
106
  flexShrink: 1,
100
107
  flexGrow: 1,
101
108
  overflow: 'hidden',
102
- md: {
103
- marginRight: 'md',
104
- },
105
109
  })}>
106
110
  {folderBreadcrumbs}
107
111
  {viewBreadcrumb}
108
112
  </m.div>
109
- {
110
- /* <HStack gap={1}>
111
- <PanelActionIcon
112
- variant="subtle"
113
- size={24}
114
- component={m.button}
115
- whileHover={{
116
- scale: 1.085,
117
- }}
118
- whileTap={{
119
- scale: 1,
120
- translateY: 1,
121
- }}
122
- children={<IconInfoCircleFilled style={{ width: '85%', height: '85%' }} />}
123
- />
124
- <PanelActionIcon
125
- variant="subtle"
126
- size={24}
127
- component={m.button}
128
- whileHover={{
129
- scale: 1.085,
130
- }}
131
- whileTap={{
132
- scale: 1,
133
- translateY: 1,
134
- }}
135
- children={<IconLink style={{ width: '85%', height: '85%' }} />}
136
- />
137
- </HStack> */
138
- }
139
-
140
- {enableDynamicViewWalkthrough && isDynamicView && <StartWalkthroughButton />}
141
113
  <m.div
114
+ key="actions"
142
115
  layout="position"
143
116
  className={hstack({
144
- gap: 1,
117
+ gap: '[1px]',
118
+ flexGrow: 0,
145
119
  _empty: {
146
120
  display: 'none',
147
121
  },
148
122
  })}>
123
+ <ViewDetailsCard
124
+ onOpen={() => actor.closeDropdown()}
125
+ />
149
126
  <OpenSource />
150
127
  <ToggleReadonly />
151
128
  </m.div>
152
- {enableSearch && <SearchControl />}
129
+ {enableDynamicViewWalkthrough && isDynamicView && <StartWalkthroughButton key="walkthrough-button" />}
130
+ {enableSearch && <SearchControl key="search-control" />}
153
131
  </AnimatePresence>
154
132
  )
155
133
  }
@@ -32,6 +32,7 @@ import { isArray, isEmpty, pipe, sort } from 'remeda'
32
32
  import { type NavigationLinkProps, NavigationLink } from '../components/NavigationLink'
33
33
  import { useLikeC4Model } from '../likec4model/useLikeC4Model'
34
34
  import type { NavigationPanelActorContext } from './actor'
35
+ import { ProjectsMenu } from './dropdown/ProjectsMenu'
35
36
  import { useNavigationActor, useNavigationActorContext, useNavigationActorRef } from './hooks'
36
37
  import { breadcrumbTitle } from './styles.css'
37
38
 
@@ -59,7 +60,7 @@ export function NavigationPanelDropdown() {
59
60
  'nowheel',
60
61
  vstack({
61
62
  layerStyle: 'likec4.dropdown',
62
- gap: 'sm',
63
+ gap: 'xs',
63
64
  pointerEvents: 'all',
64
65
  }),
65
66
  )}
@@ -67,6 +68,7 @@ export function NavigationPanelDropdown() {
67
68
  onMouseLeave={() => actor.send({ type: 'dropdown.mouseLeave' })}
68
69
  onMouseEnter={() => actor.send({ type: 'dropdown.mouseEnter' })}
69
70
  >
71
+ <ProjectsMenu />
70
72
  <HStack gap="xs">
71
73
  <SearchInput
72
74
  value={searchQuery}
@@ -94,8 +96,8 @@ export function NavigationPanelDropdown() {
94
96
  classNames={{
95
97
  root: css({
96
98
  maxWidth: [
97
- 'calc(100vw - 20px)',
98
- 'calc(100cqw - 20px)',
99
+ 'calc(100vw - 50px)',
100
+ 'calc(100cqw - 50px)',
99
101
  ],
100
102
  }),
101
103
  }}
@@ -138,15 +140,15 @@ function SearchResults({ searchQuery }: { searchQuery: string }) {
138
140
  className={css({
139
141
  width: '100%',
140
142
  maxWidth: [
141
- '70vw',
143
+ 'calc(100vw - 250px)',
142
144
  'calc(100cqw - 250px)',
143
145
  ],
144
146
  maxHeight: [
145
- '70vh',
146
- 'calc(100cqh - 250px)',
147
+ 'calc(100vh - 200px)',
148
+ 'calc(100cqh - 200px)',
147
149
  ],
148
150
  })}>
149
- <VStack gap={1}>
151
+ <VStack gap="[1px]">
150
152
  {found.map(v => (
151
153
  <FoundedView
152
154
  key={v.id}
@@ -171,10 +173,10 @@ interface FoundedViewProps {
171
173
  }
172
174
 
173
175
  const foundedViewClass = hstack({
174
- gap: '2xs',
176
+ gap: 'xxs',
175
177
  rounded: 'sm',
176
178
  px: 'xs',
177
- py: '2xs',
179
+ py: 'xxs',
178
180
  _hover: {
179
181
  backgroundColor: {
180
182
  base: 'mantine.colors.gray[1]',
@@ -207,6 +209,18 @@ function FoundedView(
207
209
  className={cx(
208
210
  inheritColor,
209
211
  breadcrumbTitle({ truncate: true }),
212
+ css({
213
+ '& > mark': {
214
+ backgroundColor: {
215
+ base: 'mantine.colors.yellow[2]/90',
216
+ _dark: 'mantine.colors.yellow[5]/80',
217
+ _groupFocus: '[transparent]',
218
+ },
219
+ color: {
220
+ _groupFocus: '[inherit!]',
221
+ },
222
+ },
223
+ }),
210
224
  )}
211
225
  maw={350}
212
226
  highlight={highlight}
@@ -252,7 +266,7 @@ function FoundedView(
252
266
  </Highlight>
253
267
  ))
254
268
  breadcrumbs.push(
255
- <HStack gap={4}>
269
+ <HStack gap="[4px]">
256
270
  {viewIcon}
257
271
  {viewLabel}
258
272
  </HStack>,
@@ -281,6 +295,7 @@ const folderIcon = (
281
295
  base: 0.3,
282
296
  _groupHover: 0.5,
283
297
  _groupActive: 0.5,
298
+ _groupFocus: 0.5,
284
299
  },
285
300
  })} />
286
301
  )
@@ -289,8 +304,9 @@ const viewTypeIconCss = css({
289
304
  opacity: {
290
305
  base: 0.3,
291
306
  _dark: 0.5,
292
- _groupHover: 0.7,
293
- _groupActive: 0.7,
307
+ _groupHover: 0.8,
308
+ _groupActive: 0.8,
309
+ _groupFocus: 0.8,
294
310
  },
295
311
  })
296
312
  const ViewTypeIcon = {
@@ -309,8 +325,8 @@ const ColumnScrollArea = ScrollAreaAutosize.withProps({
309
325
  scrollbars: 'y',
310
326
  className: css({
311
327
  maxHeight: [
312
- 'calc(100vh - 50px)',
313
- 'calc(100cqh - 50px)',
328
+ 'calc(100vh - 160px)',
329
+ 'calc(100cqh - 160px)',
314
330
  ],
315
331
  }),
316
332
  })
@@ -400,9 +416,9 @@ function FolderColumn({ data }: { data: FolderColumnData }) {
400
416
  }
401
417
 
402
418
  return (
403
- <Box pb={'4'}>
419
+ <Box mb={'1'}>
404
420
  <ColumnScrollArea>
405
- <VStack gap={1}>
421
+ <VStack gap="[1px]">
406
422
  {data.items.map((item, i) => (
407
423
  <FolderColumnItem
408
424
  key={`${data.folderPath}/${item.type}/${i}`}
@@ -28,10 +28,13 @@ export const Tooltip = MantineTooltip.withProps({
28
28
 
29
29
  export const BreadcrumbsSeparator = () => (
30
30
  <ThemeIcon
31
- visibleFrom="sm"
32
31
  variant="transparent"
33
32
  size={16}
34
33
  className={css({
34
+ display: {
35
+ base: 'none',
36
+ '@/md': 'flex',
37
+ },
35
38
  color: {
36
39
  base: 'mantine.colors.gray[5]',
37
40
  _dark: 'mantine.colors.dark[3]',
@@ -40,7 +40,7 @@ export type NavigationPanelActorEvent =
40
40
  | { type: 'dropdown.mouseLeave' }
41
41
  | { type: 'dropdown.dismiss' }
42
42
 
43
- export type NavigationPanelActorEmitted = { type: 'trigger.navigateTo'; viewId: ViewId }
43
+ export type NavigationPanelActorEmitted = { type: 'navigateTo'; viewId: ViewId }
44
44
 
45
45
  export type BreadcrumbItem =
46
46
  | { type: 'folder'; folderPath: string; title: string }
@@ -109,6 +109,9 @@ const _actorLogic = setup({
109
109
  activatedBy: 'click',
110
110
  }),
111
111
  'update selected folder': assign(({ event }) => {
112
+ if (event.type === 'breadcrumbs.click.root') {
113
+ return { selectedFolder: '' } // reset to root
114
+ }
112
115
  assertEvent(event, ['breadcrumbs.click.folder', 'select.folder'])
113
116
  return { selectedFolder: event.folderPath }
114
117
  }),
@@ -136,10 +139,10 @@ const _actorLogic = setup({
136
139
  assertEvent(event, 'searchQuery.change')
137
140
  return { searchQuery: event.value ?? '' }
138
141
  }),
139
- 'emit trigger.navigateTo': emit(({ event }) => {
142
+ 'emit navigateTo': emit(({ event }) => {
140
143
  assertEvent(event, 'select.view')
141
144
  return {
142
- type: 'trigger.navigateTo' as const,
145
+ type: 'navigateTo' as const,
143
146
  viewId: ViewId(event.viewId),
144
147
  }
145
148
  }),
@@ -248,15 +251,11 @@ const _actorLogic = setup({
248
251
  actions: 'keep dropdown open',
249
252
  target: 'search',
250
253
  },
251
- 'breadcrumbs.click.folder': {
252
- actions: 'update selected folder',
253
- target: 'opened',
254
- reenter: true,
255
- },
256
254
  'breadcrumbs.click.viewtitle': {
257
255
  actions: 'reset selected folder',
258
- reenter: true,
259
- target: 'opened',
256
+ },
257
+ 'breadcrumbs.click.*': {
258
+ actions: 'update selected folder',
260
259
  },
261
260
  'select.folder': {
262
261
  actions: [
@@ -266,30 +265,30 @@ const _actorLogic = setup({
266
265
  },
267
266
  'select.view': {
268
267
  actions: [
269
- 'emit trigger.navigateTo',
268
+ 'emit navigateTo',
270
269
  ],
271
270
  },
272
271
  },
273
272
  },
274
273
  search: {
275
274
  on: {
276
- 'breadcrumbs.click.folder': {
275
+ 'breadcrumbs.click.viewtitle': {
277
276
  actions: [
278
277
  'reset search query',
279
- 'update selected folder',
278
+ 'reset selected folder',
280
279
  ],
281
280
  target: 'opened',
282
281
  },
283
282
  'breadcrumbs.click.*': {
284
283
  actions: [
285
284
  'reset search query',
286
- 'reset selected folder',
285
+ 'update selected folder',
287
286
  ],
288
287
  target: 'opened',
289
288
  },
290
289
  'select.view': {
291
290
  actions: [
292
- 'emit trigger.navigateTo',
291
+ 'emit navigateTo',
293
292
  ],
294
293
  },
295
294
  },
@@ -1,10 +1,10 @@
1
1
  import { IconMenu2 } from '@tabler/icons-react'
2
- import { useDiagramEventHandlers } from '../../context'
2
+ import { useDiagramEventHandlers } from '../../context/DiagramEventHandlers'
3
3
  import { PanelActionIcon } from '../_common'
4
- import { useNavigationActorRef } from '../hooks'
4
+ import { useNavigationActor } from '../hooks'
5
5
 
6
6
  export const BurgerButton = () => {
7
- const actor = useNavigationActorRef()
7
+ const actor = useNavigationActor()
8
8
  const { onBurgerMenuClick } = useDiagramEventHandlers()
9
9
  return (
10
10
  <PanelActionIcon
@@ -17,14 +17,12 @@ export const BurgerButton = () => {
17
17
  }}
18
18
  onClick={e => {
19
19
  e.stopPropagation()
20
- if (onBurgerMenuClick) {
21
- actor.send({ type: 'breadcrumbs.mouseLeave.root' })
20
+ if (onBurgerMenuClick && actor.isOpened()) {
22
21
  setTimeout(() => {
23
22
  onBurgerMenuClick()
24
23
  }, 100)
25
- } else {
26
- actor.send({ type: 'breadcrumbs.click.root' })
27
24
  }
25
+ actor.send({ type: 'breadcrumbs.click.root' })
28
26
  }}
29
27
  children={<IconMenu2 style={{ width: '80%', height: '80%' }} />}
30
28
  />
@@ -14,7 +14,15 @@ export const NavigationButtons = () => {
14
14
  hasStepForward: s.navigationHistory.currentIndex < s.navigationHistory.history.length - 1,
15
15
  }))
16
16
  return (
17
- <m.div layout="position" className={hstack({ gap: 1, mdDown: { display: 'none' } })}>
17
+ <m.div
18
+ layout="position"
19
+ className={hstack({
20
+ gap: '[1px]',
21
+ display: {
22
+ base: 'none',
23
+ '@likec4-root/sm': 'flex',
24
+ },
25
+ })}>
18
26
  <PanelActionIcon
19
27
  disabled={!hasStepBack}
20
28
  onClick={e => {
@@ -21,7 +21,7 @@ export const OpenSource = () => {
21
21
  e.stopPropagation()
22
22
  onOpenSource?.({ view: viewId })
23
23
  }}
24
- children={<IconFileSymlink size={12} stroke={1.5} style={{ width: '65%' }} />}
24
+ children={<IconFileSymlink stroke={1.5} style={{ width: '65%' }} />}
25
25
  />
26
26
  </Tooltip>
27
27
  )
@@ -24,14 +24,15 @@ export function SearchControl() {
24
24
  diagram.openSearch()
25
25
  }}
26
26
  whileTap={{
27
+ scale: 0.95,
27
28
  translateY: 1,
28
29
  }}
29
30
  className={cx(
30
31
  'group',
31
32
  hstack({
32
- gap: '2xs',
33
+ gap: 'xxs',
33
34
  paddingInline: 'sm',
34
- paddingBlock: '2xs',
35
+ paddingBlock: 'xxs',
35
36
  rounded: 'sm',
36
37
  userSelect: 'none',
37
38
  cursor: 'pointer',
@@ -43,8 +44,9 @@ export function SearchControl() {
43
44
  base: 'likec4.panel.action-icon.bg',
44
45
  _hover: 'likec4.panel.action-icon.bg.hover',
45
46
  },
46
- smDown: {
47
- display: 'none',
47
+ display: {
48
+ base: 'none',
49
+ '@/md': 'flex',
48
50
  },
49
51
  }),
50
52
  )}>
@@ -33,9 +33,9 @@ export const ToggleReadonly = () => {
33
33
  className={cx(
34
34
  'group',
35
35
  hstack({
36
- gap: '2',
37
- paddingInline: '2xs',
38
- paddingBlock: '2xs',
36
+ gap: '0.5',
37
+ paddingInline: 'xxs',
38
+ paddingBlock: 'xxs',
39
39
  rounded: 'sm',
40
40
  userSelect: 'none',
41
41
  cursor: 'pointer',