organify-ui 0.3.3 → 0.3.4

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
@@ -1,14 +1,14 @@
1
1
  export { I18nProvider, createTranslator, useI18n } from './chunk-FQA33MF4.js';
2
2
  export { ThemeProvider, useTheme } from './chunk-RFOKENE3.js';
3
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, Separator, ResponsiveDialog, Label, Input, Textarea, Button, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from './chunk-Z7OW3K7Y.js';
4
- export { Alert, Button, ChatMessages, ChatSidebar, CreateRoomDialog, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, Input, Label, MOCK_PROJECTS, MOCK_USERS, OrgLoader, OrgLoaderInline, OrganifyChat, ResponsiveDialog, RoomManagementPanel, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, TypingIndicatorMock, alertVariants, buttonVariants, generateAutoReplies, getMockMentionOptions, getRoomPermissions, inputVariants, orgLoaderVariants, typingIndicator, useChat } from './chunk-Z7OW3K7Y.js';
3
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, Separator, ResponsiveDialog, Label, Input, Textarea, Button, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from './chunk-NUA6OPJV.js';
4
+ export { AiChatSidebar, Alert, Button, ChatMessages, ChatSidebar, CreateRoomDialog, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, Input, Label, MOCK_PROJECTS, MOCK_USERS, OrgLoader, OrgLoaderInline, OrganifyChat, ResponsiveDialog, RoomManagementPanel, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, TypingIndicatorMock, alertVariants, buttonVariants, generateAutoReplies, getMockMentionOptions, getRoomPermissions, inputVariants, orgLoaderVariants, typingIndicator, useChat } from './chunk-NUA6OPJV.js';
5
5
  import { Popover, PopoverTrigger, PopoverContent } from './chunk-A2H2TBSV.js';
6
6
  export { NotificationBell, NotificationItem, NotificationList, OrganifyNotifications, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PresenceAvatarStack, PresenceIndicator, useNotifications, usePresence } from './chunk-A2H2TBSV.js';
7
7
  import { cn, Avatar, AvatarImage, AvatarFallback, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, Skeleton, useOrganify, useOrganifyGql, ScrollArea, useOrganifyUser, useOrganifyApi, Badge, useOrganifyWorkspace, useOrganifyNavigation, useOrganifyProject } from './chunk-VHQZS77G.js';
8
8
  export { Avatar, AvatarFallback, AvatarImage, Badge, OrganifyContext, OrganifyProvider, ScrollArea, ScrollBar, Skeleton, SkeletonCard, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, avatarVariants, badgeVariants, cn, useOrganify, useOrganifyApi, useOrganifyGql, useOrganifyNavigation, useOrganifyProject, useOrganifyRest, useOrganifyUser, useOrganifyWorkspace } from './chunk-VHQZS77G.js';
9
9
  import { OrgDiamond, OrgPlus, OrgComment, OrgEdit, OrgTrash, OrgCheckCircle, OrgAttachment, OrgCalendar, OrgMail, OrgBoard, OrgSprint, OrgRocket, OrgWarning, OrgFlag, OrgShield, OrgZap, OrgStar } from './chunk-MZKEDV5W.js';
10
10
  export { OrgAI, OrgActivity, OrgArrowLeft, OrgArrowRight, OrgAttachment, OrgBell, OrgBoard, OrgCalendar, OrgCelebrate, OrgChart, OrgChat, OrgCheck, OrgCheckCircle, OrgChevronDown, OrgChevronLeft, OrgChevronRight, OrgChevronUp, OrgClock, OrgClose, OrgComment, OrgCopy, OrgCreditCard, OrgDeveloper, OrgDiamond, OrgDoor, OrgDownload, OrgEdit, OrgError, OrgExecutive, OrgEye, OrgEyeOff, OrgFile, OrgFilter, OrgFlag, OrgFolder, OrgGauge, OrgGlobe, OrgGrid, OrgHeart, OrgHome, OrgInfo, OrgIntegration, OrgLink, OrgList, OrgLock, OrgLogo, OrgLogout, OrgMail, OrgMention, OrgMenu, OrgMoon, OrgPMO, OrgPause, OrgPlay, OrgPlus, OrgProjectManager, OrgReport, OrgRocket, OrgSearch, OrgSettings, OrgShield, OrgSort, OrgSprint, OrgStakeholder, OrgStar, OrgSun, OrgTag, OrgTarget, OrgTeam, OrgTrash, OrgTutorial, OrgUnlock, OrgUpload, OrgUser, OrgWarning, OrgWave, OrgWordmark, OrgWorkflow, OrgWorkspace, OrgZap } from './chunk-MZKEDV5W.js';
11
- import * as React4 from 'react';
11
+ import * as React5 from 'react';
12
12
  import * as SwitchPrimitive from '@radix-ui/react-switch';
13
13
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
14
14
  import * as ProgressPrimitive from '@radix-ui/react-progress';
@@ -25,8 +25,8 @@ export { toast } from 'sonner';
25
25
  import { useQueryClient, useQuery } from '@tanstack/react-query';
26
26
  export { QueryClient, QueryClientProvider } from '@tanstack/react-query';
27
27
 
28
- var Toggle = React4.forwardRef(({ className, label, description, ...props }, ref) => {
29
- const id = React4.useId();
28
+ var Toggle = React5.forwardRef(({ className, label, description, ...props }, ref) => {
29
+ const id = React5.useId();
30
30
  if (label) {
31
31
  return /* @__PURE__ */ jsxs(
32
32
  "div",
@@ -167,7 +167,7 @@ function UserAvatar({
167
167
  ] }) });
168
168
  }
169
169
  UserAvatar.displayName = "UserAvatar";
170
- var Progress = React4.forwardRef(({ className, value, showLabel, label, variant = "default", ...props }, ref) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
170
+ var Progress = React5.forwardRef(({ className, value, showLabel, label, variant = "default", ...props }, ref) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
171
171
  (label || showLabel) && /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between", children: [
172
172
  label && /* @__PURE__ */ jsx("span", { className: "text-label uppercase tracking-widest text-org-text-muted", children: label }),
173
173
  showLabel && /* @__PURE__ */ jsxs("span", { className: "font-mono text-lg text-primary-light", children: [
@@ -345,8 +345,8 @@ function EmptyState({
345
345
  );
346
346
  }
347
347
  function useMediaQuery(query) {
348
- const [matches, setMatches] = React4.useState(false);
349
- React4.useEffect(() => {
348
+ const [matches, setMatches] = React5.useState(false);
349
+ React5.useEffect(() => {
350
350
  const mql = window.matchMedia(query);
351
351
  setMatches(mql.matches);
352
352
  const handler = (e) => setMatches(e.matches);
@@ -763,77 +763,127 @@ function DockSidebar({
763
763
  onExpandedChange,
764
764
  hoverExpand = false,
765
765
  renderLink,
766
+ mobileOpen = false,
767
+ onMobileClose,
766
768
  className,
767
769
  // Destructure hoverExpand out so it doesn't leak to DOM via ...props
768
770
  ...props
769
771
  }) {
770
772
  const handleToggle = () => onExpandedChange?.(!expanded);
771
- return /* @__PURE__ */ jsxs(
772
- "aside",
773
- {
774
- className: cn(
775
- sidebarVariants({ state: expanded ? "expanded" : "collapsed" }),
776
- className
777
- ),
778
- onMouseEnter: () => hoverExpand && onExpandedChange?.(true),
779
- onMouseLeave: () => hoverExpand && onExpandedChange?.(false),
780
- ...props,
781
- children: [
782
- /* @__PURE__ */ jsxs("div", { className: cn("flex items-center px-3 h-16 border-b border-white/10", expanded ? "justify-between" : "justify-center"), children: [
783
- header,
784
- /* @__PURE__ */ jsx(
785
- "button",
786
- {
787
- type: "button",
788
- onClick: handleToggle,
789
- "aria-label": expanded ? "Collapse sidebar" : "Expand sidebar",
790
- className: cn(
791
- "flex h-7 w-7 items-center justify-center rounded-xl",
792
- "text-org-text-muted transition-all hover:bg-white/[0.05] hover:text-org-text"
773
+ React5.useEffect(() => {
774
+ if (!mobileOpen) return;
775
+ const onKey = (e) => {
776
+ if (e.key === "Escape") onMobileClose?.();
777
+ };
778
+ document.addEventListener("keydown", onKey);
779
+ return () => document.removeEventListener("keydown", onKey);
780
+ }, [mobileOpen, onMobileClose]);
781
+ React5.useEffect(() => {
782
+ if (!mobileOpen) return;
783
+ document.body.style.overflow = "hidden";
784
+ return () => {
785
+ document.body.style.overflow = "";
786
+ };
787
+ }, [mobileOpen]);
788
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
789
+ mobileOpen && /* @__PURE__ */ jsx(
790
+ "div",
791
+ {
792
+ className: "fixed inset-0 z-[49] bg-black/60 backdrop-blur-sm sm:hidden animate-in fade-in duration-200",
793
+ onClick: onMobileClose,
794
+ "aria-hidden": "true"
795
+ }
796
+ ),
797
+ /* @__PURE__ */ jsxs(
798
+ "aside",
799
+ {
800
+ className: cn(
801
+ // Desktop: normal fixed sidebar
802
+ "hidden sm:flex",
803
+ sidebarVariants({ state: expanded ? "expanded" : "collapsed" }),
804
+ // Mobile: overlay drawer mode
805
+ mobileOpen && "flex sm:flex fixed inset-y-0 left-0 z-50 w-64 shadow-2xl shadow-black/50 animate-in slide-in-from-left duration-300",
806
+ !mobileOpen && "max-sm:hidden",
807
+ className
808
+ ),
809
+ onMouseEnter: () => hoverExpand && onExpandedChange?.(true),
810
+ onMouseLeave: () => hoverExpand && onExpandedChange?.(false),
811
+ ...props,
812
+ children: [
813
+ /* @__PURE__ */ jsxs("div", { className: cn(
814
+ "flex items-center px-3 h-16 border-b border-white/10",
815
+ expanded || mobileOpen ? "justify-between" : "justify-center"
816
+ ), children: [
817
+ header,
818
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
819
+ mobileOpen && /* @__PURE__ */ jsx(
820
+ "button",
821
+ {
822
+ type: "button",
823
+ onClick: onMobileClose,
824
+ "aria-label": "Fechar menu",
825
+ className: "flex h-7 w-7 items-center justify-center rounded-xl text-org-text-muted hover:bg-white/[0.05] hover:text-org-text sm:hidden",
826
+ children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M4 4L12 12M12 4L4 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) })
827
+ }
793
828
  ),
794
- children: /* @__PURE__ */ jsx(
795
- "svg",
829
+ /* @__PURE__ */ jsx(
830
+ "button",
796
831
  {
797
- width: "16",
798
- height: "16",
799
- viewBox: "0 0 16 16",
800
- fill: "none",
832
+ type: "button",
833
+ onClick: handleToggle,
834
+ "aria-label": expanded ? "Collapse sidebar" : "Expand sidebar",
801
835
  className: cn(
802
- "transition-transform duration-[400ms]",
803
- expanded ? "rotate-0" : "rotate-180"
836
+ "hidden sm:flex h-7 w-7 items-center justify-center rounded-xl",
837
+ "text-org-text-muted transition-all hover:bg-white/[0.05] hover:text-org-text"
804
838
  ),
805
- children: /* @__PURE__ */ jsx("path", { d: "M10 12L6 8L10 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
839
+ children: /* @__PURE__ */ jsx(
840
+ "svg",
841
+ {
842
+ width: "16",
843
+ height: "16",
844
+ viewBox: "0 0 16 16",
845
+ fill: "none",
846
+ className: cn(
847
+ "transition-transform duration-[400ms]",
848
+ expanded ? "rotate-0" : "rotate-180"
849
+ ),
850
+ children: /* @__PURE__ */ jsx("path", { d: "M10 12L6 8L10 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
851
+ }
852
+ )
806
853
  }
807
854
  )
808
- }
809
- )
810
- ] }),
811
- /* @__PURE__ */ jsx("nav", { className: "flex-1 overflow-y-auto overflow-x-hidden py-2 px-2 space-y-0.5", children: items.map((entry, i) => /* @__PURE__ */ jsx(
812
- SidebarEntry,
813
- {
814
- entry,
815
- expanded,
816
- renderLink
817
- },
818
- isSeparator(entry) ? `sep-${i}` : entry.id
819
- )) }),
820
- bottomItems && bottomItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-t border-white/10 py-2 px-2 space-y-0.5", children: bottomItems.map((entry, i) => /* @__PURE__ */ jsx(
821
- SidebarEntry,
822
- {
823
- entry,
824
- expanded,
825
- renderLink
826
- },
827
- isSeparator(entry) ? `bsep-${i}` : entry.id
828
- )) })
829
- ]
830
- }
831
- );
855
+ ] })
856
+ ] }),
857
+ /* @__PURE__ */ jsx("nav", { className: "flex-1 overflow-y-auto overflow-x-hidden py-2 px-2 space-y-0.5", children: items.map((entry, i) => /* @__PURE__ */ jsx(
858
+ SidebarEntry,
859
+ {
860
+ entry,
861
+ expanded: expanded || mobileOpen,
862
+ renderLink,
863
+ onNavigate: mobileOpen ? onMobileClose : void 0
864
+ },
865
+ isSeparator(entry) ? `sep-${i}` : entry.id
866
+ )) }),
867
+ bottomItems && bottomItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-t border-white/10 py-2 px-2 space-y-0.5", children: bottomItems.map((entry, i) => /* @__PURE__ */ jsx(
868
+ SidebarEntry,
869
+ {
870
+ entry,
871
+ expanded: expanded || mobileOpen,
872
+ renderLink,
873
+ onNavigate: mobileOpen ? onMobileClose : void 0
874
+ },
875
+ isSeparator(entry) ? `bsep-${i}` : entry.id
876
+ )) })
877
+ ]
878
+ }
879
+ )
880
+ ] });
832
881
  }
833
882
  function SidebarEntry({
834
883
  entry,
835
884
  expanded,
836
- renderLink
885
+ renderLink,
886
+ onNavigate
837
887
  }) {
838
888
  if (isSeparator(entry)) {
839
889
  return /* @__PURE__ */ jsxs("div", { className: "py-2", children: [
@@ -846,16 +896,22 @@ function SidebarEntry({
846
896
  {
847
897
  item: entry,
848
898
  expanded,
849
- renderLink
899
+ renderLink,
900
+ onNavigate
850
901
  }
851
902
  );
852
903
  }
853
904
  function SidebarButton({
854
905
  item,
855
906
  expanded,
856
- renderLink
907
+ renderLink,
908
+ onNavigate
857
909
  }) {
858
910
  const { icon, label, href, onClick, active, badge, disabled } = item;
911
+ const handleClick = () => {
912
+ onClick?.();
913
+ onNavigate?.();
914
+ };
859
915
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
860
916
  /* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-xl transition-all", children: icon }),
861
917
  /* @__PURE__ */ jsx(
@@ -891,13 +947,13 @@ function SidebarButton({
891
947
  !expanded && "justify-center"
892
948
  );
893
949
  if (href && renderLink) {
894
- return renderLink({ href, children: content, className: sharedClass, onClick });
950
+ return renderLink({ href, children: content, className: sharedClass, onClick: handleClick });
895
951
  }
896
952
  return /* @__PURE__ */ jsxs(
897
953
  "button",
898
954
  {
899
955
  type: "button",
900
- onClick,
956
+ onClick: handleClick,
901
957
  disabled,
902
958
  "aria-current": active ? "page" : void 0,
903
959
  className: sharedClass,
@@ -964,12 +1020,12 @@ function WorkspaceSwitcher({ compact = false, onCreateWorkspace, className }) {
964
1020
  onWorkspaceChange
965
1021
  } = useOrganify();
966
1022
  const gql = useOrganifyGql();
967
- const [isOpen, setIsOpen] = React4.useState(false);
968
- const [createDialogOpen, setCreateDialogOpen] = React4.useState(false);
969
- const [editingWorkspace, setEditingWorkspace] = React4.useState(null);
970
- const [deletingWorkspace, setDeletingWorkspace] = React4.useState(null);
971
- const dropdownRef = React4.useRef(null);
972
- React4.useEffect(() => {
1023
+ const [isOpen, setIsOpen] = React5.useState(false);
1024
+ const [createDialogOpen, setCreateDialogOpen] = React5.useState(false);
1025
+ const [editingWorkspace, setEditingWorkspace] = React5.useState(null);
1026
+ const [deletingWorkspace, setDeletingWorkspace] = React5.useState(null);
1027
+ const dropdownRef = React5.useRef(null);
1028
+ React5.useEffect(() => {
973
1029
  function handleClickOutside(event) {
974
1030
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
975
1031
  setIsOpen(false);
@@ -978,7 +1034,7 @@ function WorkspaceSwitcher({ compact = false, onCreateWorkspace, className }) {
978
1034
  document.addEventListener("mousedown", handleClickOutside);
979
1035
  return () => document.removeEventListener("mousedown", handleClickOutside);
980
1036
  }, []);
981
- const handleCreateWorkspace = React4.useCallback(
1037
+ const handleCreateWorkspace = React5.useCallback(
982
1038
  async (data) => {
983
1039
  const optimisticId = `temp-${Date.now()}`;
984
1040
  const optimisticSlug = data.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -1018,7 +1074,7 @@ function WorkspaceSwitcher({ compact = false, onCreateWorkspace, className }) {
1018
1074
  },
1019
1075
  [workspaces, gql, onWorkspacesChange, onWorkspaceChange, onCreateWorkspace]
1020
1076
  );
1021
- const handleUpdateWorkspace = React4.useCallback(
1077
+ const handleUpdateWorkspace = React5.useCallback(
1022
1078
  async (slug, data) => {
1023
1079
  const prevWorkspaces = [...workspaces];
1024
1080
  const prevActive = workspace;
@@ -1053,7 +1109,7 @@ function WorkspaceSwitcher({ compact = false, onCreateWorkspace, className }) {
1053
1109
  },
1054
1110
  [workspaces, workspace, gql, onWorkspacesChange, onWorkspaceChange]
1055
1111
  );
1056
- const handleDeleteWorkspace = React4.useCallback(
1112
+ const handleDeleteWorkspace = React5.useCallback(
1057
1113
  async (slug) => {
1058
1114
  const prevWorkspaces = [...workspaces];
1059
1115
  const prevActive = workspace;
@@ -1242,7 +1298,7 @@ function SwitcherItem({
1242
1298
  onEdit,
1243
1299
  onDelete
1244
1300
  }) {
1245
- const [showActions, setShowActions] = React4.useState(false);
1301
+ const [showActions, setShowActions] = React5.useState(false);
1246
1302
  const isOptimistic = ws.id.startsWith("temp-");
1247
1303
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
1248
1304
  /* @__PURE__ */ jsx(
@@ -1316,11 +1372,11 @@ function CreateWorkspaceInlineDialog({
1316
1372
  onOpenChange,
1317
1373
  onSubmit
1318
1374
  }) {
1319
- const [name, setName] = React4.useState("");
1320
- const [description, setDescription] = React4.useState("");
1321
- const [loading, setLoading] = React4.useState(false);
1322
- const [error, setError] = React4.useState("");
1323
- React4.useEffect(() => {
1375
+ const [name, setName] = React5.useState("");
1376
+ const [description, setDescription] = React5.useState("");
1377
+ const [loading, setLoading] = React5.useState(false);
1378
+ const [error, setError] = React5.useState("");
1379
+ React5.useEffect(() => {
1324
1380
  if (open) {
1325
1381
  setName("");
1326
1382
  setDescription("");
@@ -1393,11 +1449,11 @@ function EditWorkspaceDialog({
1393
1449
  workspace,
1394
1450
  onSubmit
1395
1451
  }) {
1396
- const [name, setName] = React4.useState("");
1397
- const [description, setDescription] = React4.useState("");
1398
- const [loading, setLoading] = React4.useState(false);
1399
- const [error, setError] = React4.useState("");
1400
- React4.useEffect(() => {
1452
+ const [name, setName] = React5.useState("");
1453
+ const [description, setDescription] = React5.useState("");
1454
+ const [loading, setLoading] = React5.useState(false);
1455
+ const [error, setError] = React5.useState("");
1456
+ React5.useEffect(() => {
1401
1457
  if (open && workspace) {
1402
1458
  setName(workspace.name);
1403
1459
  setDescription(workspace.description ?? "");
@@ -1471,10 +1527,10 @@ function DeleteWorkspaceDialog({
1471
1527
  workspace,
1472
1528
  onConfirm
1473
1529
  }) {
1474
- const [loading, setLoading] = React4.useState(false);
1475
- const [error, setError] = React4.useState("");
1476
- const [confirmText, setConfirmText] = React4.useState("");
1477
- React4.useEffect(() => {
1530
+ const [loading, setLoading] = React5.useState(false);
1531
+ const [error, setError] = React5.useState("");
1532
+ const [confirmText, setConfirmText] = React5.useState("");
1533
+ React5.useEffect(() => {
1478
1534
  if (open) {
1479
1535
  setError("");
1480
1536
  setConfirmText("");
@@ -4104,7 +4160,7 @@ function SheetContent({
4104
4160
  "data-slot": "sheet-content",
4105
4161
  className: cn(
4106
4162
  "data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-xl dark:shadow-[0_24px_80px_-15px_rgba(0,0,0,0.8)] transition ease-[cubic-bezier(0.25,1,0.5,1)] data-[state=closed]:duration-300 data-[state=open]:duration-500",
4107
- "border-gray-300 bg-white text-gray-900 dark:border-gray-700 dark:bg-gray-900 dark:text-white",
4163
+ "[background:var(--org-bg-elevated,#110E22)] [color:var(--org-text,#F0ECF9)] [border-color:var(--org-glass-border,rgba(167,139,250,0.15))]",
4108
4164
  side === "right" && "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l-2 sm:max-w-sm",
4109
4165
  side === "left" && "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r-2 sm:max-w-sm",
4110
4166
  side === "top" && "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b-2",
@@ -4202,9 +4258,9 @@ function CommentItem({
4202
4258
  onDelete,
4203
4259
  onReact
4204
4260
  }) {
4205
- const [editing, setEditing] = React4.useState(false);
4206
- const [editContent, setEditContent] = React4.useState(comment.content);
4207
- const [showReactions, setShowReactions] = React4.useState(false);
4261
+ const [editing, setEditing] = React5.useState(false);
4262
+ const [editContent, setEditContent] = React5.useState(comment.content);
4263
+ const [showReactions, setShowReactions] = React5.useState(false);
4208
4264
  const isAuthor = comment.author.id === currentUser.id;
4209
4265
  const isPending = comment._status === "pending";
4210
4266
  const isError = comment._status === "error";
@@ -4368,9 +4424,9 @@ function CommentInput({
4368
4424
  compact = false,
4369
4425
  alwaysExpanded = true
4370
4426
  }) {
4371
- const [content, setContent] = React4.useState("");
4372
- const textareaRef = React4.useRef(null);
4373
- React4.useEffect(() => {
4427
+ const [content, setContent] = React5.useState("");
4428
+ const textareaRef = React5.useRef(null);
4429
+ React5.useEffect(() => {
4374
4430
  if (autoFocus && textareaRef.current) {
4375
4431
  textareaRef.current.focus();
4376
4432
  }
@@ -4490,7 +4546,7 @@ function CommentThread({
4490
4546
  displayName: providerUser?.name ?? "",
4491
4547
  avatarUrl: providerUser?.avatarUrl ?? null
4492
4548
  };
4493
- const effectiveOnFetch = React4.useCallback(
4549
+ const effectiveOnFetch = React5.useCallback(
4494
4550
  async (_entityType, _entityId) => {
4495
4551
  if (onFetch) return onFetch(_entityType, _entityId);
4496
4552
  const data = await gql(
@@ -4509,7 +4565,7 @@ function CommentThread({
4509
4565
  // eslint-disable-next-line react-hooks/exhaustive-deps
4510
4566
  [gql, onFetch]
4511
4567
  );
4512
- const effectiveOnAdd = React4.useCallback(
4568
+ const effectiveOnAdd = React5.useCallback(
4513
4569
  async (input) => {
4514
4570
  if (onAdd) return onAdd(input);
4515
4571
  const data = await gql(
@@ -4526,7 +4582,7 @@ function CommentThread({
4526
4582
  // eslint-disable-next-line react-hooks/exhaustive-deps
4527
4583
  [gql, onAdd, currentUser.id]
4528
4584
  );
4529
- const effectiveOnEdit = React4.useCallback(
4585
+ const effectiveOnEdit = React5.useCallback(
4530
4586
  async (commentId, content) => {
4531
4587
  if (onEdit) return onEdit(commentId, content);
4532
4588
  const data = await gql(
@@ -4548,7 +4604,7 @@ function CommentThread({
4548
4604
  },
4549
4605
  [gql, onEdit]
4550
4606
  );
4551
- const effectiveOnDelete = React4.useCallback(
4607
+ const effectiveOnDelete = React5.useCallback(
4552
4608
  async (commentId) => {
4553
4609
  if (onDelete) return onDelete(commentId);
4554
4610
  await gql(
@@ -4559,15 +4615,15 @@ function CommentThread({
4559
4615
  },
4560
4616
  [gql, onDelete]
4561
4617
  );
4562
- const [comments, setComments] = React4.useState(externalComments || []);
4563
- const [loading, setLoading] = React4.useState(!externalComments);
4564
- const [showAll, setShowAll] = React4.useState(false);
4565
- const [replyingTo, setReplyingTo] = React4.useState(null);
4566
- const hasFetchedRef = React4.useRef(false);
4567
- React4.useEffect(() => {
4618
+ const [comments, setComments] = React5.useState(externalComments || []);
4619
+ const [loading, setLoading] = React5.useState(!externalComments);
4620
+ const [showAll, setShowAll] = React5.useState(false);
4621
+ const [replyingTo, setReplyingTo] = React5.useState(null);
4622
+ const hasFetchedRef = React5.useRef(false);
4623
+ React5.useEffect(() => {
4568
4624
  hasFetchedRef.current = false;
4569
4625
  }, [entityId, entityType]);
4570
- React4.useEffect(() => {
4626
+ React5.useEffect(() => {
4571
4627
  if (externalComments) return;
4572
4628
  if (hasFetchedRef.current) return;
4573
4629
  hasFetchedRef.current = true;
@@ -4585,12 +4641,12 @@ function CommentThread({
4585
4641
  cancelled = true;
4586
4642
  };
4587
4643
  }, [entityType, entityId, externalComments, effectiveOnFetch]);
4588
- React4.useEffect(() => {
4644
+ React5.useEffect(() => {
4589
4645
  if (externalComments) {
4590
4646
  setComments(externalComments);
4591
4647
  }
4592
4648
  }, [externalComments]);
4593
- React4.useEffect(() => {
4649
+ React5.useEffect(() => {
4594
4650
  if (externalComments || onFetch) return;
4595
4651
  if (!entityId || entityType !== "task") return;
4596
4652
  const projectsServiceUrl = api?.services?.projects || api?.gatewayUrl;
@@ -4850,7 +4906,7 @@ function CommentThread({
4850
4906
  /* @__PURE__ */ jsx("p", { className: "text-[11px] text-theme-muted mt-0.5", children: "Seja o primeiro a comentar." })
4851
4907
  ] }),
4852
4908
  !loading && visibleComments.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
4853
- visibleComments.map((comment) => /* @__PURE__ */ jsxs(React4.Fragment, { children: [
4909
+ visibleComments.map((comment) => /* @__PURE__ */ jsxs(React5.Fragment, { children: [
4854
4910
  /* @__PURE__ */ jsx(
4855
4911
  CommentItem,
4856
4912
  {
@@ -4939,11 +4995,11 @@ function LabelPicker({
4939
4995
  trigger,
4940
4996
  disabled = false
4941
4997
  }) {
4942
- const [open, setOpen] = React4.useState(false);
4943
- const [search, setSearch] = React4.useState("");
4944
- const [isCreating, setIsCreating] = React4.useState(false);
4945
- const [newLabelName, setNewLabelName] = React4.useState("");
4946
- const [newLabelColor, setNewLabelColor] = React4.useState(presetColors[8]);
4998
+ const [open, setOpen] = React5.useState(false);
4999
+ const [search, setSearch] = React5.useState("");
5000
+ const [isCreating, setIsCreating] = React5.useState(false);
5001
+ const [newLabelName, setNewLabelName] = React5.useState("");
5002
+ const [newLabelColor, setNewLabelColor] = React5.useState(presetColors[8]);
4947
5003
  const selectedIds = new Set(selectedLabels.map((l) => l.id));
4948
5004
  const filteredLabels = availableLabels.filter(
4949
5005
  (label) => label.name.toLowerCase().includes(search.toLowerCase())
@@ -5098,8 +5154,8 @@ function AssigneePicker({
5098
5154
  disabled = false,
5099
5155
  maxAssignees
5100
5156
  }) {
5101
- const [open, setOpen] = React4.useState(false);
5102
- const [search, setSearch] = React4.useState("");
5157
+ const [open, setOpen] = React5.useState(false);
5158
+ const [search, setSearch] = React5.useState("");
5103
5159
  const selectedIds = new Set(selectedAssignees.map((a) => a.id));
5104
5160
  const canAddMore = maxAssignees ? selectedAssignees.length < maxAssignees : true;
5105
5161
  const filteredUsers = availableUsers.filter(
@@ -5184,8 +5240,8 @@ var statusColors = {
5184
5240
  DONE: "bg-emerald-500/15 text-emerald-400 border-emerald-500/30"
5185
5241
  };
5186
5242
  function useMediaQuery2(query) {
5187
- const [matches, setMatches] = React4.useState(false);
5188
- React4.useEffect(() => {
5243
+ const [matches, setMatches] = React5.useState(false);
5244
+ React5.useEffect(() => {
5189
5245
  const mql = window.matchMedia(query);
5190
5246
  setMatches(mql.matches);
5191
5247
  const handler = (e) => setMatches(e.matches);
@@ -5202,13 +5258,13 @@ function EditableField({
5202
5258
  inputClassName,
5203
5259
  as: Tag = "span"
5204
5260
  }) {
5205
- const [editing, setEditing] = React4.useState(false);
5206
- const [localValue, setLocalValue] = React4.useState(value);
5207
- const inputRef = React4.useRef(null);
5208
- React4.useEffect(() => {
5261
+ const [editing, setEditing] = React5.useState(false);
5262
+ const [localValue, setLocalValue] = React5.useState(value);
5263
+ const inputRef = React5.useRef(null);
5264
+ React5.useEffect(() => {
5209
5265
  setLocalValue(value);
5210
5266
  }, [value]);
5211
- React4.useEffect(() => {
5267
+ React5.useEffect(() => {
5212
5268
  if (editing && inputRef.current) {
5213
5269
  inputRef.current.focus();
5214
5270
  inputRef.current.select();
@@ -5262,9 +5318,9 @@ function EditableField({
5262
5318
  );
5263
5319
  }
5264
5320
  function EditableDate({ value, onSave, placeholder = "Adicionar data" }) {
5265
- const [editing, setEditing] = React4.useState(false);
5266
- const inputRef = React4.useRef(null);
5267
- React4.useEffect(() => {
5321
+ const [editing, setEditing] = React5.useState(false);
5322
+ const inputRef = React5.useRef(null);
5323
+ React5.useEffect(() => {
5268
5324
  if (editing && inputRef.current) {
5269
5325
  inputRef.current.focus();
5270
5326
  }
@@ -5348,13 +5404,13 @@ function AssigneeItem({ assignee, onRemove, showDelete = true }) {
5348
5404
  ] });
5349
5405
  }
5350
5406
  function SubtaskItem({ subtask, onToggle, onDelete, onUpdate }) {
5351
- const [editing, setEditing] = React4.useState(false);
5352
- const [localTitle, setLocalTitle] = React4.useState(subtask.title);
5353
- const inputRef = React4.useRef(null);
5354
- React4.useEffect(() => {
5407
+ const [editing, setEditing] = React5.useState(false);
5408
+ const [localTitle, setLocalTitle] = React5.useState(subtask.title);
5409
+ const inputRef = React5.useRef(null);
5410
+ React5.useEffect(() => {
5355
5411
  setLocalTitle(subtask.title);
5356
5412
  }, [subtask.title]);
5357
- React4.useEffect(() => {
5413
+ React5.useEffect(() => {
5358
5414
  if (editing && inputRef.current) {
5359
5415
  inputRef.current.focus();
5360
5416
  inputRef.current.select();
@@ -5428,10 +5484,10 @@ function SubtaskItem({ subtask, onToggle, onDelete, onUpdate }) {
5428
5484
  ] });
5429
5485
  }
5430
5486
  function SubtaskAddForm({ onAdd }) {
5431
- const [adding, setAdding] = React4.useState(false);
5432
- const [title, setTitle] = React4.useState("");
5433
- const inputRef = React4.useRef(null);
5434
- React4.useEffect(() => {
5487
+ const [adding, setAdding] = React5.useState(false);
5488
+ const [title, setTitle] = React5.useState("");
5489
+ const inputRef = React5.useRef(null);
5490
+ React5.useEffect(() => {
5435
5491
  if (adding && inputRef.current) {
5436
5492
  inputRef.current.focus();
5437
5493
  }
@@ -5519,7 +5575,7 @@ function SubtaskSection({
5519
5575
  onDelete,
5520
5576
  onUpdate
5521
5577
  }) {
5522
- const [loading, setLoading] = React4.useState(null);
5578
+ const [loading, setLoading] = React5.useState(null);
5523
5579
  const handleAdd = async (title) => {
5524
5580
  if (onAdd) {
5525
5581
  setLoading("add");
@@ -5977,7 +6033,7 @@ function TaskCard({
5977
6033
  className,
5978
6034
  ...props
5979
6035
  }) {
5980
- const [sheetOpen, setSheetOpen] = React4.useState(false);
6036
+ const [sheetOpen, setSheetOpen] = React5.useState(false);
5981
6037
  if (!task) {
5982
6038
  return /* @__PURE__ */ jsx(TaskCardSkeleton, { compact, className });
5983
6039
  }
@@ -6416,8 +6472,33 @@ function TaskCard2({
6416
6472
  isDragging,
6417
6473
  externalDnD,
6418
6474
  onDragStart,
6419
- onDragEnd
6475
+ onDragEnd,
6476
+ onTouchDragStart
6420
6477
  }) {
6478
+ const touchTimerRef = React5.useRef(null);
6479
+ const hasMoved = React5.useRef(false);
6480
+ const handleTouchStart = (e) => {
6481
+ hasMoved.current = false;
6482
+ touchTimerRef.current = setTimeout(() => {
6483
+ if (!hasMoved.current) {
6484
+ onTouchDragStart?.(task, columnId);
6485
+ if (navigator.vibrate) navigator.vibrate(50);
6486
+ }
6487
+ }, 300);
6488
+ };
6489
+ const handleTouchMove = () => {
6490
+ hasMoved.current = true;
6491
+ if (touchTimerRef.current) {
6492
+ clearTimeout(touchTimerRef.current);
6493
+ touchTimerRef.current = null;
6494
+ }
6495
+ };
6496
+ const handleTouchEnd = () => {
6497
+ if (touchTimerRef.current) {
6498
+ clearTimeout(touchTimerRef.current);
6499
+ touchTimerRef.current = null;
6500
+ }
6501
+ };
6421
6502
  const displayLabels = (task.labels || []).map(
6422
6503
  (label) => typeof label === "string" ? label : label.name
6423
6504
  );
@@ -6428,14 +6509,18 @@ function TaskCard2({
6428
6509
  onDragStart: !externalDnD ? (e) => onDragStart?.(e, task, columnId) : void 0,
6429
6510
  onDragEnd: !externalDnD ? onDragEnd : void 0,
6430
6511
  onClick,
6512
+ onTouchStart: handleTouchStart,
6513
+ onTouchMove: handleTouchMove,
6514
+ onTouchEnd: handleTouchEnd,
6431
6515
  "data-task-id": task.id,
6432
6516
  "data-column-id": columnId,
6433
6517
  "data-index": index,
6434
6518
  className: cn(
6435
- "group relative flex flex-col gap-2 p-3 cursor-pointer",
6519
+ "group relative flex flex-col gap-2 p-3 cursor-pointer select-none",
6436
6520
  "bg-theme-subtle backdrop-blur-md border border-theme-subtle",
6437
6521
  "transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] rounded-xl",
6438
6522
  "hover:border-primary-light/30",
6523
+ "active:scale-[0.98]",
6439
6524
  isDragging && "opacity-50 scale-95"
6440
6525
  ),
6441
6526
  children: [
@@ -6447,7 +6532,7 @@ function TaskCard2({
6447
6532
  children: /* @__PURE__ */ jsx(GripVertical, { className: "w-4 h-4" })
6448
6533
  }
6449
6534
  ),
6450
- /* @__PURE__ */ jsx("h4", { className: "text-sm font-medium text-theme pr-6", children: task.title }),
6535
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-medium text-theme pr-6 line-clamp-2", children: task.title }),
6451
6536
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
6452
6537
  task.priority && /* @__PURE__ */ jsx(
6453
6538
  Badge,
@@ -6488,18 +6573,19 @@ function Column({
6488
6573
  onDragEnd,
6489
6574
  onDragOver,
6490
6575
  onDrop,
6491
- isDropTarget
6576
+ isDropTarget,
6577
+ onTouchDragStart
6492
6578
  }) {
6493
- const [isRenaming, setIsRenaming] = React4.useState(false);
6494
- const [renameValue, setRenameValue] = React4.useState(column.title);
6495
- const renameInputRef = React4.useRef(null);
6496
- const [isAddingTask, setIsAddingTask] = React4.useState(false);
6497
- const [newTaskTitle, setNewTaskTitle] = React4.useState("");
6498
- const taskInputRef = React4.useRef(null);
6499
- React4.useEffect(() => {
6579
+ const [isRenaming, setIsRenaming] = React5.useState(false);
6580
+ const [renameValue, setRenameValue] = React5.useState(column.title);
6581
+ const renameInputRef = React5.useRef(null);
6582
+ const [isAddingTask, setIsAddingTask] = React5.useState(false);
6583
+ const [newTaskTitle, setNewTaskTitle] = React5.useState("");
6584
+ const taskInputRef = React5.useRef(null);
6585
+ React5.useEffect(() => {
6500
6586
  if (isRenaming) renameInputRef.current?.focus();
6501
6587
  }, [isRenaming]);
6502
- React4.useEffect(() => {
6588
+ React5.useEffect(() => {
6503
6589
  if (isAddingTask) taskInputRef.current?.focus();
6504
6590
  }, [isAddingTask]);
6505
6591
  const handleRenameSubmit = () => {
@@ -6543,9 +6629,10 @@ function Column({
6543
6629
  } : void 0,
6544
6630
  onDrop: !externalDnD ? (e) => onDrop?.(e, column.id) : void 0,
6545
6631
  className: cn(
6546
- "flex flex-col w-72 shrink-0 h-full",
6632
+ "flex flex-col w-[280px] sm:w-72 shrink-0 max-h-[calc(100vh-10rem)]",
6547
6633
  "bg-theme-glass backdrop-blur-md border border-theme-subtle rounded-xl",
6548
6634
  "transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)]",
6635
+ "snap-start",
6549
6636
  isDropTarget && "border-primary-light/50 bg-primary/5"
6550
6637
  ),
6551
6638
  children: [
@@ -6581,16 +6668,30 @@ function Column({
6581
6668
  children: column.title
6582
6669
  }
6583
6670
  ),
6584
- /* @__PURE__ */ jsx(
6671
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 shrink-0", children: /* @__PURE__ */ jsxs(
6585
6672
  Badge,
6586
6673
  {
6587
- variant: "default",
6588
- className: "bg-theme-highlight text-theme-muted border-theme-subtle text-xs shrink-0",
6589
- children: column.tasks.length
6674
+ variant: column.wipLimit && column.tasks.length > column.wipLimit ? "error" : "default",
6675
+ className: cn(
6676
+ "text-xs",
6677
+ column.wipLimit && column.tasks.length > column.wipLimit ? "bg-red-500/20 text-red-400 border-red-500/40 animate-pulse" : "bg-theme-highlight text-theme-muted border-theme-subtle"
6678
+ ),
6679
+ children: [
6680
+ column.tasks.length,
6681
+ column.wipLimit != null && /* @__PURE__ */ jsxs("span", { className: "text-theme-muted", children: [
6682
+ "/",
6683
+ column.wipLimit
6684
+ ] })
6685
+ ]
6590
6686
  }
6591
- )
6687
+ ) })
6688
+ ] }),
6689
+ column.wipLimit != null && column.tasks.length > column.wipLimit && /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 bg-red-500/10 border-b border-red-500/20 text-[10px] font-medium text-red-400 text-center", children: [
6690
+ "\u26A0 WIP limit exceeded (",
6691
+ column.tasks.length - column.wipLimit,
6692
+ " over)"
6592
6693
  ] }),
6593
- /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxs("div", { className: "p-2 space-y-2", children: [
6694
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1 min-h-0 [&_[data-radix-scroll-area-viewport]]:!overflow-y-auto [&_[data-radix-scroll-area-viewport]]:scrollbar-none", children: /* @__PURE__ */ jsxs("div", { className: "p-2 space-y-2", children: [
6594
6695
  column.tasks.map((task, index) => {
6595
6696
  const isDragging = draggedTask?.task.id === task.id;
6596
6697
  return /* @__PURE__ */ jsx(
@@ -6603,7 +6704,8 @@ function Column({
6603
6704
  isDragging,
6604
6705
  externalDnD,
6605
6706
  onDragStart,
6606
- onDragEnd
6707
+ onDragEnd,
6708
+ onTouchDragStart
6607
6709
  },
6608
6710
  task.id
6609
6711
  );
@@ -6687,16 +6789,40 @@ function KanbanBoard({
6687
6789
  onAddSubtask,
6688
6790
  onToggleSubtask,
6689
6791
  onDeleteSubtask,
6690
- onUpdateSubtask
6792
+ onUpdateSubtask,
6793
+ onTaskClick
6691
6794
  }) {
6692
- const [draggedTask, setDraggedTask] = React4.useState(null);
6693
- const [dropTargetColumnId, setDropTargetColumnId] = React4.useState(null);
6694
- const [sheetOpen, setSheetOpen] = React4.useState(false);
6695
- const [selectedTask, setSelectedTask] = React4.useState(null);
6696
- const [isAddingColumn, setIsAddingColumn] = React4.useState(false);
6697
- const [newColumnTitle, setNewColumnTitle] = React4.useState("");
6698
- const addColumnInputRef = React4.useRef(null);
6699
- React4.useEffect(() => {
6795
+ const [draggedTask, setDraggedTask] = React5.useState(null);
6796
+ const [dropTargetColumnId, setDropTargetColumnId] = React5.useState(null);
6797
+ const [touchDraggedTask, setTouchDraggedTask] = React5.useState(null);
6798
+ const handleTouchDragStart = React5.useCallback((task, fromColumnId) => {
6799
+ setTouchDraggedTask({ task, fromColumnId });
6800
+ }, []);
6801
+ const handleTouchDrop = React5.useCallback((toColumnId) => {
6802
+ if (!touchDraggedTask) return;
6803
+ const { task, fromColumnId } = touchDraggedTask;
6804
+ if (fromColumnId !== toColumnId) {
6805
+ onTaskMove?.(task.id, fromColumnId, toColumnId, 0);
6806
+ if (onColumnChange) {
6807
+ const newColumns = columns.map((col) => {
6808
+ if (col.id === fromColumnId) return { ...col, tasks: col.tasks.filter((t) => t.id !== task.id) };
6809
+ if (col.id === toColumnId) return { ...col, tasks: [...col.tasks, task] };
6810
+ return col;
6811
+ });
6812
+ onColumnChange(newColumns);
6813
+ }
6814
+ }
6815
+ setTouchDraggedTask(null);
6816
+ }, [touchDraggedTask, columns, onTaskMove, onColumnChange]);
6817
+ const cancelTouchDrag = React5.useCallback(() => setTouchDraggedTask(null), []);
6818
+ const isTouchDragging = touchDraggedTask !== null;
6819
+ const effectiveDraggedTask = draggedTask || touchDraggedTask;
6820
+ const [sheetOpen, setSheetOpen] = React5.useState(false);
6821
+ const [selectedTask, setSelectedTask] = React5.useState(null);
6822
+ const [isAddingColumn, setIsAddingColumn] = React5.useState(false);
6823
+ const [newColumnTitle, setNewColumnTitle] = React5.useState("");
6824
+ const addColumnInputRef = React5.useRef(null);
6825
+ React5.useEffect(() => {
6700
6826
  if (isAddingColumn) addColumnInputRef.current?.focus();
6701
6827
  }, [isAddingColumn]);
6702
6828
  const handleAddColumnSubmit = () => {
@@ -6717,6 +6843,10 @@ function KanbanBoard({
6717
6843
  }
6718
6844
  };
6719
6845
  const handleTaskClick = (task, columnId) => {
6846
+ if (onTaskClick) {
6847
+ onTaskClick(task.id);
6848
+ return;
6849
+ }
6720
6850
  setSelectedTask({ task, columnId });
6721
6851
  setSheetOpen(true);
6722
6852
  };
@@ -6758,8 +6888,9 @@ function KanbanBoard({
6758
6888
  "div",
6759
6889
  {
6760
6890
  className: cn(
6761
- "flex gap-4 p-4 overflow-x-auto h-full min-h-[400px]",
6762
- "bg-void",
6891
+ "flex gap-3 sm:gap-4 p-3 sm:p-4 overflow-x-auto h-full min-h-[400px]",
6892
+ "bg-void snap-x snap-mandatory sm:snap-none",
6893
+ "scrollbar-none",
6763
6894
  className
6764
6895
  ),
6765
6896
  children: [
@@ -6771,12 +6902,13 @@ function KanbanBoard({
6771
6902
  onAddTask,
6772
6903
  onRenameColumn,
6773
6904
  externalDnD,
6774
- draggedTask,
6905
+ draggedTask: effectiveDraggedTask,
6775
6906
  onDragStart: handleDragStart,
6776
6907
  onDragEnd: handleDragEnd,
6777
6908
  onDragOver: handleDragOver,
6778
6909
  onDrop: handleDrop,
6779
- isDropTarget: dropTargetColumnId === column.id
6910
+ isDropTarget: dropTargetColumnId === column.id,
6911
+ onTouchDragStart: handleTouchDragStart
6780
6912
  },
6781
6913
  column.id
6782
6914
  )),
@@ -6837,6 +6969,35 @@ function KanbanBoard({
6837
6969
  ]
6838
6970
  }
6839
6971
  ),
6972
+ isTouchDragging && /* @__PURE__ */ jsxs("div", { className: "fixed inset-x-0 bottom-0 z-50 flex gap-2 p-3 bg-void/90 backdrop-blur-xl border-t border-theme-subtle animate-in slide-in-from-bottom-4 duration-300 sm:hidden", children: [
6973
+ /* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto scrollbar-none flex gap-2", children: columns.filter((col) => col.id !== touchDraggedTask?.fromColumnId).map((col) => /* @__PURE__ */ jsxs(
6974
+ "button",
6975
+ {
6976
+ onClick: () => handleTouchDrop(col.id),
6977
+ className: cn(
6978
+ "flex-shrink-0 flex items-center gap-2 px-4 py-3 rounded-xl",
6979
+ "bg-theme-glass border border-theme-subtle",
6980
+ "text-sm font-medium text-theme",
6981
+ "active:bg-primary/20 active:border-primary-light/50",
6982
+ "transition-all duration-200"
6983
+ ),
6984
+ children: [
6985
+ col.color && /* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full shrink-0", style: { backgroundColor: col.color } }),
6986
+ col.title,
6987
+ /* @__PURE__ */ jsx(Badge, { className: "text-[10px] bg-theme-highlight text-theme-muted border-theme-subtle", children: col.tasks.length })
6988
+ ]
6989
+ },
6990
+ col.id
6991
+ )) }),
6992
+ /* @__PURE__ */ jsx(
6993
+ "button",
6994
+ {
6995
+ onClick: cancelTouchDrag,
6996
+ className: "shrink-0 p-3 rounded-xl bg-rose-500/20 text-rose-400 border border-rose-500/30",
6997
+ children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
6998
+ }
6999
+ )
7000
+ ] }),
6840
7001
  /* @__PURE__ */ jsx(
6841
7002
  TaskDetailSheet,
6842
7003
  {
@@ -7025,7 +7186,7 @@ function PlanBadgeFull({
7025
7186
  config.bgColor,
7026
7187
  config.borderColor
7027
7188
  ),
7028
- children: /* @__PURE__ */ jsx("span", { className: config.color, children: React4.cloneElement(config.icon, {
7189
+ children: /* @__PURE__ */ jsx("span", { className: config.color, children: React5.cloneElement(config.icon, {
7029
7190
  className: "w-5 h-5"
7030
7191
  }) })
7031
7192
  }
@@ -7326,7 +7487,7 @@ function Checkbox({
7326
7487
  }
7327
7488
  );
7328
7489
  }
7329
- var Switch = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7490
+ var Switch = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7330
7491
  SwitchPrimitive.Root,
7331
7492
  {
7332
7493
  className: cn(
@@ -7744,11 +7905,11 @@ function CreateProjectDialog({
7744
7905
  const gql = useOrganifyGql();
7745
7906
  const { workspace } = useOrganifyWorkspace();
7746
7907
  const { navigate } = useOrganifyNavigation();
7747
- const [name, setName] = React4.useState("");
7748
- const [type, setType] = React4.useState("KANBAN");
7749
- const [error, setError] = React4.useState("");
7750
- const [loading, setLoading] = React4.useState(false);
7751
- React4.useEffect(() => {
7908
+ const [name, setName] = React5.useState("");
7909
+ const [type, setType] = React5.useState("KANBAN");
7910
+ const [error, setError] = React5.useState("");
7911
+ const [loading, setLoading] = React5.useState(false);
7912
+ React5.useEffect(() => {
7752
7913
  if (open) {
7753
7914
  setName("");
7754
7915
  setType("KANBAN");
@@ -7864,10 +8025,10 @@ function CreateWorkspaceDialog({
7864
8025
  }) {
7865
8026
  const gql = useOrganifyGql();
7866
8027
  const { navigate } = useOrganifyNavigation();
7867
- const [name, setName] = React4.useState("");
7868
- const [error, setError] = React4.useState("");
7869
- const [loading, setLoading] = React4.useState(false);
7870
- React4.useEffect(() => {
8028
+ const [name, setName] = React5.useState("");
8029
+ const [error, setError] = React5.useState("");
8030
+ const [loading, setLoading] = React5.useState(false);
8031
+ React5.useEffect(() => {
7871
8032
  if (open) {
7872
8033
  setName("");
7873
8034
  setError("");
@@ -7957,13 +8118,13 @@ function CreateSprintDialog({
7957
8118
  const gql = useOrganifyGql();
7958
8119
  const { project } = useOrganifyProject();
7959
8120
  const effectiveProjectId = propProjectId ?? project?.id;
7960
- const [name, setName] = React4.useState("");
7961
- const [goal, setGoal] = React4.useState("");
7962
- const [startDate, setStartDate] = React4.useState("");
7963
- const [endDate, setEndDate] = React4.useState("");
7964
- const [error, setError] = React4.useState("");
7965
- const [loading, setLoading] = React4.useState(false);
7966
- React4.useEffect(() => {
8121
+ const [name, setName] = React5.useState("");
8122
+ const [goal, setGoal] = React5.useState("");
8123
+ const [startDate, setStartDate] = React5.useState("");
8124
+ const [endDate, setEndDate] = React5.useState("");
8125
+ const [error, setError] = React5.useState("");
8126
+ const [loading, setLoading] = React5.useState(false);
8127
+ React5.useEffect(() => {
7967
8128
  if (open) {
7968
8129
  setName("");
7969
8130
  setGoal("");
@@ -8104,12 +8265,12 @@ function CreateEpicDialog({
8104
8265
  const gql = useOrganifyGql();
8105
8266
  const { project } = useOrganifyProject();
8106
8267
  const effectiveProjectId = propProjectId ?? project?.id;
8107
- const [name, setName] = React4.useState("");
8108
- const [description, setDescription] = React4.useState("");
8109
- const [color, setColor] = React4.useState(EPIC_COLORS[0]);
8110
- const [error, setError] = React4.useState("");
8111
- const [loading, setLoading] = React4.useState(false);
8112
- React4.useEffect(() => {
8268
+ const [name, setName] = React5.useState("");
8269
+ const [description, setDescription] = React5.useState("");
8270
+ const [color, setColor] = React5.useState(EPIC_COLORS[0]);
8271
+ const [error, setError] = React5.useState("");
8272
+ const [loading, setLoading] = React5.useState(false);
8273
+ React5.useEffect(() => {
8113
8274
  if (open) {
8114
8275
  setName("");
8115
8276
  setDescription("");
@@ -8245,11 +8406,11 @@ function CreateTaskDialog({
8245
8406
  const gql = useOrganifyGql();
8246
8407
  const projectCtx = useOrganifyProject();
8247
8408
  const projectId = projectIdProp ?? projectCtx?.project?.id;
8248
- const [title, setTitle] = React4.useState("");
8249
- const [priority, setPriority] = React4.useState("NONE");
8250
- const [error, setError] = React4.useState("");
8251
- const [loading, setLoading] = React4.useState(false);
8252
- React4.useEffect(() => {
8409
+ const [title, setTitle] = React5.useState("");
8410
+ const [priority, setPriority] = React5.useState("NONE");
8411
+ const [error, setError] = React5.useState("");
8412
+ const [loading, setLoading] = React5.useState(false);
8413
+ React5.useEffect(() => {
8253
8414
  if (open) {
8254
8415
  setTitle("");
8255
8416
  setPriority("NONE");
@@ -8361,11 +8522,11 @@ function InviteMemberDialog({
8361
8522
  const gql = useOrganifyGql();
8362
8523
  const { workspace } = useOrganifyWorkspace();
8363
8524
  const effectiveWsId = propWorkspaceId ?? workspace?.id;
8364
- const [email, setEmail] = React4.useState("");
8365
- const [role, setRole] = React4.useState("MEMBER");
8366
- const [error, setError] = React4.useState("");
8367
- const [loading, setLoading] = React4.useState(false);
8368
- React4.useEffect(() => {
8525
+ const [email, setEmail] = React5.useState("");
8526
+ const [role, setRole] = React5.useState("MEMBER");
8527
+ const [error, setError] = React5.useState("");
8528
+ const [loading, setLoading] = React5.useState(false);
8529
+ React5.useEffect(() => {
8369
8530
  if (open) {
8370
8531
  setEmail("");
8371
8532
  setRole("MEMBER");