@devfellowship/components 1.2.3 → 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.
package/dist/index.js CHANGED
@@ -4751,10 +4751,434 @@ function AppNavbar({
4751
4751
  );
4752
4752
  }
4753
4753
 
4754
- // src/components/organisms/PublishDrawer.tsx
4754
+ // src/components/organisms/Gantt.tsx
4755
4755
  import * as React44 from "react";
4756
- import { Loader2, Youtube, Image as ImageIcon, CheckCircle2, AlertCircle } from "lucide-react";
4757
4756
  import { jsx as jsx63, jsxs as jsxs31 } from "react/jsx-runtime";
4757
+ var DEFAULT_NAME_COL_WIDTH = 320;
4758
+ function resolveNameColWidth(nameColWidth, labelWidth) {
4759
+ if (typeof nameColWidth === "number" && nameColWidth > 0) return Math.round(nameColWidth);
4760
+ if (typeof labelWidth === "number" && labelWidth > 0) return Math.round(labelWidth);
4761
+ return DEFAULT_NAME_COL_WIDTH;
4762
+ }
4763
+ function clampPct(value) {
4764
+ if (value == null || Number.isNaN(value)) return 0;
4765
+ return Math.max(0, Math.min(100, Math.round(value)));
4766
+ }
4767
+ function stageProgress(stage) {
4768
+ if (stage.progress != null) return clampPct(stage.progress);
4769
+ const ms = stage.milestones ?? [];
4770
+ if (ms.length === 0) return 0;
4771
+ const done = ms.filter((m) => m.done).length;
4772
+ return clampPct(done / ms.length * 100);
4773
+ }
4774
+ function resolveWeekCount(stages, weeks) {
4775
+ if (Array.isArray(weeks)) return Math.max(1, weeks.length);
4776
+ if (typeof weeks === "number" && weeks > 0) return Math.round(weeks);
4777
+ let max = 1;
4778
+ for (const s of stages) {
4779
+ max = Math.max(max, s.weekStart + Math.max(1, s.weekSpan) - 1);
4780
+ for (const m of s.milestones ?? []) {
4781
+ const ws = m.weekStart ?? s.weekStart;
4782
+ max = Math.max(max, ws + Math.max(1, m.weekSpan ?? 1) - 1);
4783
+ }
4784
+ }
4785
+ return Math.max(1, max);
4786
+ }
4787
+ function resolveWeekLabels(count2, weeks) {
4788
+ if (Array.isArray(weeks)) return weeks;
4789
+ return Array.from({ length: count2 }, (_, i) => `W${i + 1}`);
4790
+ }
4791
+ function barGridColumn(weekStart, weekSpan, weekCount) {
4792
+ const start = Math.max(1, Math.min(weekStart, weekCount));
4793
+ const rawEnd = start + Math.max(1, weekSpan) - 1;
4794
+ const end = Math.max(start, Math.min(rawEnd, weekCount));
4795
+ return { start, span: end - start + 1 };
4796
+ }
4797
+ var DEFAULT_DOT = "var(--s-brand-solid, #E07A4A)";
4798
+ function Gantt({
4799
+ stages,
4800
+ weeks,
4801
+ dependencies = [],
4802
+ rowsHeader = "Stage / Task",
4803
+ stagesOnly = false,
4804
+ header,
4805
+ labelWidth,
4806
+ nameColWidth,
4807
+ weekMinWidth = 64,
4808
+ className,
4809
+ style,
4810
+ ...rest
4811
+ }) {
4812
+ const weekCount = resolveWeekCount(stages, weeks);
4813
+ const weekLabels = resolveWeekLabels(weekCount, weeks);
4814
+ const nameWidth = resolveNameColWidth(nameColWidth, labelWidth);
4815
+ const [collapsed, setCollapsed] = React44.useState(
4816
+ () => Object.fromEntries(stages.filter((s) => s.collapsed).map((s) => [s.id, true]))
4817
+ );
4818
+ const toggle = (id) => setCollapsed((c) => ({ ...c, [id]: !c[id] }));
4819
+ const gridRef = React44.useRef(null);
4820
+ const barRefs = React44.useRef({});
4821
+ const [edges, setEdges] = React44.useState([]);
4822
+ const recomputeEdges = React44.useCallback(() => {
4823
+ const root = gridRef.current;
4824
+ if (!root || dependencies.length === 0) {
4825
+ setEdges([]);
4826
+ return;
4827
+ }
4828
+ const rootBox = root.getBoundingClientRect();
4829
+ const next = [];
4830
+ for (const dep of dependencies) {
4831
+ const a = barRefs.current[dep.from];
4832
+ const b = barRefs.current[dep.to];
4833
+ if (!a || !b) continue;
4834
+ const ab = a.getBoundingClientRect();
4835
+ const bb = b.getBoundingClientRect();
4836
+ next.push({
4837
+ id: `${dep.from}->${dep.to}`,
4838
+ x1: ab.right - rootBox.left,
4839
+ y1: ab.top - rootBox.top + ab.height / 2,
4840
+ x2: bb.left - rootBox.left,
4841
+ y2: bb.top - rootBox.top + bb.height / 2
4842
+ });
4843
+ }
4844
+ setEdges(next);
4845
+ }, [dependencies]);
4846
+ React44.useLayoutEffect(() => {
4847
+ recomputeEdges();
4848
+ }, [recomputeEdges, collapsed, weekCount, stages]);
4849
+ React44.useEffect(() => {
4850
+ if (dependencies.length === 0) return;
4851
+ const handler = () => recomputeEdges();
4852
+ window.addEventListener("resize", handler);
4853
+ return () => window.removeEventListener("resize", handler);
4854
+ }, [dependencies.length, recomputeEdges]);
4855
+ const trackTemplate = `${nameWidth}px repeat(${weekCount}, minmax(${weekMinWidth}px, 1fr))`;
4856
+ const stickyCol = "sticky left-0 z-20 after:absolute after:inset-y-0 after:right-0 after:w-px after:bg-[var(--s-border-subtle,#2A2622)]";
4857
+ return /* @__PURE__ */ jsxs31(
4858
+ "div",
4859
+ {
4860
+ className: cn(
4861
+ "dfl-gantt rounded-[var(--c-card-radius,10px)] border border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-panel,#141210)] text-[var(--s-ink-primary,#F6F1E7)] overflow-hidden",
4862
+ className
4863
+ ),
4864
+ style,
4865
+ ...rest,
4866
+ children: [
4867
+ header && /* @__PURE__ */ jsx63("div", { className: "border-b border-[var(--s-border-subtle,#2A2622)] px-5 py-4", children: header }),
4868
+ /* @__PURE__ */ jsx63("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs31("div", { ref: gridRef, className: "relative min-w-max", children: [
4869
+ edges.length > 0 && /* @__PURE__ */ jsxs31(
4870
+ "svg",
4871
+ {
4872
+ className: "pointer-events-none absolute inset-0 h-full w-full",
4873
+ "aria-hidden": "true",
4874
+ children: [
4875
+ /* @__PURE__ */ jsx63("defs", { children: /* @__PURE__ */ jsx63(
4876
+ "marker",
4877
+ {
4878
+ id: "dfl-gantt-arrow",
4879
+ markerWidth: "7",
4880
+ markerHeight: "7",
4881
+ refX: "5",
4882
+ refY: "3",
4883
+ orient: "auto",
4884
+ children: /* @__PURE__ */ jsx63(
4885
+ "path",
4886
+ {
4887
+ d: "M0,0 L6,3 L0,6 Z",
4888
+ fill: "var(--s-brand-solid, #E07A4A)"
4889
+ }
4890
+ )
4891
+ }
4892
+ ) }),
4893
+ edges.map((e) => {
4894
+ const stub = 14;
4895
+ const c1x = e.x1 + stub;
4896
+ const c2x = e.x2 - stub;
4897
+ return /* @__PURE__ */ jsx63(
4898
+ "path",
4899
+ {
4900
+ d: `M ${e.x1} ${e.y1} C ${c1x} ${e.y1}, ${c2x} ${e.y2}, ${e.x2} ${e.y2}`,
4901
+ fill: "none",
4902
+ stroke: "var(--s-brand-solid, #E07A4A)",
4903
+ strokeWidth: 1.5,
4904
+ strokeOpacity: 0.65,
4905
+ markerEnd: "url(#dfl-gantt-arrow)"
4906
+ },
4907
+ e.id
4908
+ );
4909
+ })
4910
+ ]
4911
+ }
4912
+ ),
4913
+ /* @__PURE__ */ jsxs31(
4914
+ "div",
4915
+ {
4916
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-raised,#1A1714)]",
4917
+ style: { gridTemplateColumns: trackTemplate },
4918
+ children: [
4919
+ /* @__PURE__ */ jsx63(
4920
+ "div",
4921
+ {
4922
+ className: cn(
4923
+ stickyCol,
4924
+ "bg-[var(--s-surface-raised,#1A1714)] px-4 py-2.5 font-[var(--s-font-mono,monospace)] text-[10.5px] font-medium uppercase tracking-[0.6px] text-[var(--s-ink-muted,#7D7568)]"
4925
+ ),
4926
+ children: rowsHeader
4927
+ }
4928
+ ),
4929
+ weekLabels.map((label, i) => /* @__PURE__ */ jsx63(
4930
+ "div",
4931
+ {
4932
+ className: "border-l border-[var(--s-border-subtle,#2A2622)] py-2.5 text-center font-[var(--s-font-mono,monospace)] text-[11px] tabular-nums text-[var(--s-ink-muted,#7D7568)]",
4933
+ children: label
4934
+ },
4935
+ i
4936
+ ))
4937
+ ]
4938
+ }
4939
+ ),
4940
+ stages.map((stage) => {
4941
+ const pct = stageProgress(stage);
4942
+ const dot = stage.color || DEFAULT_DOT;
4943
+ const isCollapsed = !!collapsed[stage.id];
4944
+ const ms = stage.milestones ?? [];
4945
+ const done = ms.filter((m) => m.done).length;
4946
+ const sCol = barGridColumn(stage.weekStart, stage.weekSpan, weekCount);
4947
+ return /* @__PURE__ */ jsxs31(React44.Fragment, { children: [
4948
+ /* @__PURE__ */ jsxs31(
4949
+ "div",
4950
+ {
4951
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)]",
4952
+ style: { gridTemplateColumns: trackTemplate },
4953
+ children: [
4954
+ /* @__PURE__ */ jsxs31(
4955
+ "button",
4956
+ {
4957
+ type: "button",
4958
+ onClick: () => toggle(stage.id),
4959
+ className: cn(
4960
+ stickyCol,
4961
+ "flex items-center gap-2 bg-[var(--s-surface-panel,#141210)] px-4 py-3 text-left transition-colors hover:bg-[var(--s-surface-raised,#1A1714)]"
4962
+ ),
4963
+ "aria-expanded": !isCollapsed,
4964
+ children: [
4965
+ /* @__PURE__ */ jsx63(Chevron, { open: !isCollapsed }),
4966
+ /* @__PURE__ */ jsx63(
4967
+ "span",
4968
+ {
4969
+ className: "h-2.5 w-2.5 shrink-0 rounded-full",
4970
+ style: { background: dot }
4971
+ }
4972
+ ),
4973
+ /* @__PURE__ */ jsxs31("span", { className: "min-w-0", children: [
4974
+ /* @__PURE__ */ jsx63(
4975
+ "span",
4976
+ {
4977
+ className: "block truncate text-[13px] font-semibold text-[var(--s-ink-primary,#F6F1E7)]",
4978
+ title: stage.title,
4979
+ children: stage.title
4980
+ }
4981
+ ),
4982
+ stage.subtitle && /* @__PURE__ */ jsx63(
4983
+ "span",
4984
+ {
4985
+ className: "block truncate text-[11px] text-[var(--s-ink-muted,#7D7568)]",
4986
+ title: stage.subtitle,
4987
+ children: stage.subtitle
4988
+ }
4989
+ )
4990
+ ] }),
4991
+ ms.length > 0 && /* @__PURE__ */ jsxs31("span", { className: "ml-auto shrink-0 rounded-[var(--c-badge-radius,4px)] bg-[var(--s-surface-elevated,#1F1C18)] px-1.5 py-0.5 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-secondary,#C9C0B4)]", children: [
4992
+ done,
4993
+ "/",
4994
+ ms.length
4995
+ ] })
4996
+ ]
4997
+ }
4998
+ ),
4999
+ /* @__PURE__ */ jsx63(
5000
+ "div",
5001
+ {
5002
+ className: "relative h-9",
5003
+ style: {
5004
+ gridColumn: `${1 + sCol.start} / span ${sCol.span}`
5005
+ },
5006
+ children: /* @__PURE__ */ jsxs31(
5007
+ "div",
5008
+ {
5009
+ ref: (el) => {
5010
+ barRefs.current[stage.id] = el;
5011
+ },
5012
+ className: "absolute inset-y-2 inset-x-1 overflow-hidden rounded-[var(--p-radius-sm,4px)]",
5013
+ style: { background: tint(dot, 0.16) },
5014
+ title: `${stage.title} \xB7 ${pct}%`,
5015
+ children: [
5016
+ /* @__PURE__ */ jsx63(
5017
+ "div",
5018
+ {
5019
+ className: "h-full rounded-[var(--p-radius-sm,4px)]",
5020
+ style: { width: `${pct}%`, background: dot }
5021
+ }
5022
+ ),
5023
+ /* @__PURE__ */ jsxs31("span", { className: "absolute inset-0 flex items-center px-2 font-[var(--s-font-mono,monospace)] text-[10.5px] font-medium tabular-nums text-[var(--s-ink-primary,#F6F1E7)]", children: [
5024
+ pct,
5025
+ "%"
5026
+ ] })
5027
+ ]
5028
+ }
5029
+ )
5030
+ }
5031
+ )
5032
+ ]
5033
+ }
5034
+ ),
5035
+ !stagesOnly && !isCollapsed && ms.map((m) => {
5036
+ const mStart = m.weekStart ?? stage.weekStart;
5037
+ const mCol = barGridColumn(
5038
+ mStart,
5039
+ m.weekSpan ?? 1,
5040
+ weekCount
5041
+ );
5042
+ return /* @__PURE__ */ jsxs31(
5043
+ "div",
5044
+ {
5045
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-page,#0A0908)]",
5046
+ style: { gridTemplateColumns: trackTemplate },
5047
+ children: [
5048
+ /* @__PURE__ */ jsxs31(
5049
+ "div",
5050
+ {
5051
+ className: cn(
5052
+ stickyCol,
5053
+ "flex items-center gap-2 bg-[var(--s-surface-page,#0A0908)] py-2 pl-10 pr-4"
5054
+ ),
5055
+ children: [
5056
+ /* @__PURE__ */ jsx63(StatusDot, { done: m.done, color: dot }),
5057
+ /* @__PURE__ */ jsx63(
5058
+ "span",
5059
+ {
5060
+ className: cn(
5061
+ "min-w-0 flex-1 truncate text-[13px]",
5062
+ m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5063
+ ),
5064
+ title: m.title,
5065
+ children: m.title
5066
+ }
5067
+ ),
5068
+ m.points != null && /* @__PURE__ */ jsx63("span", { className: "shrink-0 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-muted,#7D7568)]", children: m.points })
5069
+ ]
5070
+ }
5071
+ ),
5072
+ /* @__PURE__ */ jsx63(
5073
+ "div",
5074
+ {
5075
+ className: "relative h-6",
5076
+ style: {
5077
+ gridColumn: `${1 + mCol.start} / span ${mCol.span}`
5078
+ },
5079
+ children: /* @__PURE__ */ jsx63(
5080
+ "div",
5081
+ {
5082
+ className: cn(
5083
+ "absolute inset-y-1.5 inset-x-1 rounded-[var(--p-radius-sm,4px)]",
5084
+ m.done ? "" : "border"
5085
+ ),
5086
+ style: m.done ? { background: dot } : {
5087
+ background: tint(dot, 0.08),
5088
+ borderColor: tint(dot, 0.4)
5089
+ }
5090
+ }
5091
+ )
5092
+ }
5093
+ )
5094
+ ]
5095
+ },
5096
+ m.id
5097
+ );
5098
+ })
5099
+ ] }, stage.id);
5100
+ }),
5101
+ stages.length === 0 && /* @__PURE__ */ jsx63("div", { className: "px-4 py-8 text-center text-[13px] text-[var(--s-ink-muted,#7D7568)]", children: "No stages yet." })
5102
+ ] }) }),
5103
+ /* @__PURE__ */ jsxs31("div", { className: "flex flex-wrap items-center gap-4 border-t border-[var(--s-border-subtle,#2A2622)] px-5 py-2.5 font-[var(--s-font-mono,monospace)] text-[10.5px] uppercase tracking-[0.6px] text-[var(--s-ink-muted,#7D7568)]", children: [
5104
+ /* @__PURE__ */ jsx63(LegendItem, { swatch: /* @__PURE__ */ jsx63("span", { className: "h-2.5 w-3 rounded-[2px]", style: { background: "var(--s-brand-solid, #E07A4A)" } }), label: "Completed" }),
5105
+ /* @__PURE__ */ jsx63(LegendItem, { swatch: /* @__PURE__ */ jsx63("span", { className: "h-2.5 w-3 rounded-[2px] border", style: { background: "rgba(224,122,74,0.08)", borderColor: "rgba(224,122,74,0.4)" } }), label: "Upcoming" }),
5106
+ dependencies.length > 0 && /* @__PURE__ */ jsx63(LegendItem, { swatch: /* @__PURE__ */ jsx63("span", { className: "block h-0.5 w-4", style: { background: "var(--s-brand-solid, #E07A4A)", opacity: 0.7 } }), label: "Depends on" })
5107
+ ] })
5108
+ ]
5109
+ }
5110
+ );
5111
+ }
5112
+ function Chevron({ open }) {
5113
+ return /* @__PURE__ */ jsx63(
5114
+ "svg",
5115
+ {
5116
+ width: "14",
5117
+ height: "14",
5118
+ viewBox: "0 0 24 24",
5119
+ fill: "none",
5120
+ stroke: "currentColor",
5121
+ strokeWidth: "1.5",
5122
+ strokeLinecap: "round",
5123
+ strokeLinejoin: "round",
5124
+ className: "shrink-0 text-[var(--s-ink-muted,#7D7568)] transition-transform",
5125
+ style: { transform: open ? "rotate(90deg)" : "none" },
5126
+ "aria-hidden": "true",
5127
+ children: /* @__PURE__ */ jsx63("path", { d: "M9 18l6-6-6-6" })
5128
+ }
5129
+ );
5130
+ }
5131
+ function StatusDot({ done, color }) {
5132
+ if (done) {
5133
+ return /* @__PURE__ */ jsxs31("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
5134
+ /* @__PURE__ */ jsx63("circle", { cx: "12", cy: "12", r: "9", fill: color }),
5135
+ /* @__PURE__ */ jsx63(
5136
+ "path",
5137
+ {
5138
+ d: "M8 12l3 3 5-6",
5139
+ fill: "none",
5140
+ stroke: "var(--s-ink-inverse, #0A0908)",
5141
+ strokeWidth: "2",
5142
+ strokeLinecap: "round",
5143
+ strokeLinejoin: "round"
5144
+ }
5145
+ )
5146
+ ] });
5147
+ }
5148
+ return /* @__PURE__ */ jsx63("svg", { width: "14", height: "14", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx63(
5149
+ "circle",
5150
+ {
5151
+ cx: "12",
5152
+ cy: "12",
5153
+ r: "8",
5154
+ fill: "none",
5155
+ stroke: "var(--s-border-strong, #3A3530)",
5156
+ strokeWidth: "2"
5157
+ }
5158
+ ) });
5159
+ }
5160
+ function LegendItem({ swatch, label }) {
5161
+ return /* @__PURE__ */ jsxs31("span", { className: "flex items-center gap-1.5", children: [
5162
+ swatch,
5163
+ label
5164
+ ] });
5165
+ }
5166
+ function tint(color, alpha) {
5167
+ const hex = /^#([0-9a-f]{6})$/i.exec(color.trim());
5168
+ if (hex) {
5169
+ const n = parseInt(hex[1], 16);
5170
+ const r = n >> 16 & 255;
5171
+ const g = n >> 8 & 255;
5172
+ const b = n & 255;
5173
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
5174
+ }
5175
+ return `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent)`;
5176
+ }
5177
+
5178
+ // src/components/organisms/PublishDrawer.tsx
5179
+ import * as React45 from "react";
5180
+ import { Loader2, Youtube, Image as ImageIcon, CheckCircle2, AlertCircle } from "lucide-react";
5181
+ import { jsx as jsx64, jsxs as jsxs32 } from "react/jsx-runtime";
4758
5182
  function parseTags(raw) {
4759
5183
  return raw.split(/[,\n]/).map((t) => t.trim()).filter((t) => t.length > 0);
4760
5184
  }
@@ -4790,16 +5214,16 @@ function PublishDrawer({
4790
5214
  onError,
4791
5215
  className
4792
5216
  }) {
4793
- const [title, setTitle] = React44.useState(suggestedTitle);
4794
- const [description, setDescription] = React44.useState(suggestedDescription);
4795
- const [tagsRaw, setTagsRaw] = React44.useState("");
4796
- const [thumbnailUrl, setThumbnailUrl] = React44.useState(suggestedThumbnailUrl);
4797
- const [accounts, setAccounts] = React44.useState([]);
4798
- const [accountId, setAccountId] = React44.useState(null);
4799
- const [status, setStatus] = React44.useState("idle");
4800
- const [errorMsg, setErrorMsg] = React44.useState(null);
4801
- const [result, setResult] = React44.useState(null);
4802
- React44.useEffect(() => {
5217
+ const [title, setTitle] = React45.useState(suggestedTitle);
5218
+ const [description, setDescription] = React45.useState(suggestedDescription);
5219
+ const [tagsRaw, setTagsRaw] = React45.useState("");
5220
+ const [thumbnailUrl, setThumbnailUrl] = React45.useState(suggestedThumbnailUrl);
5221
+ const [accounts, setAccounts] = React45.useState([]);
5222
+ const [accountId, setAccountId] = React45.useState(null);
5223
+ const [status, setStatus] = React45.useState("idle");
5224
+ const [errorMsg, setErrorMsg] = React45.useState(null);
5225
+ const [result, setResult] = React45.useState(null);
5226
+ React45.useEffect(() => {
4803
5227
  if (open) {
4804
5228
  setTitle(suggestedTitle);
4805
5229
  setDescription(suggestedDescription);
@@ -4809,7 +5233,7 @@ function PublishDrawer({
4809
5233
  setResult(null);
4810
5234
  }
4811
5235
  }, [open]);
4812
- React44.useEffect(() => {
5236
+ React45.useEffect(() => {
4813
5237
  if (!open) return;
4814
5238
  let cancelled = false;
4815
5239
  (async () => {
@@ -4833,7 +5257,7 @@ function PublishDrawer({
4833
5257
  cancelled = true;
4834
5258
  };
4835
5259
  }, [open, supabase]);
4836
- const fail = React44.useCallback(
5260
+ const fail = React45.useCallback(
4837
5261
  (msg) => {
4838
5262
  setStatus("error");
4839
5263
  setErrorMsg(msg);
@@ -4935,18 +5359,18 @@ function PublishDrawer({
4935
5359
  onPublished?.(publishResult);
4936
5360
  }
4937
5361
  const busy = status === "publishing" || status === "rendering-thumb" || status === "loading-accounts";
4938
- return /* @__PURE__ */ jsx63(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs31(SheetContent, { side: "right", className: cn("flex w-full flex-col gap-4 overflow-y-auto sm:max-w-md", className), children: [
4939
- /* @__PURE__ */ jsxs31(SheetHeader, { children: [
4940
- /* @__PURE__ */ jsxs31(SheetTitle, { className: "flex items-center gap-2", children: [
4941
- /* @__PURE__ */ jsx63(Youtube, { className: "h-5 w-5 text-red-600" }),
5362
+ return /* @__PURE__ */ jsx64(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs32(SheetContent, { side: "right", className: cn("flex w-full flex-col gap-4 overflow-y-auto sm:max-w-md", className), children: [
5363
+ /* @__PURE__ */ jsxs32(SheetHeader, { children: [
5364
+ /* @__PURE__ */ jsxs32(SheetTitle, { className: "flex items-center gap-2", children: [
5365
+ /* @__PURE__ */ jsx64(Youtube, { className: "h-5 w-5 text-red-600" }),
4942
5366
  "Publicar no YouTube"
4943
5367
  ] }),
4944
- /* @__PURE__ */ jsx63(SheetDescription, { children: "Publique o v\xEDdeo gravado cross-platform via Zernio. Preencha t\xEDtulo, descri\xE7\xE3o e palavras-chave manualmente." })
5368
+ /* @__PURE__ */ jsx64(SheetDescription, { children: "Publique o v\xEDdeo gravado cross-platform via Zernio. Preencha t\xEDtulo, descri\xE7\xE3o e palavras-chave manualmente." })
4945
5369
  ] }),
4946
- status === "done" && result ? /* @__PURE__ */ jsxs31("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-center", children: [
4947
- /* @__PURE__ */ jsx63(CheckCircle2, { className: "h-10 w-10 text-green-600" }),
4948
- /* @__PURE__ */ jsx63("p", { className: "font-medium", children: "V\xEDdeo publicado!" }),
4949
- result.post_url && /* @__PURE__ */ jsx63(
5370
+ status === "done" && result ? /* @__PURE__ */ jsxs32("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-center", children: [
5371
+ /* @__PURE__ */ jsx64(CheckCircle2, { className: "h-10 w-10 text-green-600" }),
5372
+ /* @__PURE__ */ jsx64("p", { className: "font-medium", children: "V\xEDdeo publicado!" }),
5373
+ result.post_url && /* @__PURE__ */ jsx64(
4950
5374
  "a",
4951
5375
  {
4952
5376
  href: result.post_url,
@@ -4956,15 +5380,15 @@ function PublishDrawer({
4956
5380
  children: "Abrir no YouTube"
4957
5381
  }
4958
5382
  ),
4959
- /* @__PURE__ */ jsxs31("p", { className: "text-xs text-muted-foreground", children: [
5383
+ /* @__PURE__ */ jsxs32("p", { className: "text-xs text-muted-foreground", children: [
4960
5384
  "Zernio post id: ",
4961
5385
  result.zernio_post_id
4962
5386
  ] }),
4963
- /* @__PURE__ */ jsx63(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Fechar" })
4964
- ] }) : /* @__PURE__ */ jsxs31("div", { className: "flex flex-1 flex-col gap-4", children: [
4965
- /* @__PURE__ */ jsxs31("div", { className: "grid gap-2", children: [
4966
- /* @__PURE__ */ jsx63(Label3, { htmlFor: "pd-title", children: "T\xEDtulo" }),
4967
- /* @__PURE__ */ jsx63(
5387
+ /* @__PURE__ */ jsx64(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Fechar" })
5388
+ ] }) : /* @__PURE__ */ jsxs32("div", { className: "flex flex-1 flex-col gap-4", children: [
5389
+ /* @__PURE__ */ jsxs32("div", { className: "grid gap-2", children: [
5390
+ /* @__PURE__ */ jsx64(Label3, { htmlFor: "pd-title", children: "T\xEDtulo" }),
5391
+ /* @__PURE__ */ jsx64(
4968
5392
  Input,
4969
5393
  {
4970
5394
  id: "pd-title",
@@ -4975,9 +5399,9 @@ function PublishDrawer({
4975
5399
  }
4976
5400
  )
4977
5401
  ] }),
4978
- /* @__PURE__ */ jsxs31("div", { className: "grid gap-2", children: [
4979
- /* @__PURE__ */ jsx63(Label3, { htmlFor: "pd-desc", children: "Descri\xE7\xE3o" }),
4980
- /* @__PURE__ */ jsx63(
5402
+ /* @__PURE__ */ jsxs32("div", { className: "grid gap-2", children: [
5403
+ /* @__PURE__ */ jsx64(Label3, { htmlFor: "pd-desc", children: "Descri\xE7\xE3o" }),
5404
+ /* @__PURE__ */ jsx64(
4981
5405
  Textarea,
4982
5406
  {
4983
5407
  id: "pd-desc",
@@ -4989,9 +5413,9 @@ function PublishDrawer({
4989
5413
  }
4990
5414
  )
4991
5415
  ] }),
4992
- /* @__PURE__ */ jsxs31("div", { className: "grid gap-2", children: [
4993
- /* @__PURE__ */ jsx63(Label3, { htmlFor: "pd-tags", children: "Palavras-chave / tags" }),
4994
- /* @__PURE__ */ jsx63(
5416
+ /* @__PURE__ */ jsxs32("div", { className: "grid gap-2", children: [
5417
+ /* @__PURE__ */ jsx64(Label3, { htmlFor: "pd-tags", children: "Palavras-chave / tags" }),
5418
+ /* @__PURE__ */ jsx64(
4995
5419
  Input,
4996
5420
  {
4997
5421
  id: "pd-tags",
@@ -5001,11 +5425,11 @@ function PublishDrawer({
5001
5425
  disabled: busy
5002
5426
  }
5003
5427
  ),
5004
- /* @__PURE__ */ jsx63("p", { className: "text-xs text-muted-foreground", children: "Separadas por v\xEDrgula. A primeira vira a keyword." })
5428
+ /* @__PURE__ */ jsx64("p", { className: "text-xs text-muted-foreground", children: "Separadas por v\xEDrgula. A primeira vira a keyword." })
5005
5429
  ] }),
5006
- /* @__PURE__ */ jsxs31("div", { className: "grid gap-2", children: [
5007
- /* @__PURE__ */ jsx63(Label3, { htmlFor: "pd-thumb", children: "Thumbnail" }),
5008
- /* @__PURE__ */ jsx63(
5430
+ /* @__PURE__ */ jsxs32("div", { className: "grid gap-2", children: [
5431
+ /* @__PURE__ */ jsx64(Label3, { htmlFor: "pd-thumb", children: "Thumbnail" }),
5432
+ /* @__PURE__ */ jsx64(
5009
5433
  Input,
5010
5434
  {
5011
5435
  id: "pd-thumb",
@@ -5015,7 +5439,7 @@ function PublishDrawer({
5015
5439
  disabled: busy
5016
5440
  }
5017
5441
  ),
5018
- thumbnailTemplateId && /* @__PURE__ */ jsxs31(
5442
+ thumbnailTemplateId && /* @__PURE__ */ jsxs32(
5019
5443
  Button,
5020
5444
  {
5021
5445
  type: "button",
@@ -5025,12 +5449,12 @@ function PublishDrawer({
5025
5449
  disabled: busy,
5026
5450
  className: "w-fit",
5027
5451
  children: [
5028
- status === "rendering-thumb" ? /* @__PURE__ */ jsx63(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx63(ImageIcon, { className: "mr-2 h-4 w-4" }),
5452
+ status === "rendering-thumb" ? /* @__PURE__ */ jsx64(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx64(ImageIcon, { className: "mr-2 h-4 w-4" }),
5029
5453
  "Gerar via Thumbify"
5030
5454
  ]
5031
5455
  }
5032
5456
  ),
5033
- thumbnailUrl && /* @__PURE__ */ jsx63(
5457
+ thumbnailUrl && /* @__PURE__ */ jsx64(
5034
5458
  "img",
5035
5459
  {
5036
5460
  src: thumbnailUrl,
@@ -5039,26 +5463,26 @@ function PublishDrawer({
5039
5463
  }
5040
5464
  )
5041
5465
  ] }),
5042
- /* @__PURE__ */ jsxs31("div", { className: "grid gap-2", children: [
5043
- /* @__PURE__ */ jsx63(Label3, { htmlFor: "pd-account", children: "Canal do YouTube" }),
5044
- /* @__PURE__ */ jsxs31(Select, { value: accountId ?? void 0, onValueChange: setAccountId, disabled: busy || accounts.length === 0, children: [
5045
- /* @__PURE__ */ jsx63(SelectTrigger, { id: "pd-account", children: /* @__PURE__ */ jsx63(
5466
+ /* @__PURE__ */ jsxs32("div", { className: "grid gap-2", children: [
5467
+ /* @__PURE__ */ jsx64(Label3, { htmlFor: "pd-account", children: "Canal do YouTube" }),
5468
+ /* @__PURE__ */ jsxs32(Select, { value: accountId ?? void 0, onValueChange: setAccountId, disabled: busy || accounts.length === 0, children: [
5469
+ /* @__PURE__ */ jsx64(SelectTrigger, { id: "pd-account", children: /* @__PURE__ */ jsx64(
5046
5470
  SelectValue,
5047
5471
  {
5048
5472
  placeholder: status === "loading-accounts" ? "Carregando canais\u2026" : accounts.length === 0 ? "Nenhum canal conectado" : "Selecione um canal"
5049
5473
  }
5050
5474
  ) }),
5051
- /* @__PURE__ */ jsx63(SelectContent, { children: accounts.map((a) => /* @__PURE__ */ jsx63(SelectItem, { value: a.account_id, children: a.account_name ?? a.account_id }, a.id)) })
5475
+ /* @__PURE__ */ jsx64(SelectContent, { children: accounts.map((a) => /* @__PURE__ */ jsx64(SelectItem, { value: a.account_id, children: a.account_name ?? a.account_id }, a.id)) })
5052
5476
  ] })
5053
5477
  ] }),
5054
- errorMsg && /* @__PURE__ */ jsxs31("p", { className: "flex items-center gap-2 text-sm text-destructive", children: [
5055
- /* @__PURE__ */ jsx63(AlertCircle, { className: "h-4 w-4" }),
5478
+ errorMsg && /* @__PURE__ */ jsxs32("p", { className: "flex items-center gap-2 text-sm text-destructive", children: [
5479
+ /* @__PURE__ */ jsx64(AlertCircle, { className: "h-4 w-4" }),
5056
5480
  errorMsg
5057
5481
  ] }),
5058
- /* @__PURE__ */ jsxs31(SheetFooter, { className: "mt-auto", children: [
5059
- /* @__PURE__ */ jsx63(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: "Cancelar" }),
5060
- /* @__PURE__ */ jsxs31(Button, { onClick: handlePublish, disabled: busy, children: [
5061
- status === "publishing" && /* @__PURE__ */ jsx63(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
5482
+ /* @__PURE__ */ jsxs32(SheetFooter, { className: "mt-auto", children: [
5483
+ /* @__PURE__ */ jsx64(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: "Cancelar" }),
5484
+ /* @__PURE__ */ jsxs32(Button, { onClick: handlePublish, disabled: busy, children: [
5485
+ status === "publishing" && /* @__PURE__ */ jsx64(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
5062
5486
  "Publicar"
5063
5487
  ] })
5064
5488
  ] })
@@ -5074,9 +5498,9 @@ function useIframeAuth() {
5074
5498
  }
5075
5499
 
5076
5500
  // src/hooks/use-iframe-navigate.ts
5077
- import { useCallback as useCallback7 } from "react";
5501
+ import { useCallback as useCallback8 } from "react";
5078
5502
  function useIframeNavigate() {
5079
- return useCallback7((path) => {
5503
+ return useCallback8((path) => {
5080
5504
  if (!window.parent || window.parent === window) return;
5081
5505
  window.parent.postMessage(
5082
5506
  { type: "DFL_NAVIGATE", path },
@@ -5091,7 +5515,7 @@ import {
5091
5515
  useContext as useContext9,
5092
5516
  useMemo as useMemo5
5093
5517
  } from "react";
5094
- import { jsx as jsx64 } from "react/jsx-runtime";
5518
+ import { jsx as jsx65 } from "react/jsx-runtime";
5095
5519
  var FeatureFlagContext = createContext8({
5096
5520
  flags: {},
5097
5521
  isEnabled: () => false
@@ -5107,7 +5531,7 @@ var FeatureFlagProvider = ({
5107
5531
  }),
5108
5532
  [flags]
5109
5533
  );
5110
- return /* @__PURE__ */ jsx64(FeatureFlagContext.Provider, { value, children });
5534
+ return /* @__PURE__ */ jsx65(FeatureFlagContext.Provider, { value, children });
5111
5535
  };
5112
5536
  var useFeatureFlag = (flag) => {
5113
5537
  const { isEnabled } = useContext9(FeatureFlagContext);
@@ -5200,6 +5624,7 @@ export {
5200
5624
  ContextMenuSubContent,
5201
5625
  ContextMenuSubTrigger,
5202
5626
  ContextMenuTrigger,
5627
+ DEFAULT_NAME_COL_WIDTH,
5203
5628
  DflRemote,
5204
5629
  Dialog,
5205
5630
  DialogClose,
@@ -5244,6 +5669,7 @@ export {
5244
5669
  FormItem,
5245
5670
  FormLabel,
5246
5671
  FormMessage,
5672
+ Gantt,
5247
5673
  HoverCard,
5248
5674
  HoverCardContent,
5249
5675
  HoverCardTrigger,
@@ -5384,7 +5810,9 @@ export {
5384
5810
  UserAvatar,
5385
5811
  UserMenu,
5386
5812
  badgeVariants,
5813
+ barGridColumn,
5387
5814
  buttonVariants,
5815
+ clampPct,
5388
5816
  cn,
5389
5817
  filterPublishableAccounts,
5390
5818
  getInitials,
@@ -5396,6 +5824,10 @@ export {
5396
5824
  memberHueVar,
5397
5825
  navigationMenuTriggerStyle,
5398
5826
  parseTags,
5827
+ resolveNameColWidth,
5828
+ resolveWeekCount,
5829
+ resolveWeekLabels,
5830
+ stageProgress,
5399
5831
  toast,
5400
5832
  toggleVariants,
5401
5833
  useAuth,