@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.cjs CHANGED
@@ -112,6 +112,7 @@ __export(src_exports, {
112
112
  ContextMenuSubContent: () => ContextMenuSubContent,
113
113
  ContextMenuSubTrigger: () => ContextMenuSubTrigger,
114
114
  ContextMenuTrigger: () => ContextMenuTrigger,
115
+ DEFAULT_NAME_COL_WIDTH: () => DEFAULT_NAME_COL_WIDTH,
115
116
  DflRemote: () => DflRemote,
116
117
  Dialog: () => Dialog,
117
118
  DialogClose: () => DialogClose,
@@ -156,6 +157,7 @@ __export(src_exports, {
156
157
  FormItem: () => FormItem,
157
158
  FormLabel: () => FormLabel,
158
159
  FormMessage: () => FormMessage,
160
+ Gantt: () => Gantt,
159
161
  HoverCard: () => HoverCard,
160
162
  HoverCardContent: () => HoverCardContent,
161
163
  HoverCardTrigger: () => HoverCardTrigger,
@@ -296,7 +298,9 @@ __export(src_exports, {
296
298
  UserAvatar: () => UserAvatar,
297
299
  UserMenu: () => UserMenu,
298
300
  badgeVariants: () => badgeVariants,
301
+ barGridColumn: () => barGridColumn,
299
302
  buttonVariants: () => buttonVariants,
303
+ clampPct: () => clampPct,
300
304
  cn: () => cn,
301
305
  filterPublishableAccounts: () => filterPublishableAccounts,
302
306
  getInitials: () => getInitials,
@@ -308,6 +312,10 @@ __export(src_exports, {
308
312
  memberHueVar: () => memberHueVar,
309
313
  navigationMenuTriggerStyle: () => navigationMenuTriggerStyle,
310
314
  parseTags: () => parseTags,
315
+ resolveNameColWidth: () => resolveNameColWidth,
316
+ resolveWeekCount: () => resolveWeekCount,
317
+ resolveWeekLabels: () => resolveWeekLabels,
318
+ stageProgress: () => stageProgress,
311
319
  toast: () => toast,
312
320
  toggleVariants: () => toggleVariants,
313
321
  useAuth: () => useAuth,
@@ -5065,10 +5073,434 @@ function AppNavbar({
5065
5073
  );
5066
5074
  }
5067
5075
 
5068
- // src/components/organisms/PublishDrawer.tsx
5076
+ // src/components/organisms/Gantt.tsx
5069
5077
  var React44 = __toESM(require("react"), 1);
5070
- var import_lucide_react23 = require("lucide-react");
5071
5078
  var import_jsx_runtime63 = require("react/jsx-runtime");
5079
+ var DEFAULT_NAME_COL_WIDTH = 320;
5080
+ function resolveNameColWidth(nameColWidth, labelWidth) {
5081
+ if (typeof nameColWidth === "number" && nameColWidth > 0) return Math.round(nameColWidth);
5082
+ if (typeof labelWidth === "number" && labelWidth > 0) return Math.round(labelWidth);
5083
+ return DEFAULT_NAME_COL_WIDTH;
5084
+ }
5085
+ function clampPct(value) {
5086
+ if (value == null || Number.isNaN(value)) return 0;
5087
+ return Math.max(0, Math.min(100, Math.round(value)));
5088
+ }
5089
+ function stageProgress(stage) {
5090
+ if (stage.progress != null) return clampPct(stage.progress);
5091
+ const ms = stage.milestones ?? [];
5092
+ if (ms.length === 0) return 0;
5093
+ const done = ms.filter((m) => m.done).length;
5094
+ return clampPct(done / ms.length * 100);
5095
+ }
5096
+ function resolveWeekCount(stages, weeks) {
5097
+ if (Array.isArray(weeks)) return Math.max(1, weeks.length);
5098
+ if (typeof weeks === "number" && weeks > 0) return Math.round(weeks);
5099
+ let max = 1;
5100
+ for (const s of stages) {
5101
+ max = Math.max(max, s.weekStart + Math.max(1, s.weekSpan) - 1);
5102
+ for (const m of s.milestones ?? []) {
5103
+ const ws = m.weekStart ?? s.weekStart;
5104
+ max = Math.max(max, ws + Math.max(1, m.weekSpan ?? 1) - 1);
5105
+ }
5106
+ }
5107
+ return Math.max(1, max);
5108
+ }
5109
+ function resolveWeekLabels(count2, weeks) {
5110
+ if (Array.isArray(weeks)) return weeks;
5111
+ return Array.from({ length: count2 }, (_, i) => `W${i + 1}`);
5112
+ }
5113
+ function barGridColumn(weekStart, weekSpan, weekCount) {
5114
+ const start = Math.max(1, Math.min(weekStart, weekCount));
5115
+ const rawEnd = start + Math.max(1, weekSpan) - 1;
5116
+ const end = Math.max(start, Math.min(rawEnd, weekCount));
5117
+ return { start, span: end - start + 1 };
5118
+ }
5119
+ var DEFAULT_DOT = "var(--s-brand-solid, #E07A4A)";
5120
+ function Gantt({
5121
+ stages,
5122
+ weeks,
5123
+ dependencies = [],
5124
+ rowsHeader = "Stage / Task",
5125
+ stagesOnly = false,
5126
+ header,
5127
+ labelWidth,
5128
+ nameColWidth,
5129
+ weekMinWidth = 64,
5130
+ className,
5131
+ style,
5132
+ ...rest
5133
+ }) {
5134
+ const weekCount = resolveWeekCount(stages, weeks);
5135
+ const weekLabels = resolveWeekLabels(weekCount, weeks);
5136
+ const nameWidth = resolveNameColWidth(nameColWidth, labelWidth);
5137
+ const [collapsed, setCollapsed] = React44.useState(
5138
+ () => Object.fromEntries(stages.filter((s) => s.collapsed).map((s) => [s.id, true]))
5139
+ );
5140
+ const toggle = (id) => setCollapsed((c) => ({ ...c, [id]: !c[id] }));
5141
+ const gridRef = React44.useRef(null);
5142
+ const barRefs = React44.useRef({});
5143
+ const [edges, setEdges] = React44.useState([]);
5144
+ const recomputeEdges = React44.useCallback(() => {
5145
+ const root = gridRef.current;
5146
+ if (!root || dependencies.length === 0) {
5147
+ setEdges([]);
5148
+ return;
5149
+ }
5150
+ const rootBox = root.getBoundingClientRect();
5151
+ const next = [];
5152
+ for (const dep of dependencies) {
5153
+ const a = barRefs.current[dep.from];
5154
+ const b = barRefs.current[dep.to];
5155
+ if (!a || !b) continue;
5156
+ const ab = a.getBoundingClientRect();
5157
+ const bb = b.getBoundingClientRect();
5158
+ next.push({
5159
+ id: `${dep.from}->${dep.to}`,
5160
+ x1: ab.right - rootBox.left,
5161
+ y1: ab.top - rootBox.top + ab.height / 2,
5162
+ x2: bb.left - rootBox.left,
5163
+ y2: bb.top - rootBox.top + bb.height / 2
5164
+ });
5165
+ }
5166
+ setEdges(next);
5167
+ }, [dependencies]);
5168
+ React44.useLayoutEffect(() => {
5169
+ recomputeEdges();
5170
+ }, [recomputeEdges, collapsed, weekCount, stages]);
5171
+ React44.useEffect(() => {
5172
+ if (dependencies.length === 0) return;
5173
+ const handler = () => recomputeEdges();
5174
+ window.addEventListener("resize", handler);
5175
+ return () => window.removeEventListener("resize", handler);
5176
+ }, [dependencies.length, recomputeEdges]);
5177
+ const trackTemplate = `${nameWidth}px repeat(${weekCount}, minmax(${weekMinWidth}px, 1fr))`;
5178
+ 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)]";
5179
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5180
+ "div",
5181
+ {
5182
+ className: cn(
5183
+ "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",
5184
+ className
5185
+ ),
5186
+ style,
5187
+ ...rest,
5188
+ children: [
5189
+ header && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "border-b border-[var(--s-border-subtle,#2A2622)] px-5 py-4", children: header }),
5190
+ /* @__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: [
5191
+ edges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5192
+ "svg",
5193
+ {
5194
+ className: "pointer-events-none absolute inset-0 h-full w-full",
5195
+ "aria-hidden": "true",
5196
+ children: [
5197
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5198
+ "marker",
5199
+ {
5200
+ id: "dfl-gantt-arrow",
5201
+ markerWidth: "7",
5202
+ markerHeight: "7",
5203
+ refX: "5",
5204
+ refY: "3",
5205
+ orient: "auto",
5206
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5207
+ "path",
5208
+ {
5209
+ d: "M0,0 L6,3 L0,6 Z",
5210
+ fill: "var(--s-brand-solid, #E07A4A)"
5211
+ }
5212
+ )
5213
+ }
5214
+ ) }),
5215
+ edges.map((e) => {
5216
+ const stub = 14;
5217
+ const c1x = e.x1 + stub;
5218
+ const c2x = e.x2 - stub;
5219
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5220
+ "path",
5221
+ {
5222
+ d: `M ${e.x1} ${e.y1} C ${c1x} ${e.y1}, ${c2x} ${e.y2}, ${e.x2} ${e.y2}`,
5223
+ fill: "none",
5224
+ stroke: "var(--s-brand-solid, #E07A4A)",
5225
+ strokeWidth: 1.5,
5226
+ strokeOpacity: 0.65,
5227
+ markerEnd: "url(#dfl-gantt-arrow)"
5228
+ },
5229
+ e.id
5230
+ );
5231
+ })
5232
+ ]
5233
+ }
5234
+ ),
5235
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5236
+ "div",
5237
+ {
5238
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-raised,#1A1714)]",
5239
+ style: { gridTemplateColumns: trackTemplate },
5240
+ children: [
5241
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5242
+ "div",
5243
+ {
5244
+ className: cn(
5245
+ stickyCol,
5246
+ "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)]"
5247
+ ),
5248
+ children: rowsHeader
5249
+ }
5250
+ ),
5251
+ weekLabels.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5252
+ "div",
5253
+ {
5254
+ 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)]",
5255
+ children: label
5256
+ },
5257
+ i
5258
+ ))
5259
+ ]
5260
+ }
5261
+ ),
5262
+ stages.map((stage) => {
5263
+ const pct = stageProgress(stage);
5264
+ const dot = stage.color || DEFAULT_DOT;
5265
+ const isCollapsed = !!collapsed[stage.id];
5266
+ const ms = stage.milestones ?? [];
5267
+ const done = ms.filter((m) => m.done).length;
5268
+ const sCol = barGridColumn(stage.weekStart, stage.weekSpan, weekCount);
5269
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React44.Fragment, { children: [
5270
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5271
+ "div",
5272
+ {
5273
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)]",
5274
+ style: { gridTemplateColumns: trackTemplate },
5275
+ children: [
5276
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5277
+ "button",
5278
+ {
5279
+ type: "button",
5280
+ onClick: () => toggle(stage.id),
5281
+ className: cn(
5282
+ stickyCol,
5283
+ "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)]"
5284
+ ),
5285
+ "aria-expanded": !isCollapsed,
5286
+ children: [
5287
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Chevron, { open: !isCollapsed }),
5288
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5289
+ "span",
5290
+ {
5291
+ className: "h-2.5 w-2.5 shrink-0 rounded-full",
5292
+ style: { background: dot }
5293
+ }
5294
+ ),
5295
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "min-w-0", children: [
5296
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5297
+ "span",
5298
+ {
5299
+ className: "block truncate text-[13px] font-semibold text-[var(--s-ink-primary,#F6F1E7)]",
5300
+ title: stage.title,
5301
+ children: stage.title
5302
+ }
5303
+ ),
5304
+ stage.subtitle && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5305
+ "span",
5306
+ {
5307
+ className: "block truncate text-[11px] text-[var(--s-ink-muted,#7D7568)]",
5308
+ title: stage.subtitle,
5309
+ children: stage.subtitle
5310
+ }
5311
+ )
5312
+ ] }),
5313
+ 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: [
5314
+ done,
5315
+ "/",
5316
+ ms.length
5317
+ ] })
5318
+ ]
5319
+ }
5320
+ ),
5321
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5322
+ "div",
5323
+ {
5324
+ className: "relative h-9",
5325
+ style: {
5326
+ gridColumn: `${1 + sCol.start} / span ${sCol.span}`
5327
+ },
5328
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5329
+ "div",
5330
+ {
5331
+ ref: (el) => {
5332
+ barRefs.current[stage.id] = el;
5333
+ },
5334
+ className: "absolute inset-y-2 inset-x-1 overflow-hidden rounded-[var(--p-radius-sm,4px)]",
5335
+ style: { background: tint(dot, 0.16) },
5336
+ title: `${stage.title} \xB7 ${pct}%`,
5337
+ children: [
5338
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5339
+ "div",
5340
+ {
5341
+ className: "h-full rounded-[var(--p-radius-sm,4px)]",
5342
+ style: { width: `${pct}%`, background: dot }
5343
+ }
5344
+ ),
5345
+ /* @__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: [
5346
+ pct,
5347
+ "%"
5348
+ ] })
5349
+ ]
5350
+ }
5351
+ )
5352
+ }
5353
+ )
5354
+ ]
5355
+ }
5356
+ ),
5357
+ !stagesOnly && !isCollapsed && ms.map((m) => {
5358
+ const mStart = m.weekStart ?? stage.weekStart;
5359
+ const mCol = barGridColumn(
5360
+ mStart,
5361
+ m.weekSpan ?? 1,
5362
+ weekCount
5363
+ );
5364
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5365
+ "div",
5366
+ {
5367
+ className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-page,#0A0908)]",
5368
+ style: { gridTemplateColumns: trackTemplate },
5369
+ children: [
5370
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5371
+ "div",
5372
+ {
5373
+ className: cn(
5374
+ stickyCol,
5375
+ "flex items-center gap-2 bg-[var(--s-surface-page,#0A0908)] py-2 pl-10 pr-4"
5376
+ ),
5377
+ children: [
5378
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(StatusDot, { done: m.done, color: dot }),
5379
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5380
+ "span",
5381
+ {
5382
+ className: cn(
5383
+ "min-w-0 flex-1 truncate text-[13px]",
5384
+ m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5385
+ ),
5386
+ title: m.title,
5387
+ children: m.title
5388
+ }
5389
+ ),
5390
+ 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 })
5391
+ ]
5392
+ }
5393
+ ),
5394
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5395
+ "div",
5396
+ {
5397
+ className: "relative h-6",
5398
+ style: {
5399
+ gridColumn: `${1 + mCol.start} / span ${mCol.span}`
5400
+ },
5401
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5402
+ "div",
5403
+ {
5404
+ className: cn(
5405
+ "absolute inset-y-1.5 inset-x-1 rounded-[var(--p-radius-sm,4px)]",
5406
+ m.done ? "" : "border"
5407
+ ),
5408
+ style: m.done ? { background: dot } : {
5409
+ background: tint(dot, 0.08),
5410
+ borderColor: tint(dot, 0.4)
5411
+ }
5412
+ }
5413
+ )
5414
+ }
5415
+ )
5416
+ ]
5417
+ },
5418
+ m.id
5419
+ );
5420
+ })
5421
+ ] }, stage.id);
5422
+ }),
5423
+ 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." })
5424
+ ] }) }),
5425
+ /* @__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: [
5426
+ /* @__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" }),
5427
+ /* @__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" }),
5428
+ 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" })
5429
+ ] })
5430
+ ]
5431
+ }
5432
+ );
5433
+ }
5434
+ function Chevron({ open }) {
5435
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5436
+ "svg",
5437
+ {
5438
+ width: "14",
5439
+ height: "14",
5440
+ viewBox: "0 0 24 24",
5441
+ fill: "none",
5442
+ stroke: "currentColor",
5443
+ strokeWidth: "1.5",
5444
+ strokeLinecap: "round",
5445
+ strokeLinejoin: "round",
5446
+ className: "shrink-0 text-[var(--s-ink-muted,#7D7568)] transition-transform",
5447
+ style: { transform: open ? "rotate(90deg)" : "none" },
5448
+ "aria-hidden": "true",
5449
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("path", { d: "M9 18l6-6-6-6" })
5450
+ }
5451
+ );
5452
+ }
5453
+ function StatusDot({ done, color }) {
5454
+ if (done) {
5455
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
5456
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("circle", { cx: "12", cy: "12", r: "9", fill: color }),
5457
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5458
+ "path",
5459
+ {
5460
+ d: "M8 12l3 3 5-6",
5461
+ fill: "none",
5462
+ stroke: "var(--s-ink-inverse, #0A0908)",
5463
+ strokeWidth: "2",
5464
+ strokeLinecap: "round",
5465
+ strokeLinejoin: "round"
5466
+ }
5467
+ )
5468
+ ] });
5469
+ }
5470
+ 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)(
5471
+ "circle",
5472
+ {
5473
+ cx: "12",
5474
+ cy: "12",
5475
+ r: "8",
5476
+ fill: "none",
5477
+ stroke: "var(--s-border-strong, #3A3530)",
5478
+ strokeWidth: "2"
5479
+ }
5480
+ ) });
5481
+ }
5482
+ function LegendItem({ swatch, label }) {
5483
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "flex items-center gap-1.5", children: [
5484
+ swatch,
5485
+ label
5486
+ ] });
5487
+ }
5488
+ function tint(color, alpha) {
5489
+ const hex = /^#([0-9a-f]{6})$/i.exec(color.trim());
5490
+ if (hex) {
5491
+ const n = parseInt(hex[1], 16);
5492
+ const r = n >> 16 & 255;
5493
+ const g = n >> 8 & 255;
5494
+ const b = n & 255;
5495
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
5496
+ }
5497
+ return `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent)`;
5498
+ }
5499
+
5500
+ // src/components/organisms/PublishDrawer.tsx
5501
+ var React45 = __toESM(require("react"), 1);
5502
+ var import_lucide_react23 = require("lucide-react");
5503
+ var import_jsx_runtime64 = require("react/jsx-runtime");
5072
5504
  function parseTags(raw) {
5073
5505
  return raw.split(/[,\n]/).map((t) => t.trim()).filter((t) => t.length > 0);
5074
5506
  }
@@ -5104,16 +5536,16 @@ function PublishDrawer({
5104
5536
  onError,
5105
5537
  className
5106
5538
  }) {
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(() => {
5539
+ const [title, setTitle] = React45.useState(suggestedTitle);
5540
+ const [description, setDescription] = React45.useState(suggestedDescription);
5541
+ const [tagsRaw, setTagsRaw] = React45.useState("");
5542
+ const [thumbnailUrl, setThumbnailUrl] = React45.useState(suggestedThumbnailUrl);
5543
+ const [accounts, setAccounts] = React45.useState([]);
5544
+ const [accountId, setAccountId] = React45.useState(null);
5545
+ const [status, setStatus] = React45.useState("idle");
5546
+ const [errorMsg, setErrorMsg] = React45.useState(null);
5547
+ const [result, setResult] = React45.useState(null);
5548
+ React45.useEffect(() => {
5117
5549
  if (open) {
5118
5550
  setTitle(suggestedTitle);
5119
5551
  setDescription(suggestedDescription);
@@ -5123,7 +5555,7 @@ function PublishDrawer({
5123
5555
  setResult(null);
5124
5556
  }
5125
5557
  }, [open]);
5126
- React44.useEffect(() => {
5558
+ React45.useEffect(() => {
5127
5559
  if (!open) return;
5128
5560
  let cancelled = false;
5129
5561
  (async () => {
@@ -5147,7 +5579,7 @@ function PublishDrawer({
5147
5579
  cancelled = true;
5148
5580
  };
5149
5581
  }, [open, supabase]);
5150
- const fail = React44.useCallback(
5582
+ const fail = React45.useCallback(
5151
5583
  (msg) => {
5152
5584
  setStatus("error");
5153
5585
  setErrorMsg(msg);
@@ -5249,18 +5681,18 @@ function PublishDrawer({
5249
5681
  onPublished?.(publishResult);
5250
5682
  }
5251
5683
  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" }),
5684
+ 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: [
5685
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(SheetHeader, { children: [
5686
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(SheetTitle, { className: "flex items-center gap-2", children: [
5687
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.Youtube, { className: "h-5 w-5 text-red-600" }),
5256
5688
  "Publicar no YouTube"
5257
5689
  ] }),
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." })
5690
+ /* @__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
5691
  ] }),
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)(
5692
+ 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: [
5693
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.CheckCircle2, { className: "h-10 w-10 text-green-600" }),
5694
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("p", { className: "font-medium", children: "V\xEDdeo publicado!" }),
5695
+ result.post_url && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5264
5696
  "a",
5265
5697
  {
5266
5698
  href: result.post_url,
@@ -5270,15 +5702,15 @@ function PublishDrawer({
5270
5702
  children: "Abrir no YouTube"
5271
5703
  }
5272
5704
  ),
5273
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
5705
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
5274
5706
  "Zernio post id: ",
5275
5707
  result.zernio_post_id
5276
5708
  ] }),
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)(
5709
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Fechar" })
5710
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "flex flex-1 flex-col gap-4", children: [
5711
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5712
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-title", children: "T\xEDtulo" }),
5713
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5282
5714
  Input,
5283
5715
  {
5284
5716
  id: "pd-title",
@@ -5289,9 +5721,9 @@ function PublishDrawer({
5289
5721
  }
5290
5722
  )
5291
5723
  ] }),
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)(
5724
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5725
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-desc", children: "Descri\xE7\xE3o" }),
5726
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5295
5727
  Textarea,
5296
5728
  {
5297
5729
  id: "pd-desc",
@@ -5303,9 +5735,9 @@ function PublishDrawer({
5303
5735
  }
5304
5736
  )
5305
5737
  ] }),
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)(
5738
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5739
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-tags", children: "Palavras-chave / tags" }),
5740
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5309
5741
  Input,
5310
5742
  {
5311
5743
  id: "pd-tags",
@@ -5315,11 +5747,11 @@ function PublishDrawer({
5315
5747
  disabled: busy
5316
5748
  }
5317
5749
  ),
5318
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "text-xs text-muted-foreground", children: "Separadas por v\xEDrgula. A primeira vira a keyword." })
5750
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("p", { className: "text-xs text-muted-foreground", children: "Separadas por v\xEDrgula. A primeira vira a keyword." })
5319
5751
  ] }),
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)(
5752
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5753
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-thumb", children: "Thumbnail" }),
5754
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5323
5755
  Input,
5324
5756
  {
5325
5757
  id: "pd-thumb",
@@ -5329,7 +5761,7 @@ function PublishDrawer({
5329
5761
  disabled: busy
5330
5762
  }
5331
5763
  ),
5332
- thumbnailTemplateId && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5764
+ thumbnailTemplateId && /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
5333
5765
  Button,
5334
5766
  {
5335
5767
  type: "button",
@@ -5339,12 +5771,12 @@ function PublishDrawer({
5339
5771
  disabled: busy,
5340
5772
  className: "w-fit",
5341
5773
  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" }),
5774
+ 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
5775
  "Gerar via Thumbify"
5344
5776
  ]
5345
5777
  }
5346
5778
  ),
5347
- thumbnailUrl && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5779
+ thumbnailUrl && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5348
5780
  "img",
5349
5781
  {
5350
5782
  src: thumbnailUrl,
@@ -5353,26 +5785,26 @@ function PublishDrawer({
5353
5785
  }
5354
5786
  )
5355
5787
  ] }),
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)(
5788
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "grid gap-2", children: [
5789
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Label3, { htmlFor: "pd-account", children: "Canal do YouTube" }),
5790
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(Select, { value: accountId ?? void 0, onValueChange: setAccountId, disabled: busy || accounts.length === 0, children: [
5791
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(SelectTrigger, { id: "pd-account", children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5360
5792
  SelectValue,
5361
5793
  {
5362
5794
  placeholder: status === "loading-accounts" ? "Carregando canais\u2026" : accounts.length === 0 ? "Nenhum canal conectado" : "Selecione um canal"
5363
5795
  }
5364
5796
  ) }),
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)) })
5797
+ /* @__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
5798
  ] })
5367
5799
  ] }),
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" }),
5800
+ errorMsg && /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("p", { className: "flex items-center gap-2 text-sm text-destructive", children: [
5801
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.AlertCircle, { className: "h-4 w-4" }),
5370
5802
  errorMsg
5371
5803
  ] }),
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" }),
5804
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(SheetFooter, { className: "mt-auto", children: [
5805
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: "Cancelar" }),
5806
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(Button, { onClick: handlePublish, disabled: busy, children: [
5807
+ status === "publishing" && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_lucide_react23.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
5376
5808
  "Publicar"
5377
5809
  ] })
5378
5810
  ] })
@@ -5401,7 +5833,7 @@ function useIframeNavigate() {
5401
5833
 
5402
5834
  // src/providers/feature-flag-provider.tsx
5403
5835
  var import_react9 = require("react");
5404
- var import_jsx_runtime64 = require("react/jsx-runtime");
5836
+ var import_jsx_runtime65 = require("react/jsx-runtime");
5405
5837
  var FeatureFlagContext = (0, import_react9.createContext)({
5406
5838
  flags: {},
5407
5839
  isEnabled: () => false
@@ -5417,7 +5849,7 @@ var FeatureFlagProvider = ({
5417
5849
  }),
5418
5850
  [flags]
5419
5851
  );
5420
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(FeatureFlagContext.Provider, { value, children });
5852
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(FeatureFlagContext.Provider, { value, children });
5421
5853
  };
5422
5854
  var useFeatureFlag = (flag) => {
5423
5855
  const { isEnabled } = (0, import_react9.useContext)(FeatureFlagContext);
@@ -5511,6 +5943,7 @@ var useFeatureFlags = () => {
5511
5943
  ContextMenuSubContent,
5512
5944
  ContextMenuSubTrigger,
5513
5945
  ContextMenuTrigger,
5946
+ DEFAULT_NAME_COL_WIDTH,
5514
5947
  DflRemote,
5515
5948
  Dialog,
5516
5949
  DialogClose,
@@ -5555,6 +5988,7 @@ var useFeatureFlags = () => {
5555
5988
  FormItem,
5556
5989
  FormLabel,
5557
5990
  FormMessage,
5991
+ Gantt,
5558
5992
  HoverCard,
5559
5993
  HoverCardContent,
5560
5994
  HoverCardTrigger,
@@ -5695,7 +6129,9 @@ var useFeatureFlags = () => {
5695
6129
  UserAvatar,
5696
6130
  UserMenu,
5697
6131
  badgeVariants,
6132
+ barGridColumn,
5698
6133
  buttonVariants,
6134
+ clampPct,
5699
6135
  cn,
5700
6136
  filterPublishableAccounts,
5701
6137
  getInitials,
@@ -5707,6 +6143,10 @@ var useFeatureFlags = () => {
5707
6143
  memberHueVar,
5708
6144
  navigationMenuTriggerStyle,
5709
6145
  parseTags,
6146
+ resolveNameColWidth,
6147
+ resolveWeekCount,
6148
+ resolveWeekLabels,
6149
+ stageProgress,
5710
6150
  toast,
5711
6151
  toggleVariants,
5712
6152
  useAuth,