@flowdrop/flowdrop 1.2.2 → 1.4.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.
@@ -6,7 +6,7 @@
6
6
  Approach:
7
7
  1. Compute the full bezier path (xyflow's getBezierPath)
8
8
  2. Parse the SVG path to extract the cubic bezier control points
9
- 3. Evaluate the curve near the end to get the true visual tangent
9
+ 3. Compute exact tangent at endpoint via bezier derivative P'(1) = 3(P3-P2)
10
10
  4. Shorten the path along that tangent and draw the arrowhead at the target
11
11
  -->
12
12
 
@@ -42,32 +42,6 @@
42
42
  return match ? match[1].trim() : "var(--fd-edge-data, #64748b)";
43
43
  });
44
44
 
45
- /**
46
- * Evaluate a cubic bezier at parameter t.
47
- * P(t) = (1-t)^3 * P0 + 3(1-t)^2 * t * P1 + 3(1-t) * t^2 * P2 + t^3 * P3
48
- */
49
- function bezierAt(
50
- p0x: number,
51
- p0y: number,
52
- p1x: number,
53
- p1y: number,
54
- p2x: number,
55
- p2y: number,
56
- p3x: number,
57
- p3y: number,
58
- t: number,
59
- ): { x: number; y: number } {
60
- const u = 1 - t;
61
- const uu = u * u;
62
- const uuu = uu * u;
63
- const tt = t * t;
64
- const ttt = tt * t;
65
- return {
66
- x: uuu * p0x + 3 * uu * t * p1x + 3 * u * tt * p2x + ttt * p3x,
67
- y: uuu * p0y + 3 * uu * t * p1y + 3 * u * tt * p2y + ttt * p3y,
68
- };
69
- }
70
-
71
45
  /**
72
46
  * Parse the SVG cubic bezier path "M x0,y0 C x1,y1 x2,y2 x3,y3"
73
47
  * into the four control points.
@@ -87,9 +61,6 @@
87
61
  };
88
62
  }
89
63
 
90
- // Parameter near the end of the curve for tangent sampling
91
- const T_SAMPLE = 0.9;
92
-
93
64
  let computed = $derived.by(() => {
94
65
  // 1. Get the full bezier path from xyflow
95
66
  const [fullPath, lx, ly] = getBezierPath({
@@ -108,30 +79,18 @@
108
79
  return { path: fullPath, labelX: lx, labelY: ly, angleDeg: 0 };
109
80
  }
110
81
 
111
- // 3. Evaluate the curve at T_SAMPLE to get a reference point
112
- const ref = bezierAt(
113
- cp.p0x,
114
- cp.p0y,
115
- cp.p1x,
116
- cp.p1y,
117
- cp.p2x,
118
- cp.p2y,
119
- cp.p3x,
120
- cp.p3y,
121
- T_SAMPLE,
122
- );
123
-
124
- // 4. Tangent direction: from reference point to the target
125
- const dx = targetX - ref.x;
126
- const dy = targetY - ref.y;
82
+ // 3. Compute exact tangent at curve endpoint using bezier derivative:
83
+ // P'(1) = 3 * (P3 - P2), giving the true arrival direction
84
+ const dx = cp.p3x - cp.p2x;
85
+ const dy = cp.p3y - cp.p2y;
127
86
  const angleDeg = (Math.atan2(dy, dx) * 180) / Math.PI;
128
87
  const angleRad = Math.atan2(dy, dx);
129
88
 
130
- // 5. Shorten: move the endpoint back along the tangent
89
+ // 4. Shorten: move the endpoint back along the tangent
131
90
  const adjX = targetX - Math.cos(angleRad) * ARROW_LENGTH_PX;
132
91
  const adjY = targetY - Math.sin(angleRad) * ARROW_LENGTH_PX;
133
92
 
134
- // 6. Recompute the bezier path with the shortened target
93
+ // 5. Recompute the bezier path with the shortened target
135
94
  const [shortenedPath] = getBezierPath({
136
95
  sourceX,
137
96
  sourceY,
@@ -82,23 +82,23 @@
82
82
 
83
83
  <style>
84
84
  .flowdrop-logo {
85
- --logo-bg: #f9f9f9;
86
- --logo-stroke: #000000;
87
- --logo-line-fill: #000000;
88
- --logo-drop: #009cde;
89
- --logo-circle: #f46351;
90
- --logo-left: #ccbaf4;
91
- --logo-right: #ffc423;
85
+ --logo-bg: var(--fd-logo-bg, #f9f9f9);
86
+ --logo-stroke: var(--fd-logo-stroke, #000000);
87
+ --logo-line-fill: var(--fd-logo-line-fill, #000000);
88
+ --logo-drop: var(--fd-logo-drop, #009cde);
89
+ --logo-circle: var(--fd-logo-circle, #f46351);
90
+ --logo-left: var(--fd-logo-left, #ccbaf4);
91
+ --logo-right: var(--fd-logo-right, #ffc423);
92
92
  }
93
93
 
94
94
  :global([data-theme="dark"]) .flowdrop-logo {
95
- --logo-bg: none;
96
- --logo-stroke: #ffffff;
97
- --logo-line-fill: none;
98
- --logo-drop: none;
99
- --logo-circle: none;
100
- --logo-left: none;
101
- --logo-right: none;
95
+ --logo-bg: var(--fd-logo-bg, none);
96
+ --logo-stroke: var(--fd-logo-stroke, #ffffff);
97
+ --logo-line-fill: var(--fd-logo-line-fill, none);
98
+ --logo-drop: var(--fd-logo-drop, none);
99
+ --logo-circle: var(--fd-logo-circle, none);
100
+ --logo-left: var(--fd-logo-left, none);
101
+ --logo-right: var(--fd-logo-right, none);
102
102
  }
103
103
 
104
104
  .flowdrop-logo :global(svg) {
@@ -10,6 +10,7 @@
10
10
  import Icon from "@iconify/svelte";
11
11
  import Logo from "./Logo.svelte";
12
12
  import SettingsModal from "./SettingsModal.svelte";
13
+ import type { SettingsCategory } from "../types/settings.js";
13
14
 
14
15
  interface NavbarAction {
15
16
  label: string;
@@ -38,6 +39,12 @@
38
39
  breadcrumbs?: BreadcrumbItem[];
39
40
  /** Show settings gear icon */
40
41
  showSettings?: boolean;
42
+ /** Which settings tabs to show in the modal */
43
+ settingsCategories?: SettingsCategory[];
44
+ /** Show the "Sync to Cloud" button in the settings modal */
45
+ showSettingsSyncButton?: boolean;
46
+ /** Show the reset buttons in the settings modal */
47
+ showSettingsResetButton?: boolean;
41
48
  }
42
49
 
43
50
  let {
@@ -46,6 +53,9 @@
46
53
  title,
47
54
  breadcrumbs = [],
48
55
  showSettings = true,
56
+ settingsCategories,
57
+ showSettingsSyncButton,
58
+ showSettingsResetButton,
49
59
  }: Props = $props();
50
60
 
51
61
  // Dropdown state
@@ -263,7 +273,16 @@
263
273
 
264
274
  <!-- Settings Modal -->
265
275
  {#if showSettings}
266
- <SettingsModal bind:open={isSettingsOpen} />
276
+ {@const settingsModalProps = {
277
+ ...(settingsCategories !== undefined && { categories: settingsCategories }),
278
+ ...(showSettingsSyncButton !== undefined && {
279
+ showSyncButton: showSettingsSyncButton,
280
+ }),
281
+ ...(showSettingsResetButton !== undefined && {
282
+ showResetButton: showSettingsResetButton,
283
+ }),
284
+ }}
285
+ <SettingsModal bind:open={isSettingsOpen} {...settingsModalProps} />
267
286
  {/if}
268
287
 
269
288
  <style>
@@ -739,16 +758,50 @@
739
758
  }
740
759
 
741
760
  .flowdrop-navbar__start {
742
- width: 280px;
743
- min-width: 280px;
761
+ width: auto;
762
+ min-width: auto;
763
+ flex-shrink: 0;
744
764
  }
745
765
 
746
- .flowdrop-navbar__actions {
766
+ .flowdrop-navbar__center {
767
+ min-width: 0;
768
+ overflow: hidden;
769
+ }
770
+
771
+ .flowdrop-navbar__breadcrumb-list {
772
+ overflow: hidden;
773
+ }
774
+
775
+ /* Show only icons for non-current breadcrumb items */
776
+ .flowdrop-navbar__breadcrumb-link .flowdrop-navbar__breadcrumb-text {
777
+ display: none;
778
+ }
779
+
780
+ .flowdrop-navbar__breadcrumb-current .flowdrop-navbar__breadcrumb-text {
781
+ overflow: hidden;
782
+ text-overflow: ellipsis;
783
+ }
784
+
785
+ /* Force dropdown mode on small screens regardless of theme */
786
+ .flowdrop-navbar__split-actions {
787
+ display: none;
788
+ }
789
+
790
+ .flowdrop-navbar__dropdown-mode {
791
+ display: flex;
792
+ }
793
+
794
+ .flowdrop-navbar__action-label {
747
795
  display: none;
748
796
  }
749
797
 
798
+ .flowdrop-navbar__primary-action {
799
+ padding: 0.5rem;
800
+ border-radius: var(--fd-radius-md) 0 0 var(--fd-radius-md);
801
+ }
802
+
750
803
  .flowdrop-text--logo {
751
- font-size: 1rem;
804
+ display: none;
752
805
  }
753
806
 
754
807
  .flowdrop-text--tagline {
@@ -767,11 +820,6 @@
767
820
  }
768
821
 
769
822
  @media (max-width: 480px) {
770
- .flowdrop-navbar__start {
771
- width: 240px;
772
- min-width: 240px;
773
- }
774
-
775
823
  .flowdrop-navbar__title-text {
776
824
  font-size: 0.75rem;
777
825
  max-width: 200px;
@@ -1,3 +1,4 @@
1
+ import type { SettingsCategory } from "../types/settings.js";
1
2
  interface NavbarAction {
2
3
  label: string;
3
4
  href: string;
@@ -23,6 +24,12 @@ interface Props {
23
24
  breadcrumbs?: BreadcrumbItem[];
24
25
  /** Show settings gear icon */
25
26
  showSettings?: boolean;
27
+ /** Which settings tabs to show in the modal */
28
+ settingsCategories?: SettingsCategory[];
29
+ /** Show the "Sync to Cloud" button in the settings modal */
30
+ showSettingsSyncButton?: boolean;
31
+ /** Show the reset buttons in the settings modal */
32
+ showSettingsResetButton?: boolean;
26
33
  }
27
34
  declare const Navbar: import("svelte").Component<Props, {}, "">;
28
35
  type Navbar = ReturnType<typeof Navbar>;