rita-workspace 0.1.1 → 0.2.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.mjs CHANGED
@@ -483,8 +483,513 @@ function Sidebar({ isOpen = true, onToggle, width = 250 }) {
483
483
  ] });
484
484
  }
485
485
 
486
+ // src/ui/Menu/WorkspaceMenuItems.tsx
487
+ import React4 from "react";
488
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
489
+ var DrawingsIcon = /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
490
+ /* @__PURE__ */ jsx5("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
491
+ /* @__PURE__ */ jsx5("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }),
492
+ /* @__PURE__ */ jsx5("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }),
493
+ /* @__PURE__ */ jsx5("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" })
494
+ ] });
495
+ var PlusIcon = /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
496
+ /* @__PURE__ */ jsx5("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
497
+ /* @__PURE__ */ jsx5("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
498
+ ] });
499
+ var DefaultMenuItem = ({ icon, children, onSelect, shortcut }) => /* @__PURE__ */ jsxs3(
500
+ "button",
501
+ {
502
+ onClick: onSelect,
503
+ className: "rita-workspace-menu-item",
504
+ style: {
505
+ display: "flex",
506
+ alignItems: "center",
507
+ gap: "8px",
508
+ width: "100%",
509
+ padding: "8px 12px",
510
+ border: "none",
511
+ background: "none",
512
+ cursor: "pointer",
513
+ textAlign: "left",
514
+ fontSize: "14px"
515
+ },
516
+ children: [
517
+ /* @__PURE__ */ jsx5("span", { style: { width: "20px", height: "20px" }, children: icon }),
518
+ /* @__PURE__ */ jsx5("span", { style: { flex: 1 }, children }),
519
+ shortcut && /* @__PURE__ */ jsx5("span", { style: { opacity: 0.5, fontSize: "12px" }, children: shortcut })
520
+ ]
521
+ }
522
+ );
523
+ var WorkspaceMenuItems = ({
524
+ onDrawingSelect,
525
+ onManageDrawings,
526
+ renderMenuItem,
527
+ renderSubMenu,
528
+ renderSeparator
529
+ }) => {
530
+ const { drawings, activeDrawing, switchDrawing, createNewDrawing } = useWorkspace();
531
+ const MenuItem = renderMenuItem || ((props) => /* @__PURE__ */ jsx5(DefaultMenuItem, { ...props }));
532
+ const Separator = renderSeparator || (() => /* @__PURE__ */ jsx5("hr", { style: { margin: "4px 0", border: "none", borderTop: "1px solid #ccc" } }));
533
+ const handleDrawingSelect = async (drawing) => {
534
+ await switchDrawing(drawing.id);
535
+ onDrawingSelect?.(drawing);
536
+ };
537
+ const handleNewDrawing = async () => {
538
+ await createNewDrawing();
539
+ };
540
+ if (renderSubMenu) {
541
+ return /* @__PURE__ */ jsx5(Fragment2, { children: renderSubMenu({
542
+ trigger: /* @__PURE__ */ jsxs3(Fragment2, { children: [
543
+ DrawingsIcon,
544
+ /* @__PURE__ */ jsxs3("span", { children: [
545
+ "Ritningar (",
546
+ drawings.length,
547
+ ")"
548
+ ] })
549
+ ] }),
550
+ children: /* @__PURE__ */ jsxs3(Fragment2, { children: [
551
+ drawings.map((drawing) => /* @__PURE__ */ jsx5(React4.Fragment, { children: MenuItem({
552
+ icon: activeDrawing?.id === drawing.id ? "\u2713" : " ",
553
+ children: drawing.name,
554
+ onSelect: () => handleDrawingSelect(drawing)
555
+ }) }, drawing.id)),
556
+ drawings.length > 0 && Separator(),
557
+ MenuItem({
558
+ icon: PlusIcon,
559
+ children: "Ny ritning",
560
+ onSelect: handleNewDrawing,
561
+ shortcut: "Ctrl+Alt+N"
562
+ }),
563
+ onManageDrawings && MenuItem({
564
+ icon: DrawingsIcon,
565
+ children: "Hantera ritningar...",
566
+ onSelect: onManageDrawings
567
+ })
568
+ ] })
569
+ }) });
570
+ }
571
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
572
+ MenuItem({
573
+ icon: PlusIcon,
574
+ children: "Ny ritning",
575
+ onSelect: handleNewDrawing,
576
+ shortcut: "Ctrl+Alt+N"
577
+ }),
578
+ drawings.slice(0, 5).map((drawing) => /* @__PURE__ */ jsx5(React4.Fragment, { children: MenuItem({
579
+ icon: activeDrawing?.id === drawing.id ? "\u2713" : DrawingsIcon,
580
+ children: drawing.name,
581
+ onSelect: () => handleDrawingSelect(drawing)
582
+ }) }, drawing.id)),
583
+ onManageDrawings && drawings.length > 5 && /* @__PURE__ */ jsxs3(Fragment2, { children: [
584
+ Separator(),
585
+ MenuItem({
586
+ icon: DrawingsIcon,
587
+ children: `Alla ritningar (${drawings.length})...`,
588
+ onSelect: onManageDrawings
589
+ })
590
+ ] })
591
+ ] });
592
+ };
593
+
594
+ // src/ui/Dialog/DrawingsDialog.tsx
595
+ import { useState as useState5, useCallback as useCallback2 } from "react";
596
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
597
+ var DrawingsDialog = ({
598
+ open,
599
+ onClose,
600
+ onDrawingSelect
601
+ }) => {
602
+ const {
603
+ drawings,
604
+ activeDrawing,
605
+ switchDrawing,
606
+ createNewDrawing,
607
+ renameDrawing,
608
+ removeDrawing
609
+ } = useWorkspace();
610
+ const [editingId, setEditingId] = useState5(null);
611
+ const [editName, setEditName] = useState5("");
612
+ const [confirmDeleteId, setConfirmDeleteId] = useState5(null);
613
+ const handleSelect = useCallback2(async (drawing) => {
614
+ await switchDrawing(drawing.id);
615
+ onDrawingSelect?.(drawing);
616
+ onClose();
617
+ }, [switchDrawing, onDrawingSelect, onClose]);
618
+ const handleCreate = useCallback2(async () => {
619
+ const newDrawing = await createNewDrawing();
620
+ if (newDrawing) {
621
+ onDrawingSelect?.(newDrawing);
622
+ onClose();
623
+ }
624
+ }, [createNewDrawing, onDrawingSelect, onClose]);
625
+ const handleStartEdit = useCallback2((drawing) => {
626
+ setEditingId(drawing.id);
627
+ setEditName(drawing.name);
628
+ }, []);
629
+ const handleSaveEdit = useCallback2(async () => {
630
+ if (editingId && editName.trim()) {
631
+ await renameDrawing(editingId, editName.trim());
632
+ setEditingId(null);
633
+ setEditName("");
634
+ }
635
+ }, [editingId, editName, renameDrawing]);
636
+ const handleCancelEdit = useCallback2(() => {
637
+ setEditingId(null);
638
+ setEditName("");
639
+ }, []);
640
+ const handleDelete = useCallback2(async (id) => {
641
+ await removeDrawing(id);
642
+ setConfirmDeleteId(null);
643
+ }, [removeDrawing]);
644
+ const formatDate = (timestamp) => {
645
+ return new Date(timestamp).toLocaleString("sv-SE", {
646
+ year: "numeric",
647
+ month: "short",
648
+ day: "numeric",
649
+ hour: "2-digit",
650
+ minute: "2-digit"
651
+ });
652
+ };
653
+ if (!open) return null;
654
+ return /* @__PURE__ */ jsx6(
655
+ "div",
656
+ {
657
+ className: "rita-workspace-dialog-overlay",
658
+ style: {
659
+ position: "fixed",
660
+ top: 0,
661
+ left: 0,
662
+ right: 0,
663
+ bottom: 0,
664
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
665
+ display: "flex",
666
+ alignItems: "center",
667
+ justifyContent: "center",
668
+ zIndex: 9999
669
+ },
670
+ onClick: (e) => {
671
+ if (e.target === e.currentTarget) onClose();
672
+ },
673
+ children: /* @__PURE__ */ jsxs4(
674
+ "div",
675
+ {
676
+ className: "rita-workspace-dialog",
677
+ style: {
678
+ backgroundColor: "var(--island-bg-color, #fff)",
679
+ borderRadius: "8px",
680
+ boxShadow: "0 4px 24px rgba(0, 0, 0, 0.2)",
681
+ width: "90%",
682
+ maxWidth: "600px",
683
+ maxHeight: "80vh",
684
+ display: "flex",
685
+ flexDirection: "column",
686
+ color: "var(--text-primary-color, #1b1b1f)"
687
+ },
688
+ children: [
689
+ /* @__PURE__ */ jsxs4(
690
+ "div",
691
+ {
692
+ style: {
693
+ padding: "16px 20px",
694
+ borderBottom: "1px solid var(--default-border-color, #e0e0e0)",
695
+ display: "flex",
696
+ alignItems: "center",
697
+ justifyContent: "space-between"
698
+ },
699
+ children: [
700
+ /* @__PURE__ */ jsxs4("h2", { style: { margin: 0, fontSize: "18px", fontWeight: 600 }, children: [
701
+ "Ritningar (",
702
+ drawings.length,
703
+ ")"
704
+ ] }),
705
+ /* @__PURE__ */ jsx6(
706
+ "button",
707
+ {
708
+ onClick: onClose,
709
+ style: {
710
+ background: "none",
711
+ border: "none",
712
+ fontSize: "24px",
713
+ cursor: "pointer",
714
+ padding: "4px",
715
+ lineHeight: 1,
716
+ color: "inherit"
717
+ },
718
+ "aria-label": "St\xE4ng",
719
+ children: "\xD7"
720
+ }
721
+ )
722
+ ]
723
+ }
724
+ ),
725
+ /* @__PURE__ */ jsx6(
726
+ "div",
727
+ {
728
+ style: {
729
+ flex: 1,
730
+ overflow: "auto",
731
+ padding: "8px 0"
732
+ },
733
+ children: drawings.length === 0 ? /* @__PURE__ */ jsxs4(
734
+ "div",
735
+ {
736
+ style: {
737
+ padding: "40px 20px",
738
+ textAlign: "center",
739
+ color: "var(--text-secondary-color, #666)"
740
+ },
741
+ children: [
742
+ /* @__PURE__ */ jsx6("p", { children: "Inga ritningar \xE4nnu." }),
743
+ /* @__PURE__ */ jsx6("p", { children: 'Klicka "Ny ritning" f\xF6r att b\xF6rja.' })
744
+ ]
745
+ }
746
+ ) : drawings.map((drawing) => /* @__PURE__ */ jsxs4(
747
+ "div",
748
+ {
749
+ className: "rita-workspace-dialog-item",
750
+ style: {
751
+ padding: "12px 20px",
752
+ display: "flex",
753
+ alignItems: "center",
754
+ gap: "12px",
755
+ borderBottom: "1px solid var(--default-border-color, #f0f0f0)",
756
+ backgroundColor: activeDrawing?.id === drawing.id ? "var(--color-primary-light, rgba(108, 99, 255, 0.1))" : "transparent"
757
+ },
758
+ children: [
759
+ /* @__PURE__ */ jsx6("div", { style: { flex: 1, minWidth: 0 }, children: editingId === drawing.id ? /* @__PURE__ */ jsx6(
760
+ "input",
761
+ {
762
+ type: "text",
763
+ value: editName,
764
+ onChange: (e) => setEditName(e.target.value),
765
+ onKeyDown: (e) => {
766
+ if (e.key === "Enter") handleSaveEdit();
767
+ if (e.key === "Escape") handleCancelEdit();
768
+ },
769
+ autoFocus: true,
770
+ style: {
771
+ width: "100%",
772
+ padding: "4px 8px",
773
+ fontSize: "14px",
774
+ border: "1px solid var(--color-primary, #6c63ff)",
775
+ borderRadius: "4px",
776
+ outline: "none"
777
+ }
778
+ }
779
+ ) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
780
+ /* @__PURE__ */ jsxs4(
781
+ "div",
782
+ {
783
+ style: {
784
+ fontWeight: activeDrawing?.id === drawing.id ? 600 : 400,
785
+ fontSize: "14px",
786
+ overflow: "hidden",
787
+ textOverflow: "ellipsis",
788
+ whiteSpace: "nowrap"
789
+ },
790
+ children: [
791
+ activeDrawing?.id === drawing.id && "\u2713 ",
792
+ drawing.name
793
+ ]
794
+ }
795
+ ),
796
+ /* @__PURE__ */ jsxs4(
797
+ "div",
798
+ {
799
+ style: {
800
+ fontSize: "12px",
801
+ color: "var(--text-secondary-color, #888)",
802
+ marginTop: "2px"
803
+ },
804
+ children: [
805
+ "\xC4ndrad: ",
806
+ formatDate(drawing.updatedAt)
807
+ ]
808
+ }
809
+ )
810
+ ] }) }),
811
+ /* @__PURE__ */ jsx6("div", { style: { display: "flex", gap: "4px" }, children: editingId === drawing.id ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
812
+ /* @__PURE__ */ jsx6(
813
+ "button",
814
+ {
815
+ onClick: handleSaveEdit,
816
+ style: {
817
+ padding: "6px 12px",
818
+ fontSize: "12px",
819
+ backgroundColor: "var(--color-primary, #6c63ff)",
820
+ color: "#fff",
821
+ border: "none",
822
+ borderRadius: "4px",
823
+ cursor: "pointer"
824
+ },
825
+ children: "Spara"
826
+ }
827
+ ),
828
+ /* @__PURE__ */ jsx6(
829
+ "button",
830
+ {
831
+ onClick: handleCancelEdit,
832
+ style: {
833
+ padding: "6px 12px",
834
+ fontSize: "12px",
835
+ backgroundColor: "transparent",
836
+ border: "1px solid var(--default-border-color, #ccc)",
837
+ borderRadius: "4px",
838
+ cursor: "pointer",
839
+ color: "inherit"
840
+ },
841
+ children: "Avbryt"
842
+ }
843
+ )
844
+ ] }) : confirmDeleteId === drawing.id ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
845
+ /* @__PURE__ */ jsx6(
846
+ "button",
847
+ {
848
+ onClick: () => handleDelete(drawing.id),
849
+ style: {
850
+ padding: "6px 12px",
851
+ fontSize: "12px",
852
+ backgroundColor: "#dc3545",
853
+ color: "#fff",
854
+ border: "none",
855
+ borderRadius: "4px",
856
+ cursor: "pointer"
857
+ },
858
+ children: "Ta bort"
859
+ }
860
+ ),
861
+ /* @__PURE__ */ jsx6(
862
+ "button",
863
+ {
864
+ onClick: () => setConfirmDeleteId(null),
865
+ style: {
866
+ padding: "6px 12px",
867
+ fontSize: "12px",
868
+ backgroundColor: "transparent",
869
+ border: "1px solid var(--default-border-color, #ccc)",
870
+ borderRadius: "4px",
871
+ cursor: "pointer",
872
+ color: "inherit"
873
+ },
874
+ children: "Avbryt"
875
+ }
876
+ )
877
+ ] }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
878
+ /* @__PURE__ */ jsx6(
879
+ "button",
880
+ {
881
+ onClick: () => handleSelect(drawing),
882
+ style: {
883
+ padding: "6px 12px",
884
+ fontSize: "12px",
885
+ backgroundColor: "var(--color-primary, #6c63ff)",
886
+ color: "#fff",
887
+ border: "none",
888
+ borderRadius: "4px",
889
+ cursor: "pointer"
890
+ },
891
+ disabled: activeDrawing?.id === drawing.id,
892
+ children: "\xD6ppna"
893
+ }
894
+ ),
895
+ /* @__PURE__ */ jsx6(
896
+ "button",
897
+ {
898
+ onClick: () => handleStartEdit(drawing),
899
+ style: {
900
+ padding: "6px 12px",
901
+ fontSize: "12px",
902
+ backgroundColor: "transparent",
903
+ border: "1px solid var(--default-border-color, #ccc)",
904
+ borderRadius: "4px",
905
+ cursor: "pointer",
906
+ color: "inherit"
907
+ },
908
+ title: "Byt namn",
909
+ children: "\u270F\uFE0F"
910
+ }
911
+ ),
912
+ /* @__PURE__ */ jsx6(
913
+ "button",
914
+ {
915
+ onClick: () => setConfirmDeleteId(drawing.id),
916
+ style: {
917
+ padding: "6px 12px",
918
+ fontSize: "12px",
919
+ backgroundColor: "transparent",
920
+ border: "1px solid var(--default-border-color, #ccc)",
921
+ borderRadius: "4px",
922
+ cursor: "pointer",
923
+ color: "inherit"
924
+ },
925
+ title: "Ta bort",
926
+ disabled: drawings.length <= 1,
927
+ children: "\u{1F5D1}\uFE0F"
928
+ }
929
+ )
930
+ ] }) })
931
+ ]
932
+ },
933
+ drawing.id
934
+ ))
935
+ }
936
+ ),
937
+ /* @__PURE__ */ jsxs4(
938
+ "div",
939
+ {
940
+ style: {
941
+ padding: "16px 20px",
942
+ borderTop: "1px solid var(--default-border-color, #e0e0e0)",
943
+ display: "flex",
944
+ justifyContent: "space-between",
945
+ alignItems: "center"
946
+ },
947
+ children: [
948
+ /* @__PURE__ */ jsx6(
949
+ "button",
950
+ {
951
+ onClick: handleCreate,
952
+ style: {
953
+ padding: "10px 20px",
954
+ fontSize: "14px",
955
+ backgroundColor: "var(--color-primary, #6c63ff)",
956
+ color: "#fff",
957
+ border: "none",
958
+ borderRadius: "6px",
959
+ cursor: "pointer",
960
+ fontWeight: 500
961
+ },
962
+ children: "+ Ny ritning"
963
+ }
964
+ ),
965
+ /* @__PURE__ */ jsx6(
966
+ "button",
967
+ {
968
+ onClick: onClose,
969
+ style: {
970
+ padding: "10px 20px",
971
+ fontSize: "14px",
972
+ backgroundColor: "transparent",
973
+ border: "1px solid var(--default-border-color, #ccc)",
974
+ borderRadius: "6px",
975
+ cursor: "pointer",
976
+ color: "inherit"
977
+ },
978
+ children: "St\xE4ng"
979
+ }
980
+ )
981
+ ]
982
+ }
983
+ )
984
+ ]
985
+ }
986
+ )
987
+ }
988
+ );
989
+ };
990
+
486
991
  // src/integration/useExcalidrawBridge.ts
487
- import { useEffect as useEffect3, useRef as useRef2, useCallback as useCallback2 } from "react";
992
+ import { useEffect as useEffect3, useRef as useRef2, useCallback as useCallback3 } from "react";
488
993
  function useExcalidrawBridge({
489
994
  excalidrawAPI,
490
995
  autoSaveInterval = 2e3
@@ -501,7 +1006,7 @@ function useExcalidrawBridge({
501
1006
  appState: activeDrawing.appState
502
1007
  });
503
1008
  }, [excalidrawAPI, activeDrawing]);
504
- const scheduleSave = useCallback2(() => {
1009
+ const scheduleSave = useCallback3(() => {
505
1010
  if (!excalidrawAPI) return;
506
1011
  if (saveTimeoutRef.current) {
507
1012
  clearTimeout(saveTimeoutRef.current);
@@ -525,14 +1030,14 @@ function useExcalidrawBridge({
525
1030
  }
526
1031
 
527
1032
  // src/WorkspacePlugin.tsx
528
- import { useState as useState4, useEffect as useEffect4, useCallback as useCallback3 } from "react";
529
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1033
+ import { useState as useState6, useEffect as useEffect4, useCallback as useCallback4 } from "react";
1034
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
530
1035
  function WorkspacePluginInner({
531
1036
  children,
532
1037
  defaultSidebarOpen = true,
533
1038
  sidebarWidth = 250
534
1039
  }) {
535
- const [sidebarOpen, setSidebarOpen] = useState4(defaultSidebarOpen);
1040
+ const [sidebarOpen, setSidebarOpen] = useState6(defaultSidebarOpen);
536
1041
  const { activeDrawing } = useWorkspace();
537
1042
  useEffect4(() => {
538
1043
  const handleKeyDown = (e) => {
@@ -547,10 +1052,10 @@ function WorkspacePluginInner({
547
1052
  window.addEventListener("keydown", handleKeyDown);
548
1053
  return () => window.removeEventListener("keydown", handleKeyDown);
549
1054
  }, []);
550
- const handleToggleSidebar = useCallback3(() => {
1055
+ const handleToggleSidebar = useCallback4(() => {
551
1056
  setSidebarOpen((prev) => !prev);
552
1057
  }, []);
553
- return /* @__PURE__ */ jsxs3(
1058
+ return /* @__PURE__ */ jsxs5(
554
1059
  "div",
555
1060
  {
556
1061
  style: {
@@ -559,7 +1064,7 @@ function WorkspacePluginInner({
559
1064
  width: "100%"
560
1065
  },
561
1066
  children: [
562
- /* @__PURE__ */ jsx5(
1067
+ /* @__PURE__ */ jsx7(
563
1068
  Sidebar,
564
1069
  {
565
1070
  isOpen: sidebarOpen,
@@ -567,7 +1072,7 @@ function WorkspacePluginInner({
567
1072
  width: sidebarWidth
568
1073
  }
569
1074
  ),
570
- /* @__PURE__ */ jsx5(
1075
+ /* @__PURE__ */ jsx7(
571
1076
  "main",
572
1077
  {
573
1078
  style: {
@@ -583,12 +1088,14 @@ function WorkspacePluginInner({
583
1088
  );
584
1089
  }
585
1090
  function WorkspacePlugin(props) {
586
- return /* @__PURE__ */ jsx5(WorkspaceProvider, { children: /* @__PURE__ */ jsx5(WorkspacePluginInner, { ...props }) });
1091
+ return /* @__PURE__ */ jsx7(WorkspaceProvider, { children: /* @__PURE__ */ jsx7(WorkspacePluginInner, { ...props }) });
587
1092
  }
588
1093
  export {
589
1094
  DrawingList,
590
1095
  DrawingListItem,
1096
+ DrawingsDialog,
591
1097
  Sidebar,
1098
+ WorkspaceMenuItems,
592
1099
  WorkspacePlugin,
593
1100
  WorkspaceProvider,
594
1101
  addDrawingToWorkspace,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rita-workspace",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Multi-drawing workspace feature for Rita (Excalidraw fork)",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",