@mshuja288/aksuicore 0.3.0 → 0.4.1

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.
@@ -1,7 +1,8 @@
1
- export { AppShell, type AppShellProps } from "./AppShell";
1
+ export { AppShell, type AppShellProps, type MobileNavMode } from "./AppShell";
2
2
  export {
3
3
  RecordWorkspace,
4
4
  RecordTable,
5
5
  type TableColumn,
6
6
  type ExportDownloadFormat,
7
+ type ExportColumnRef,
7
8
  } from "./RecordWorkspace";
@@ -12,14 +12,16 @@ export function SideNav({
12
12
  activeId,
13
13
  onSelect,
14
14
  label = "Sections",
15
+ className = "",
15
16
  }: {
16
17
  items: SideNavItem[];
17
18
  activeId: string;
18
19
  onSelect: (id: string) => void;
19
20
  label?: string;
21
+ className?: string;
20
22
  }) {
21
23
  return (
22
- <nav className="side-nav" aria-label={label}>
24
+ <nav className={["side-nav", className].filter(Boolean).join(" ")} aria-label={label}>
23
25
  {items.map((item) => (
24
26
  <button
25
27
  key={item.id}
@@ -3,12 +3,27 @@
3
3
  import { useEffect, useRef, useState, type ReactNode } from "react";
4
4
  import { Button } from "./Button";
5
5
 
6
+ function MenuIcon({ open }: { open: boolean }) {
7
+ return (
8
+ <svg viewBox="0 0 20 20" aria-hidden="true">
9
+ {open ? (
10
+ <path d="M5 5l10 10M15 5 5 15" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
11
+ ) : (
12
+ <path d="M3.5 5.5h13M3.5 10h13M3.5 14.5h13" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
13
+ )}
14
+ </svg>
15
+ );
16
+ }
17
+
6
18
  export function Topbar({
7
19
  title,
8
20
  logoSrc,
9
21
  logoAlt = "Logo",
10
22
  username = "",
11
23
  onLogout,
24
+ showMenuButton = false,
25
+ menuOpen = false,
26
+ onMenuClick,
12
27
  children,
13
28
  }: {
14
29
  title: string;
@@ -16,30 +31,45 @@ export function Topbar({
16
31
  logoAlt?: string;
17
32
  username?: string;
18
33
  onLogout?: () => void;
34
+ /** Shows a hamburger control (used by AppShell drawer on small screens). */
35
+ showMenuButton?: boolean;
36
+ menuOpen?: boolean;
37
+ onMenuClick?: () => void;
19
38
  children?: ReactNode;
20
39
  }) {
21
- const [menuOpen, setMenuOpen] = useState(false);
40
+ const [accountOpen, setAccountOpen] = useState(false);
22
41
  const menuRef = useRef<HTMLDivElement>(null);
23
42
  const initial = (username || "U").slice(0, 1).toUpperCase();
24
43
 
25
44
  useEffect(() => {
26
- if (!menuOpen) {
45
+ if (!accountOpen) {
27
46
  return;
28
47
  }
29
48
 
30
49
  function onPointerDown(event: MouseEvent) {
31
50
  if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
32
- setMenuOpen(false);
51
+ setAccountOpen(false);
33
52
  }
34
53
  }
35
54
 
36
55
  document.addEventListener("mousedown", onPointerDown);
37
56
  return () => document.removeEventListener("mousedown", onPointerDown);
38
- }, [menuOpen]);
57
+ }, [accountOpen]);
39
58
 
40
59
  return (
41
60
  <header className="topbar">
42
61
  <div className="topbar-brand">
62
+ {showMenuButton && onMenuClick ? (
63
+ <button
64
+ type="button"
65
+ className="ghost topbar-menu-button"
66
+ aria-label={menuOpen ? "Close navigation menu" : "Open navigation menu"}
67
+ aria-expanded={menuOpen}
68
+ onClick={onMenuClick}
69
+ >
70
+ <MenuIcon open={menuOpen} />
71
+ </button>
72
+ ) : null}
43
73
  {logoSrc ? (
44
74
  <img
45
75
  className="topbar-logo"
@@ -60,20 +90,20 @@ export function Topbar({
60
90
  type="button"
61
91
  className="avatar-button"
62
92
  aria-haspopup="menu"
63
- aria-expanded={menuOpen}
64
- onClick={() => setMenuOpen((open) => !open)}
93
+ aria-expanded={accountOpen}
94
+ onClick={() => setAccountOpen((open) => !open)}
65
95
  title={username || "Account"}
66
96
  >
67
97
  <span className="avatar">{initial}</span>
68
98
  </button>
69
- {menuOpen ? (
99
+ {accountOpen ? (
70
100
  <div className="avatar-menu" role="menu">
71
101
  {username ? <p className="avatar-name">{username}</p> : null}
72
102
  <Button
73
103
  variant="ghost"
74
104
  role="menuitem"
75
105
  onClick={() => {
76
- setMenuOpen(false);
106
+ setAccountOpen(false);
77
107
  onLogout();
78
108
  }}
79
109
  >
@@ -404,11 +404,81 @@ button.side-rail-add:hover {
404
404
  background: #2a3546;
405
405
  }
406
406
 
407
+ .side-rail-columns,
407
408
  .side-rail-download {
408
409
  display: grid;
409
410
  gap: 8px;
410
411
  }
411
412
 
413
+ button.side-rail-columns-toggle {
414
+ display: inline-flex;
415
+ align-items: center;
416
+ justify-content: center;
417
+ gap: 8px;
418
+ width: 100%;
419
+ padding: 10px 12px;
420
+ border: 1px solid var(--aks-border, #d7dde5);
421
+ border-radius: var(--aks-radius);
422
+ background: #fff;
423
+ color: var(--aks-brand);
424
+ box-shadow: none;
425
+ }
426
+
427
+ button.side-rail-columns-toggle svg {
428
+ width: 18px;
429
+ height: 18px;
430
+ }
431
+
432
+ button.side-rail-columns-toggle:hover {
433
+ background: #f5f7fa;
434
+ }
435
+
436
+ .side-rail-columns-panel {
437
+ display: grid;
438
+ gap: 8px;
439
+ padding: 8px;
440
+ border: 1px solid var(--aks-line);
441
+ border-radius: var(--aks-radius);
442
+ background: #faf9f7;
443
+ }
444
+
445
+ .side-rail-columns-actions {
446
+ display: flex;
447
+ gap: 6px;
448
+ }
449
+
450
+ .side-rail-columns-actions button {
451
+ flex: 1 1 auto;
452
+ padding: 6px 8px;
453
+ font-size: 12px;
454
+ box-shadow: none;
455
+ }
456
+
457
+ .side-rail-columns-list {
458
+ display: grid;
459
+ gap: 6px;
460
+ max-height: 220px;
461
+ overflow: auto;
462
+ }
463
+
464
+ label.side-rail-column-option {
465
+ display: flex;
466
+ align-items: center;
467
+ gap: 8px;
468
+ margin: 0;
469
+ padding: 4px 2px;
470
+ color: var(--aks-brand);
471
+ font-size: 13px;
472
+ font-weight: 500;
473
+ }
474
+
475
+ label.side-rail-column-option input {
476
+ width: auto;
477
+ min-height: 0;
478
+ margin: 0;
479
+ accent-color: var(--aks-accent);
480
+ }
481
+
412
482
  button.side-rail-download-toggle {
413
483
  display: inline-flex;
414
484
  align-items: center;
@@ -664,6 +734,73 @@ button.sort-header.active .sort-indicator {
664
734
  gap: 6px;
665
735
  }
666
736
 
737
+ .row-actions-mobile {
738
+ display: none;
739
+ }
740
+
741
+ button.row-action-menu-trigger {
742
+ width: 36px;
743
+ height: 32px;
744
+ padding: 0;
745
+ color: var(--aks-muted);
746
+ box-shadow: none;
747
+ }
748
+
749
+ button.row-action-menu-trigger svg {
750
+ width: 18px;
751
+ height: 18px;
752
+ }
753
+
754
+ button.row-action-menu-trigger:hover,
755
+ button.row-action-menu-trigger.open {
756
+ transform: none;
757
+ background: #f4f2ef;
758
+ color: var(--aks-brand);
759
+ box-shadow: none;
760
+ }
761
+
762
+ .row-action-menu {
763
+ display: grid;
764
+ min-width: 160px;
765
+ padding: 6px;
766
+ border: 1px solid var(--aks-line);
767
+ border-radius: var(--aks-radius);
768
+ background: #fff;
769
+ box-shadow: 0 12px 28px rgba(30, 39, 53, 0.14);
770
+ }
771
+
772
+ .row-action-menu-portal {
773
+ position: fixed;
774
+ z-index: 90;
775
+ }
776
+
777
+ .row-action-menu button {
778
+ justify-content: flex-start;
779
+ width: 100%;
780
+ padding: 10px 12px;
781
+ font-size: 13px;
782
+ font-weight: 600;
783
+ color: var(--aks-brand);
784
+ box-shadow: none;
785
+ }
786
+
787
+ .row-action-menu button.danger:not(:disabled) {
788
+ color: #a33b2b;
789
+ }
790
+
791
+ .row-action-menu button:hover:not(:disabled) {
792
+ transform: none;
793
+ background: #f4f2ef;
794
+ box-shadow: none;
795
+ }
796
+
797
+ /* Mobile tools bar + right drawer — hidden on desktop */
798
+ .tools-mobile-bar,
799
+ .tools-drawer-backdrop,
800
+ .tools-drawer {
801
+ display: none;
802
+ }
803
+
667
804
  button.row-action {
668
805
  padding: 4px 8px;
669
806
  font-size: 12px;
@@ -761,32 +898,227 @@ button.row-action.danger:not(:disabled):hover {
761
898
  }
762
899
 
763
900
  @media (max-width: 900px) {
901
+ .list-workspace {
902
+ gap: 10px;
903
+ }
904
+
905
+ .tools-mobile-bar {
906
+ display: flex;
907
+ align-items: center;
908
+ justify-content: space-between;
909
+ gap: 10px;
910
+ flex: 0 0 auto;
911
+ min-height: 48px;
912
+ padding: 6px 8px 6px 10px;
913
+ border: 1px solid var(--aks-line);
914
+ border-radius: var(--aks-radius);
915
+ background: #fff;
916
+ }
917
+
918
+ .tools-mobile-bar-start {
919
+ min-width: 0;
920
+ flex: 1 1 auto;
921
+ }
922
+
923
+ .tools-mobile-title {
924
+ margin: 0;
925
+ color: var(--aks-brand);
926
+ font-size: 13px;
927
+ font-weight: 700;
928
+ white-space: nowrap;
929
+ overflow: hidden;
930
+ text-overflow: ellipsis;
931
+ }
932
+
933
+ button.tools-mobile-add {
934
+ display: inline-flex;
935
+ align-items: center;
936
+ gap: 6px;
937
+ min-height: 36px;
938
+ padding: 6px 12px;
939
+ border-radius: var(--aks-radius);
940
+ background: var(--aks-brand);
941
+ color: #fff;
942
+ font-size: 13px;
943
+ font-weight: 600;
944
+ box-shadow: none;
945
+ }
946
+
947
+ button.tools-mobile-add svg {
948
+ width: 16px;
949
+ height: 16px;
950
+ }
951
+
952
+ button.tools-mobile-add:hover {
953
+ transform: none;
954
+ background: #2a3546;
955
+ box-shadow: none;
956
+ }
957
+
958
+ button.tools-mobile-toggle {
959
+ position: relative;
960
+ display: inline-flex;
961
+ align-items: center;
962
+ gap: 6px;
963
+ min-height: 36px;
964
+ padding: 6px 12px;
965
+ border: 1px solid var(--aks-line);
966
+ border-radius: var(--aks-radius);
967
+ background: #faf9f7;
968
+ color: var(--aks-brand);
969
+ font-size: 13px;
970
+ font-weight: 600;
971
+ box-shadow: none;
972
+ }
973
+
974
+ button.tools-mobile-toggle svg {
975
+ width: 16px;
976
+ height: 16px;
977
+ }
978
+
979
+ button.tools-mobile-toggle:hover {
980
+ transform: none;
981
+ background: #f0eeea;
982
+ box-shadow: none;
983
+ }
984
+
985
+ button.tools-mobile-toggle .filter-badge {
986
+ position: static;
987
+ margin-left: 2px;
988
+ }
989
+
990
+ .list-body {
991
+ flex-direction: column;
992
+ }
993
+
764
994
  .list-body.side-open,
765
995
  .list-body.preview-open {
766
996
  flex-direction: column;
767
997
  }
768
998
 
769
- .preview-panel,
770
- .side-rail,
771
- .side-rail.open {
772
- width: 100%;
773
- flex-basis: auto;
999
+ /* Desktop side-rail becomes a right drawer on small screens */
1000
+ .list-body > .side-rail {
1001
+ display: none;
774
1002
  }
775
1003
 
776
- .side-rail:not(.open) {
777
- flex-direction: row;
778
- align-items: center;
1004
+ .preview-panel {
779
1005
  width: 100%;
780
1006
  flex-basis: auto;
1007
+ order: 2;
781
1008
  }
782
1009
 
783
- .side-rail:not(.open) .side-rail-icons {
784
- display: inline-flex;
785
- margin-left: auto;
1010
+ .tools-drawer-backdrop {
1011
+ display: block;
1012
+ position: fixed;
1013
+ inset: 0;
1014
+ z-index: 55;
1015
+ border: 0;
1016
+ padding: 0;
1017
+ margin: 0;
1018
+ background: rgba(30, 39, 53, 0.42);
1019
+ opacity: 0;
1020
+ pointer-events: none;
1021
+ transition: opacity 160ms ease;
1022
+ box-shadow: none;
1023
+ }
1024
+
1025
+ .tools-drawer-backdrop.open {
1026
+ opacity: 1;
1027
+ pointer-events: auto;
1028
+ }
1029
+
1030
+ .tools-drawer {
1031
+ display: flex;
1032
+ flex-direction: column;
1033
+ position: fixed;
1034
+ top: 0;
1035
+ right: 0;
1036
+ bottom: 0;
1037
+ z-index: 60;
1038
+ width: min(320px, calc(100vw - 40px));
1039
+ background: #fff;
1040
+ border-left: 1px solid var(--aks-line);
1041
+ box-shadow: -12px 0 32px rgba(30, 39, 53, 0.18);
1042
+ transform: translateX(105%);
1043
+ transition: transform 180ms ease;
1044
+ pointer-events: none;
1045
+ }
1046
+
1047
+ .tools-drawer.open {
1048
+ transform: translateX(0);
1049
+ pointer-events: auto;
1050
+ }
1051
+
1052
+ .tools-drawer-head {
1053
+ display: flex;
1054
+ align-items: flex-start;
1055
+ justify-content: space-between;
1056
+ gap: 12px;
1057
+ flex: 0 0 auto;
1058
+ padding: 16px 16px 12px;
1059
+ border-bottom: 1px solid var(--aks-line);
1060
+ background: #faf9f7;
1061
+ }
1062
+
1063
+ .tools-drawer-kicker {
1064
+ margin: 0;
1065
+ color: var(--aks-accent);
1066
+ font-size: 11px;
1067
+ font-weight: 700;
1068
+ letter-spacing: 0.06em;
1069
+ text-transform: uppercase;
1070
+ }
1071
+
1072
+ .tools-drawer-head h3 {
1073
+ margin: 2px 0 0;
1074
+ color: var(--aks-brand);
1075
+ font-size: 16px;
1076
+ font-weight: 700;
1077
+ }
1078
+
1079
+ button.tools-drawer-close {
1080
+ padding: 6px 10px;
1081
+ font-size: 12px;
1082
+ box-shadow: none;
1083
+ }
1084
+
1085
+ .tools-drawer-body {
1086
+ flex: 1 1 auto;
1087
+ min-height: 0;
1088
+ overflow: auto;
1089
+ padding: 14px;
1090
+ }
1091
+
1092
+ .tools-drawer-body .side-rail-body {
1093
+ padding: 0;
786
1094
  }
787
1095
 
788
1096
  .table-card-bar {
789
1097
  flex-wrap: wrap;
790
1098
  }
1099
+
1100
+ .data-table {
1101
+ min-width: 520px;
1102
+ }
1103
+
1104
+ .row-actions-desktop {
1105
+ display: none;
1106
+ }
1107
+
1108
+ .row-actions-mobile {
1109
+ display: inline-flex;
1110
+ }
1111
+
1112
+ .data-table .actions-col {
1113
+ position: sticky;
1114
+ right: 0;
1115
+ z-index: 1;
1116
+ background: #fff;
1117
+ box-shadow: -8px 0 12px rgba(30, 39, 53, 0.04);
1118
+ }
1119
+
1120
+ .data-table thead .actions-col {
1121
+ background: #f6f5f3;
1122
+ }
791
1123
  }
792
1124
 
@@ -28,13 +28,19 @@ button.ghost:hover,
28
28
  button.app-select-trigger:hover,
29
29
  button.date-field-trigger:hover,
30
30
  button.avatar-button:hover,
31
+ button.topbar-menu-button:hover,
31
32
  button.sort-header:hover,
32
33
  button.row-action:hover,
34
+ button.row-action-menu-trigger:hover,
33
35
  button.date-picker-day:hover,
34
36
  button.side-rail-toggle:hover,
35
37
  button.side-rail-icon:hover,
38
+ button.side-rail-columns-toggle:hover,
36
39
  button.filter-clear:hover,
37
- button.snackbar-close:hover {
40
+ button.snackbar-close:hover,
41
+ button.nav-drawer-close:hover,
42
+ button.tools-mobile-toggle:hover,
43
+ button.tools-drawer-close:hover {
38
44
  transform: none;
39
45
  }
40
46
 
@@ -152,6 +158,10 @@ select:disabled {
152
158
  min-width: 0;
153
159
  }
154
160
 
161
+ button.topbar-menu-button {
162
+ flex: 0 0 auto;
163
+ }
164
+
155
165
  .topbar-logo {
156
166
  width: 40px;
157
167
  height: 40px;