@devfellowship/components 1.2.3 → 1.3.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.cjs CHANGED
@@ -156,6 +156,7 @@ __export(src_exports, {
156
156
  FormItem: () => FormItem,
157
157
  FormLabel: () => FormLabel,
158
158
  FormMessage: () => FormMessage,
159
+ Gantt: () => Gantt,
159
160
  HoverCard: () => HoverCard,
160
161
  HoverCardContent: () => HoverCardContent,
161
162
  HoverCardTrigger: () => HoverCardTrigger,
@@ -296,7 +297,9 @@ __export(src_exports, {
296
297
  UserAvatar: () => UserAvatar,
297
298
  UserMenu: () => UserMenu,
298
299
  badgeVariants: () => badgeVariants,
300
+ barGridColumn: () => barGridColumn,
299
301
  buttonVariants: () => buttonVariants,
302
+ clampPct: () => clampPct,
300
303
  cn: () => cn,
301
304
  filterPublishableAccounts: () => filterPublishableAccounts,
302
305
  getInitials: () => getInitials,
@@ -308,6 +311,9 @@ __export(src_exports, {
308
311
  memberHueVar: () => memberHueVar,
309
312
  navigationMenuTriggerStyle: () => navigationMenuTriggerStyle,
310
313
  parseTags: () => parseTags,
314
+ resolveWeekCount: () => resolveWeekCount,
315
+ resolveWeekLabels: () => resolveWeekLabels,
316
+ stageProgress: () => stageProgress,
311
317
  toast: () => toast,
312
318
  toggleVariants: () => toggleVariants,
313
319
  useAuth: () => useAuth,
@@ -5065,10 +5071,389 @@ function AppNavbar({
5065
5071
  );
5066
5072
  }
5067
5073
 
5068
- // src/components/organisms/PublishDrawer.tsx
5074
+ // src/components/organisms/Gantt.tsx
5069
5075
  var React44 = __toESM(require("react"), 1);
5070
- var import_lucide_react23 = require("lucide-react");
5071
5076
  var import_jsx_runtime63 = require("react/jsx-runtime");
5077
+ function clampPct(value) {
5078
+ if (value == null || Number.isNaN(value)) return 0;
5079
+ return Math.max(0, Math.min(100, Math.round(value)));
5080
+ }
5081
+ function stageProgress(stage) {
5082
+ if (stage.progress != null) return clampPct(stage.progress);
5083
+ const ms = stage.milestones ?? [];
5084
+ if (ms.length === 0) return 0;
5085
+ const done = ms.filter((m) => m.done).length;
5086
+ return clampPct(done / ms.length * 100);
5087
+ }
5088
+ function resolveWeekCount(stages, weeks) {
5089
+ if (Array.isArray(weeks)) return Math.max(1, weeks.length);
5090
+ if (typeof weeks === "number" && weeks > 0) return Math.round(weeks);
5091
+ let max = 1;
5092
+ for (const s of stages) {
5093
+ max = Math.max(max, s.weekStart + Math.max(1, s.weekSpan) - 1);
5094
+ for (const m of s.milestones ?? []) {
5095
+ const ws = m.weekStart ?? s.weekStart;
5096
+ max = Math.max(max, ws + Math.max(1, m.weekSpan ?? 1) - 1);
5097
+ }
5098
+ }
5099
+ return Math.max(1, max);
5100
+ }
5101
+ function resolveWeekLabels(count2, weeks) {
5102
+ if (Array.isArray(weeks)) return weeks;
5103
+ return Array.from({ length: count2 }, (_, i) => `W${i + 1}`);
5104
+ }
5105
+ function barGridColumn(weekStart, weekSpan, weekCount) {
5106
+ const start = Math.max(1, Math.min(weekStart, weekCount));
5107
+ const rawEnd = start + Math.max(1, weekSpan) - 1;
5108
+ const end = Math.max(start, Math.min(rawEnd, weekCount));
5109
+ return { start, span: end - start + 1 };
5110
+ }
5111
+ var DEFAULT_DOT = "var(--s-brand-solid, #E07A4A)";
5112
+ function Gantt({
5113
+ stages,
5114
+ weeks,
5115
+ dependencies = [],
5116
+ rowsHeader = "Stage / Task",
5117
+ stagesOnly = false,
5118
+ header,
5119
+ labelWidth = 240,
5120
+ weekMinWidth = 64,
5121
+ className,
5122
+ style,
5123
+ ...rest
5124
+ }) {
5125
+ const weekCount = resolveWeekCount(stages, weeks);
5126
+ const weekLabels = resolveWeekLabels(weekCount, weeks);
5127
+ const [collapsed, setCollapsed] = React44.useState(
5128
+ () => Object.fromEntries(stages.filter((s) => s.collapsed).map((s) => [s.id, true]))
5129
+ );
5130
+ const toggle = (id) => setCollapsed((c) => ({ ...c, [id]: !c[id] }));
5131
+ const gridRef = React44.useRef(null);
5132
+ const barRefs = React44.useRef({});
5133
+ const [edges, setEdges] = React44.useState([]);
5134
+ const recomputeEdges = React44.useCallback(() => {
5135
+ const root = gridRef.current;
5136
+ if (!root || dependencies.length === 0) {
5137
+ setEdges([]);
5138
+ return;
5139
+ }
5140
+ const rootBox = root.getBoundingClientRect();
5141
+ const next = [];
5142
+ for (const dep of dependencies) {
5143
+ const a = barRefs.current[dep.from];
5144
+ const b = barRefs.current[dep.to];
5145
+ if (!a || !b) continue;
5146
+ const ab = a.getBoundingClientRect();
5147
+ const bb = b.getBoundingClientRect();
5148
+ next.push({
5149
+ id: `${dep.from}->${dep.to}`,
5150
+ x1: ab.right - rootBox.left,
5151
+ y1: ab.top - rootBox.top + ab.height / 2,
5152
+ x2: bb.left - rootBox.left,
5153
+ y2: bb.top - rootBox.top + bb.height / 2
5154
+ });
5155
+ }
5156
+ setEdges(next);
5157
+ }, [dependencies]);
5158
+ React44.useLayoutEffect(() => {
5159
+ recomputeEdges();
5160
+ }, [recomputeEdges, collapsed, weekCount, stages]);
5161
+ React44.useEffect(() => {
5162
+ if (dependencies.length === 0) return;
5163
+ const handler = () => recomputeEdges();
5164
+ window.addEventListener("resize", handler);
5165
+ return () => window.removeEventListener("resize", handler);
5166
+ }, [dependencies.length, recomputeEdges]);
5167
+ const trackTemplate = `${labelWidth}px repeat(${weekCount}, minmax(${weekMinWidth}px, 1fr))`;
5168
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5169
+ "div",
5170
+ {
5171
+ className: cn(
5172
+ "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",
5173
+ className
5174
+ ),
5175
+ style,
5176
+ ...rest,
5177
+ children: [
5178
+ header && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "border-b border-[var(--s-border-subtle,#2A2622)] px-5 py-4", children: header }),
5179
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { ref: gridRef, className: "relative min-w-max", children: [
5180
+ edges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5181
+ "svg",
5182
+ {
5183
+ className: "pointer-events-none absolute inset-0 h-full w-full",
5184
+ "aria-hidden": "true",
5185
+ children: [
5186
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5187
+ "marker",
5188
+ {
5189
+ id: "dfl-gantt-arrow",
5190
+ markerWidth: "7",
5191
+ markerHeight: "7",
5192
+ refX: "5",
5193
+ refY: "3",
5194
+ orient: "auto",
5195
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5196
+ "path",
5197
+ {
5198
+ d: "M0,0 L6,3 L0,6 Z",
5199
+ fill: "var(--s-brand-solid, #E07A4A)"
5200
+ }
5201
+ )
5202
+ }
5203
+ ) }),
5204
+ edges.map((e) => {
5205
+ const stub = 14;
5206
+ const c1x = e.x1 + stub;
5207
+ const c2x = e.x2 - stub;
5208
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5209
+ "path",
5210
+ {
5211
+ d: `M ${e.x1} ${e.y1} C ${c1x} ${e.y1}, ${c2x} ${e.y2}, ${e.x2} ${e.y2}`,
5212
+ fill: "none",
5213
+ stroke: "var(--s-brand-solid, #E07A4A)",
5214
+ strokeWidth: 1.5,
5215
+ strokeOpacity: 0.65,
5216
+ markerEnd: "url(#dfl-gantt-arrow)"
5217
+ },
5218
+ e.id
5219
+ );
5220
+ })
5221
+ ]
5222
+ }
5223
+ ),
5224
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5225
+ "div",
5226
+ {
5227
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-raised,#1A1714)]",
5228
+ style: { gridTemplateColumns: trackTemplate },
5229
+ children: [
5230
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "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)]", children: rowsHeader }),
5231
+ weekLabels.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5232
+ "div",
5233
+ {
5234
+ 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)]",
5235
+ children: label
5236
+ },
5237
+ i
5238
+ ))
5239
+ ]
5240
+ }
5241
+ ),
5242
+ stages.map((stage) => {
5243
+ const pct = stageProgress(stage);
5244
+ const dot = stage.color || DEFAULT_DOT;
5245
+ const isCollapsed = !!collapsed[stage.id];
5246
+ const ms = stage.milestones ?? [];
5247
+ const done = ms.filter((m) => m.done).length;
5248
+ const sCol = barGridColumn(stage.weekStart, stage.weekSpan, weekCount);
5249
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React44.Fragment, { children: [
5250
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5251
+ "div",
5252
+ {
5253
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)]",
5254
+ style: { gridTemplateColumns: trackTemplate },
5255
+ children: [
5256
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5257
+ "button",
5258
+ {
5259
+ type: "button",
5260
+ onClick: () => toggle(stage.id),
5261
+ className: "flex items-center gap-2 px-4 py-3 text-left hover:bg-[var(--s-surface-raised,#1A1714)] transition-colors",
5262
+ "aria-expanded": !isCollapsed,
5263
+ children: [
5264
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Chevron, { open: !isCollapsed }),
5265
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5266
+ "span",
5267
+ {
5268
+ className: "h-2.5 w-2.5 shrink-0 rounded-full",
5269
+ style: { background: dot }
5270
+ }
5271
+ ),
5272
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "min-w-0", children: [
5273
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "block truncate text-[13px] font-semibold text-[var(--s-ink-primary,#F6F1E7)]", children: stage.title }),
5274
+ stage.subtitle && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "block truncate text-[11px] text-[var(--s-ink-muted,#7D7568)]", children: stage.subtitle })
5275
+ ] }),
5276
+ ms.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("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: [
5277
+ done,
5278
+ "/",
5279
+ ms.length
5280
+ ] })
5281
+ ]
5282
+ }
5283
+ ),
5284
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5285
+ "div",
5286
+ {
5287
+ className: "relative h-9",
5288
+ style: {
5289
+ gridColumn: `${1 + sCol.start} / span ${sCol.span}`
5290
+ },
5291
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5292
+ "div",
5293
+ {
5294
+ ref: (el) => {
5295
+ barRefs.current[stage.id] = el;
5296
+ },
5297
+ className: "absolute inset-y-2 inset-x-1 overflow-hidden rounded-[var(--p-radius-sm,4px)]",
5298
+ style: { background: tint(dot, 0.16) },
5299
+ title: `${stage.title} \xB7 ${pct}%`,
5300
+ children: [
5301
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5302
+ "div",
5303
+ {
5304
+ className: "h-full rounded-[var(--p-radius-sm,4px)]",
5305
+ style: { width: `${pct}%`, background: dot }
5306
+ }
5307
+ ),
5308
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("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: [
5309
+ pct,
5310
+ "%"
5311
+ ] })
5312
+ ]
5313
+ }
5314
+ )
5315
+ }
5316
+ )
5317
+ ]
5318
+ }
5319
+ ),
5320
+ !stagesOnly && !isCollapsed && ms.map((m) => {
5321
+ const mStart = m.weekStart ?? stage.weekStart;
5322
+ const mCol = barGridColumn(
5323
+ mStart,
5324
+ m.weekSpan ?? 1,
5325
+ weekCount
5326
+ );
5327
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5328
+ "div",
5329
+ {
5330
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-page,#0A0908)]",
5331
+ style: { gridTemplateColumns: trackTemplate },
5332
+ children: [
5333
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex items-center gap-2 py-2 pl-10 pr-4", children: [
5334
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(StatusDot, { done: m.done, color: dot }),
5335
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5336
+ "span",
5337
+ {
5338
+ className: cn(
5339
+ "min-w-0 flex-1 truncate text-[13px]",
5340
+ m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5341
+ ),
5342
+ children: m.title
5343
+ }
5344
+ ),
5345
+ m.points != null && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "shrink-0 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-muted,#7D7568)]", children: m.points })
5346
+ ] }),
5347
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5348
+ "div",
5349
+ {
5350
+ className: "relative h-6",
5351
+ style: {
5352
+ gridColumn: `${1 + mCol.start} / span ${mCol.span}`
5353
+ },
5354
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5355
+ "div",
5356
+ {
5357
+ className: cn(
5358
+ "absolute inset-y-1.5 inset-x-1 rounded-[var(--p-radius-sm,4px)]",
5359
+ m.done ? "" : "border"
5360
+ ),
5361
+ style: m.done ? { background: dot } : {
5362
+ background: tint(dot, 0.08),
5363
+ borderColor: tint(dot, 0.4)
5364
+ }
5365
+ }
5366
+ )
5367
+ }
5368
+ )
5369
+ ]
5370
+ },
5371
+ m.id
5372
+ );
5373
+ })
5374
+ ] }, stage.id);
5375
+ }),
5376
+ stages.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "px-4 py-8 text-center text-[13px] text-[var(--s-ink-muted,#7D7568)]", children: "No stages yet." })
5377
+ ] }) }),
5378
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("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: [
5379
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(LegendItem, { swatch: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "h-2.5 w-3 rounded-[2px]", style: { background: "var(--s-brand-solid, #E07A4A)" } }), label: "Completed" }),
5380
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(LegendItem, { swatch: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("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" }),
5381
+ dependencies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(LegendItem, { swatch: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "block h-0.5 w-4", style: { background: "var(--s-brand-solid, #E07A4A)", opacity: 0.7 } }), label: "Depends on" })
5382
+ ] })
5383
+ ]
5384
+ }
5385
+ );
5386
+ }
5387
+ function Chevron({ open }) {
5388
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5389
+ "svg",
5390
+ {
5391
+ width: "14",
5392
+ height: "14",
5393
+ viewBox: "0 0 24 24",
5394
+ fill: "none",
5395
+ stroke: "currentColor",
5396
+ strokeWidth: "1.5",
5397
+ strokeLinecap: "round",
5398
+ strokeLinejoin: "round",
5399
+ className: "shrink-0 text-[var(--s-ink-muted,#7D7568)] transition-transform",
5400
+ style: { transform: open ? "rotate(90deg)" : "none" },
5401
+ "aria-hidden": "true",
5402
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("path", { d: "M9 18l6-6-6-6" })
5403
+ }
5404
+ );
5405
+ }
5406
+ function StatusDot({ done, color }) {
5407
+ if (done) {
5408
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
5409
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("circle", { cx: "12", cy: "12", r: "9", fill: color }),
5410
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5411
+ "path",
5412
+ {
5413
+ d: "M8 12l3 3 5-6",
5414
+ fill: "none",
5415
+ stroke: "var(--s-ink-inverse, #0A0908)",
5416
+ strokeWidth: "2",
5417
+ strokeLinecap: "round",
5418
+ strokeLinejoin: "round"
5419
+ }
5420
+ )
5421
+ ] });
5422
+ }
5423
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5424
+ "circle",
5425
+ {
5426
+ cx: "12",
5427
+ cy: "12",
5428
+ r: "8",
5429
+ fill: "none",
5430
+ stroke: "var(--s-border-strong, #3A3530)",
5431
+ strokeWidth: "2"
5432
+ }
5433
+ ) });
5434
+ }
5435
+ function LegendItem({ swatch, label }) {
5436
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "flex items-center gap-1.5", children: [
5437
+ swatch,
5438
+ label
5439
+ ] });
5440
+ }
5441
+ function tint(color, alpha) {
5442
+ const hex = /^#([0-9a-f]{6})$/i.exec(color.trim());
5443
+ if (hex) {
5444
+ const n = parseInt(hex[1], 16);
5445
+ const r = n >> 16 & 255;
5446
+ const g = n >> 8 & 255;
5447
+ const b = n & 255;
5448
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
5449
+ }
5450
+ return `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent)`;
5451
+ }
5452
+
5453
+ // src/components/organisms/PublishDrawer.tsx
5454
+ var React45 = __toESM(require("react"), 1);
5455
+ var import_lucide_react23 = require("lucide-react");
5456
+ var import_jsx_runtime64 = require("react/jsx-runtime");
5072
5457
  function parseTags(raw) {
5073
5458
  return raw.split(/[,\n]/).map((t) => t.trim()).filter((t) => t.length > 0);
5074
5459
  }
@@ -5104,16 +5489,16 @@ function PublishDrawer({
5104
5489
  onError,
5105
5490
  className
5106
5491
  }) {
5107
- const [title, setTitle] = React44.useState(suggestedTitle);
5108
- const [description, setDescription] = React44.useState(suggestedDescription);
5109
- const [tagsRaw, setTagsRaw] = React44.useState("");
5110
- const [thumbnailUrl, setThumbnailUrl] = React44.useState(suggestedThumbnailUrl);
5111
- const [accounts, setAccounts] = React44.useState([]);
5112
- const [accountId, setAccountId] = React44.useState(null);
5113
- const [status, setStatus] = React44.useState("idle");
5114
- const [errorMsg, setErrorMsg] = React44.useState(null);
5115
- const [result, setResult] = React44.useState(null);
5116
- React44.useEffect(() => {
5492
+ const [title, setTitle] = React45.useState(suggestedTitle);
5493
+ const [description, setDescription] = React45.useState(suggestedDescription);
5494
+ const [tagsRaw, setTagsRaw] = React45.useState("");
5495
+ const [thumbnailUrl, setThumbnailUrl] = React45.useState(suggestedThumbnailUrl);
5496
+ const [accounts, setAccounts] = React45.useState([]);
5497
+ const [accountId, setAccountId] = React45.useState(null);
5498
+ const [status, setStatus] = React45.useState("idle");
5499
+ const [errorMsg, setErrorMsg] = React45.useState(null);
5500
+ const [result, setResult] = React45.useState(null);
5501
+ React45.useEffect(() => {
5117
5502
  if (open) {
5118
5503
  setTitle(suggestedTitle);
5119
5504
  setDescription(suggestedDescription);
@@ -5123,7 +5508,7 @@ function PublishDrawer({
5123
5508
  setResult(null);
5124
5509
  }
5125
5510
  }, [open]);
5126
- React44.useEffect(() => {
5511
+ React45.useEffect(() => {
5127
5512
  if (!open) return;
5128
5513
  let cancelled = false;
5129
5514
  (async () => {
@@ -5147,7 +5532,7 @@ function PublishDrawer({
5147
5532
  cancelled = true;
5148
5533
  };
5149
5534
  }, [open, supabase]);
5150
- const fail = React44.useCallback(
5535
+ const fail = React45.useCallback(
5151
5536
  (msg) => {
5152
5537
  setStatus("error");
5153
5538
  setErrorMsg(msg);
@@ -5249,18 +5634,18 @@ function PublishDrawer({
5249
5634
  onPublished?.(publishResult);
5250
5635
  }
5251
5636
  const busy = status === "publishing" || status === "rendering-thumb" || status === "loading-accounts";
5252
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Sheet, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(SheetContent, { side: "right", className: cn("flex w-full flex-col gap-4 overflow-y-auto sm:max-w-md", className), children: [
5253
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(SheetHeader, { children: [
5254
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(SheetTitle, { className: "flex items-center gap-2", children: [
5255
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react23.Youtube, { className: "h-5 w-5 text-red-600" }),
5637
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Sheet, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(SheetContent, { side: "right", className: cn("flex w-full flex-col gap-4 overflow-y-auto sm:max-w-md", className), children: [
5638
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(SheetHeader, { children: [
5639
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(SheetTitle, { className: "flex items-center gap-2", children: [
5640
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.Youtube, { className: "h-5 w-5 text-red-600" }),
5256
5641
  "Publicar no YouTube"
5257
5642
  ] }),
5258
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(SheetDescription, { children: "Publique o v\xEDdeo gravado cross-platform via Zernio. Preencha t\xEDtulo, descri\xE7\xE3o e palavras-chave manualmente." })
5643
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(SheetDescription, { children: "Publique o v\xEDdeo gravado cross-platform via Zernio. Preencha t\xEDtulo, descri\xE7\xE3o e palavras-chave manualmente." })
5259
5644
  ] }),
5260
- status === "done" && result ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-center", children: [
5261
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react23.CheckCircle2, { className: "h-10 w-10 text-green-600" }),
5262
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "font-medium", children: "V\xEDdeo publicado!" }),
5263
- result.post_url && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5645
+ status === "done" && result ? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-center", children: [
5646
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.CheckCircle2, { className: "h-10 w-10 text-green-600" }),
5647
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("p", { className: "font-medium", children: "V\xEDdeo publicado!" }),
5648
+ result.post_url && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5264
5649
  "a",
5265
5650
  {
5266
5651
  href: result.post_url,
@@ -5270,15 +5655,15 @@ function PublishDrawer({
5270
5655
  children: "Abrir no YouTube"
5271
5656
  }
5272
5657
  ),
5273
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
5658
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
5274
5659
  "Zernio post id: ",
5275
5660
  result.zernio_post_id
5276
5661
  ] }),
5277
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Fechar" })
5278
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex flex-1 flex-col gap-4", children: [
5279
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "grid gap-2", children: [
5280
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Label3, { htmlFor: "pd-title", children: "T\xEDtulo" }),
5281
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5662
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Fechar" })
5663
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "flex flex-1 flex-col gap-4", children: [
5664
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5665
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-title", children: "T\xEDtulo" }),
5666
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5282
5667
  Input,
5283
5668
  {
5284
5669
  id: "pd-title",
@@ -5289,9 +5674,9 @@ function PublishDrawer({
5289
5674
  }
5290
5675
  )
5291
5676
  ] }),
5292
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "grid gap-2", children: [
5293
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Label3, { htmlFor: "pd-desc", children: "Descri\xE7\xE3o" }),
5294
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5677
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5678
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-desc", children: "Descri\xE7\xE3o" }),
5679
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5295
5680
  Textarea,
5296
5681
  {
5297
5682
  id: "pd-desc",
@@ -5303,9 +5688,9 @@ function PublishDrawer({
5303
5688
  }
5304
5689
  )
5305
5690
  ] }),
5306
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "grid gap-2", children: [
5307
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Label3, { htmlFor: "pd-tags", children: "Palavras-chave / tags" }),
5308
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5691
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5692
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-tags", children: "Palavras-chave / tags" }),
5693
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5309
5694
  Input,
5310
5695
  {
5311
5696
  id: "pd-tags",
@@ -5315,11 +5700,11 @@ function PublishDrawer({
5315
5700
  disabled: busy
5316
5701
  }
5317
5702
  ),
5318
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "text-xs text-muted-foreground", children: "Separadas por v\xEDrgula. A primeira vira a keyword." })
5703
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("p", { className: "text-xs text-muted-foreground", children: "Separadas por v\xEDrgula. A primeira vira a keyword." })
5319
5704
  ] }),
5320
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "grid gap-2", children: [
5321
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Label3, { htmlFor: "pd-thumb", children: "Thumbnail" }),
5322
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5705
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5706
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-thumb", children: "Thumbnail" }),
5707
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5323
5708
  Input,
5324
5709
  {
5325
5710
  id: "pd-thumb",
@@ -5329,7 +5714,7 @@ function PublishDrawer({
5329
5714
  disabled: busy
5330
5715
  }
5331
5716
  ),
5332
- thumbnailTemplateId && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5717
+ thumbnailTemplateId && /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
5333
5718
  Button,
5334
5719
  {
5335
5720
  type: "button",
@@ -5339,12 +5724,12 @@ function PublishDrawer({
5339
5724
  disabled: busy,
5340
5725
  className: "w-fit",
5341
5726
  children: [
5342
- status === "rendering-thumb" ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react23.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react23.Image, { className: "mr-2 h-4 w-4" }),
5727
+ status === "rendering-thumb" ? /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.Image, { className: "mr-2 h-4 w-4" }),
5343
5728
  "Gerar via Thumbify"
5344
5729
  ]
5345
5730
  }
5346
5731
  ),
5347
- thumbnailUrl && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5732
+ thumbnailUrl && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5348
5733
  "img",
5349
5734
  {
5350
5735
  src: thumbnailUrl,
@@ -5353,26 +5738,26 @@ function PublishDrawer({
5353
5738
  }
5354
5739
  )
5355
5740
  ] }),
5356
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "grid gap-2", children: [
5357
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Label3, { htmlFor: "pd-account", children: "Canal do YouTube" }),
5358
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(Select, { value: accountId ?? void 0, onValueChange: setAccountId, disabled: busy || accounts.length === 0, children: [
5359
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(SelectTrigger, { id: "pd-account", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5741
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5742
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-account", children: "Canal do YouTube" }),
5743
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(Select, { value: accountId ?? void 0, onValueChange: setAccountId, disabled: busy || accounts.length === 0, children: [
5744
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(SelectTrigger, { id: "pd-account", children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5360
5745
  SelectValue,
5361
5746
  {
5362
5747
  placeholder: status === "loading-accounts" ? "Carregando canais\u2026" : accounts.length === 0 ? "Nenhum canal conectado" : "Selecione um canal"
5363
5748
  }
5364
5749
  ) }),
5365
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(SelectContent, { children: accounts.map((a) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(SelectItem, { value: a.account_id, children: a.account_name ?? a.account_id }, a.id)) })
5750
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(SelectContent, { children: accounts.map((a) => /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(SelectItem, { value: a.account_id, children: a.account_name ?? a.account_id }, a.id)) })
5366
5751
  ] })
5367
5752
  ] }),
5368
- errorMsg && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("p", { className: "flex items-center gap-2 text-sm text-destructive", children: [
5369
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react23.AlertCircle, { className: "h-4 w-4" }),
5753
+ errorMsg && /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("p", { className: "flex items-center gap-2 text-sm text-destructive", children: [
5754
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.AlertCircle, { className: "h-4 w-4" }),
5370
5755
  errorMsg
5371
5756
  ] }),
5372
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(SheetFooter, { className: "mt-auto", children: [
5373
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: "Cancelar" }),
5374
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(Button, { onClick: handlePublish, disabled: busy, children: [
5375
- status === "publishing" && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react23.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
5757
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(SheetFooter, { className: "mt-auto", children: [
5758
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: "Cancelar" }),
5759
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(Button, { onClick: handlePublish, disabled: busy, children: [
5760
+ status === "publishing" && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
5376
5761
  "Publicar"
5377
5762
  ] })
5378
5763
  ] })
@@ -5401,7 +5786,7 @@ function useIframeNavigate() {
5401
5786
 
5402
5787
  // src/providers/feature-flag-provider.tsx
5403
5788
  var import_react9 = require("react");
5404
- var import_jsx_runtime64 = require("react/jsx-runtime");
5789
+ var import_jsx_runtime65 = require("react/jsx-runtime");
5405
5790
  var FeatureFlagContext = (0, import_react9.createContext)({
5406
5791
  flags: {},
5407
5792
  isEnabled: () => false
@@ -5417,7 +5802,7 @@ var FeatureFlagProvider = ({
5417
5802
  }),
5418
5803
  [flags]
5419
5804
  );
5420
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(FeatureFlagContext.Provider, { value, children });
5805
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(FeatureFlagContext.Provider, { value, children });
5421
5806
  };
5422
5807
  var useFeatureFlag = (flag) => {
5423
5808
  const { isEnabled } = (0, import_react9.useContext)(FeatureFlagContext);
@@ -5555,6 +5940,7 @@ var useFeatureFlags = () => {
5555
5940
  FormItem,
5556
5941
  FormLabel,
5557
5942
  FormMessage,
5943
+ Gantt,
5558
5944
  HoverCard,
5559
5945
  HoverCardContent,
5560
5946
  HoverCardTrigger,
@@ -5695,7 +6081,9 @@ var useFeatureFlags = () => {
5695
6081
  UserAvatar,
5696
6082
  UserMenu,
5697
6083
  badgeVariants,
6084
+ barGridColumn,
5698
6085
  buttonVariants,
6086
+ clampPct,
5699
6087
  cn,
5700
6088
  filterPublishableAccounts,
5701
6089
  getInitials,
@@ -5707,6 +6095,9 @@ var useFeatureFlags = () => {
5707
6095
  memberHueVar,
5708
6096
  navigationMenuTriggerStyle,
5709
6097
  parseTags,
6098
+ resolveWeekCount,
6099
+ resolveWeekLabels,
6100
+ stageProgress,
5710
6101
  toast,
5711
6102
  toggleVariants,
5712
6103
  useAuth,