strapi-plugin-magic-mark 3.2.7 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  const React = require("react");
3
+ const admin = require("@strapi/strapi/admin");
3
4
  const jsxRuntime = require("react/jsx-runtime");
4
5
  const icons = require("@strapi/icons");
5
- const designSystem = require("@strapi/design-system");
6
+ const outline = require("@heroicons/react/24/outline");
6
7
  const reactIntl = require("react-intl");
7
8
  const reactRouterDom = require("react-router-dom");
8
- const admin = require("@strapi/strapi/admin");
9
9
  const styled = require("styled-components");
10
+ const designSystem = require("@strapi/design-system");
10
11
  const ReactDOM = require("react-dom");
11
12
  const qs = require("qs");
12
13
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
@@ -39,55 +40,28 @@ const pluginPkg = {
39
40
  const pluginId = "magic-mark";
40
41
  const Initializer = ({ setPlugin }) => {
41
42
  const ref = React.useRef(setPlugin);
43
+ const { get } = admin.useFetchClient();
42
44
  React.useEffect(() => {
43
45
  ref.current(pluginId);
44
46
  }, []);
47
+ React.useEffect(() => {
48
+ const HEARTBEAT_INTERVAL = 4 * 60 * 1e3;
49
+ const heartbeat = async () => {
50
+ try {
51
+ await get(`/${pluginId}/license/status`);
52
+ } catch (error) {
53
+ }
54
+ };
55
+ const initialTimeout = setTimeout(heartbeat, 60 * 1e3);
56
+ const interval = setInterval(heartbeat, HEARTBEAT_INTERVAL);
57
+ return () => {
58
+ clearTimeout(initialTimeout);
59
+ clearInterval(interval);
60
+ };
61
+ }, [get]);
45
62
  return null;
46
63
  };
47
64
  const PluginIcon = () => /* @__PURE__ */ jsxRuntime.jsx(icons.Book, {});
48
- const ViewsListPopover = ({
49
- views,
50
- onViewClick,
51
- isLoading = false,
52
- buttonElement
53
- }) => {
54
- const { formatMessage } = reactIntl.useIntl();
55
- return /* @__PURE__ */ jsxRuntime.jsx(
56
- designSystem.Box,
57
- {
58
- hasRadius: true,
59
- shadow: "popover",
60
- padding: 3,
61
- style: {
62
- position: "absolute",
63
- top: "100%",
64
- left: 0,
65
- marginTop: "8px",
66
- minWidth: "200px",
67
- maxWidth: "300px",
68
- zIndex: 1e3,
69
- backgroundColor: "white"
70
- },
71
- children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", textAlign: "center", children: formatMessage({ id: "loading", defaultMessage: "Loading..." }) }) : views && views.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 1, as: "nav", children: views.map((view) => /* @__PURE__ */ jsxRuntime.jsx(
72
- designSystem.Button,
73
- {
74
- variant: "ghost",
75
- fullWidth: true,
76
- onClick: () => onViewClick(view),
77
- style: {
78
- textAlign: "left",
79
- justifyContent: "flex-start"
80
- },
81
- children: view.name
82
- },
83
- view.id
84
- )) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage({
85
- id: `${pluginId}.ViewsWidget.ViewsPopover.emptyList`,
86
- defaultMessage: "You don't have any private views saved yet..."
87
- }) })
88
- }
89
- );
90
- };
91
65
  const parseQueryString = (queryString) => {
92
66
  const result = {
93
67
  filters: [],
@@ -241,534 +215,1147 @@ const FilterPreview = ({ query }) => {
241
215
  sort
242
216
  ] }, idx)) })
243
217
  ] }),
244
- parsed.populate.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
245
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Relations:" }),
246
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { wrap: "wrap", gap: 1, children: parsed.populate.map((field, idx) => /* @__PURE__ */ jsxRuntime.jsxs(PopulateChip, { children: [
247
- /* @__PURE__ */ jsxRuntime.jsx(icons.Link, { width: "12px", height: "12px", style: { marginRight: "4px" } }),
248
- " ",
249
- field
250
- ] }, idx)) })
218
+ parsed.populate.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
219
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Relations:" }),
220
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { wrap: "wrap", gap: 1, children: parsed.populate.map((field, idx) => /* @__PURE__ */ jsxRuntime.jsxs(PopulateChip, { children: [
221
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Link, { width: "12px", height: "12px", style: { marginRight: "4px" } }),
222
+ " ",
223
+ field
224
+ ] }, idx)) })
225
+ ] })
226
+ ] });
227
+ };
228
+ const theme$1 = {
229
+ colors: {
230
+ primary: { 500: "#4945FF", 600: "#3B38E0", 100: "#EEF0FF", 200: "#D9D8FF" },
231
+ secondary: { 100: "#F0F0FF" },
232
+ danger: { 500: "#D02B20", 100: "#FCECEA" },
233
+ neutral: { 0: "#FFFFFF", 100: "#F6F6F9", 200: "#DCDCE4", 400: "#A5A5BA", 600: "#666687", 800: "#32324D" }
234
+ },
235
+ shadows: {
236
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
237
+ xl: "0 20px 25px -5px rgba(0, 0, 0, 0.15)"
238
+ },
239
+ gradients: {
240
+ header: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
241
+ }
242
+ };
243
+ const BOOKMARK_ICONS = [
244
+ { id: "bookmark", icon: outline.BookmarkIcon, label: "Bookmark" },
245
+ { id: "book", icon: outline.BookOpenIcon, label: "Book" },
246
+ { id: "star", icon: outline.StarIcon, label: "Star" },
247
+ { id: "heart", icon: outline.HeartIcon, label: "Heart" },
248
+ { id: "bolt", icon: outline.BoltIcon, label: "Lightning" },
249
+ { id: "rocket", icon: outline.RocketLaunchIcon, label: "Rocket" },
250
+ { id: "pencil", icon: outline.PencilIcon, label: "Pencil" },
251
+ { id: "link", icon: outline.LinkIcon, label: "Link" },
252
+ { id: "sparkles", icon: outline.SparklesIcon, label: "Sparkles" },
253
+ { id: "briefcase", icon: outline.BriefcaseIcon, label: "Briefcase" },
254
+ { id: "photo", icon: outline.PhotoIcon, label: "Photo" },
255
+ { id: "document", icon: outline.DocumentIcon, label: "Document" },
256
+ { id: "bell", icon: outline.BellIcon, label: "Bell" },
257
+ { id: "check", icon: outline.CheckCircleIcon, label: "Check" },
258
+ { id: "gift", icon: outline.GiftIcon, label: "Gift" },
259
+ { id: "user", icon: outline.UserIcon, label: "User" },
260
+ { id: "users", icon: outline.UserGroupIcon, label: "Users" },
261
+ { id: "mail", icon: outline.EnvelopeIcon, label: "Mail" },
262
+ { id: "calendar", icon: outline.CalendarIcon, label: "Calendar" },
263
+ { id: "clock", icon: outline.ClockIcon, label: "Clock" },
264
+ { id: "folder", icon: outline.FolderIcon, label: "Folder" },
265
+ { id: "search", icon: outline.MagnifyingGlassIcon, label: "Search" },
266
+ { id: "filter", icon: outline.FunnelIcon, label: "Filter" },
267
+ { id: "globe", icon: outline.GlobeAltIcon, label: "Globe" },
268
+ { id: "tag", icon: outline.TagIcon, label: "Tag" },
269
+ { id: "flag", icon: outline.FlagIcon, label: "Flag" },
270
+ { id: "fire", icon: outline.FireIcon, label: "Fire" },
271
+ { id: "cube", icon: outline.CubeIcon, label: "Cube" },
272
+ { id: "home", icon: outline.HomeIcon, label: "Home" },
273
+ { id: "cog", icon: outline.CogIcon, label: "Settings" },
274
+ { id: "wrench", icon: outline.WrenchIcon, label: "Wrench" },
275
+ { id: "terminal", icon: outline.CommandLineIcon, label: "Terminal" },
276
+ { id: "chart", icon: outline.ChartBarIcon, label: "Chart" }
277
+ ];
278
+ const getIconById = (iconId) => {
279
+ const found = BOOKMARK_ICONS.find((i) => i.id === iconId);
280
+ return found ? found.icon : outline.BookmarkIcon;
281
+ };
282
+ const fadeIn$3 = styled.keyframes`
283
+ from { opacity: 0; transform: scale(0.95); }
284
+ to { opacity: 1; transform: scale(1); }
285
+ `;
286
+ styled.keyframes`
287
+ from { opacity: 0; max-height: 0; }
288
+ to { opacity: 1; max-height: 500px; }
289
+ `;
290
+ const Overlay = styled__default.default.div`
291
+ position: fixed;
292
+ top: 0;
293
+ left: 0;
294
+ right: 0;
295
+ bottom: 0;
296
+ background: rgba(0, 0, 0, 0.6);
297
+ backdrop-filter: blur(4px);
298
+ display: flex;
299
+ align-items: center;
300
+ justify-content: center;
301
+ z-index: 999;
302
+ `;
303
+ const ModalContainer = styled__default.default.div`
304
+ background: ${theme$1.colors.neutral[0]};
305
+ border-radius: 16px;
306
+ max-height: 90vh;
307
+ overflow: hidden;
308
+ max-width: 580px;
309
+ width: 95%;
310
+ box-shadow: ${theme$1.shadows.xl};
311
+ animation: ${fadeIn$3} 0.2s ease-out;
312
+ display: flex;
313
+ flex-direction: column;
314
+ `;
315
+ const ModalHeader = styled__default.default.div`
316
+ background: ${theme$1.gradients.header};
317
+ padding: 24px 28px;
318
+ display: flex;
319
+ justify-content: space-between;
320
+ align-items: center;
321
+ `;
322
+ const HeaderTitle = styled__default.default.h2`
323
+ color: white;
324
+ font-size: 1.25rem;
325
+ font-weight: 600;
326
+ margin: 0;
327
+ display: flex;
328
+ align-items: center;
329
+ gap: 10px;
330
+
331
+ svg {
332
+ width: 24px;
333
+ height: 24px;
334
+ }
335
+ `;
336
+ const CloseButton = styled__default.default.button`
337
+ background: rgba(255, 255, 255, 0.2);
338
+ border: none;
339
+ border-radius: 8px;
340
+ padding: 8px;
341
+ cursor: pointer;
342
+ display: flex;
343
+ align-items: center;
344
+ justify-content: center;
345
+ transition: all 0.15s ease;
346
+
347
+ svg {
348
+ width: 20px;
349
+ height: 20px;
350
+ color: white;
351
+ }
352
+
353
+ &:hover {
354
+ background: rgba(255, 255, 255, 0.3);
355
+ transform: scale(1.05);
356
+ }
357
+ `;
358
+ const ModalBody = styled__default.default.div`
359
+ padding: 24px 28px;
360
+ overflow-y: auto;
361
+ flex: 1;
362
+ `;
363
+ const ModalFooter = styled__default.default.div`
364
+ padding: 16px 28px;
365
+ background: ${theme$1.colors.neutral[100]};
366
+ border-top: 1px solid ${theme$1.colors.neutral[200]};
367
+ display: flex;
368
+ justify-content: flex-end;
369
+ gap: 12px;
370
+ `;
371
+ const Section = styled__default.default.div`
372
+ margin-bottom: 20px;
373
+ border: 1px solid ${theme$1.colors.neutral[200]};
374
+ border-radius: 12px;
375
+ overflow: hidden;
376
+ background: ${theme$1.colors.neutral[0]};
377
+ transition: all 0.2s ease;
378
+
379
+ &:hover {
380
+ border-color: ${theme$1.colors.primary[200]};
381
+ }
382
+ `;
383
+ const SectionHeader = styled__default.default.button`
384
+ width: 100%;
385
+ padding: 14px 16px;
386
+ background: ${theme$1.colors.neutral[100]};
387
+ border: none;
388
+ cursor: pointer;
389
+ display: flex;
390
+ align-items: center;
391
+ justify-content: space-between;
392
+ transition: all 0.15s ease;
393
+
394
+ &:hover {
395
+ background: ${theme$1.colors.neutral[200]};
396
+ }
397
+ `;
398
+ const SectionTitle = styled__default.default.div`
399
+ display: flex;
400
+ align-items: center;
401
+ gap: 10px;
402
+ font-weight: 600;
403
+ font-size: 0.875rem;
404
+ color: ${theme$1.colors.neutral[800]};
405
+
406
+ svg {
407
+ width: 18px;
408
+ height: 18px;
409
+ color: ${theme$1.colors.primary[500]};
410
+ }
411
+ `;
412
+ const SectionContent = styled__default.default.div`
413
+ padding: ${(props) => props.$collapsed ? "0" : "16px"};
414
+ max-height: ${(props) => props.$collapsed ? "0" : "500px"};
415
+ opacity: ${(props) => props.$collapsed ? "0" : "1"};
416
+ overflow: hidden;
417
+ transition: all 0.25s ease;
418
+ `;
419
+ const ChevronIcon = styled__default.default.div`
420
+ transform: rotate(${(props) => props.$collapsed ? "0" : "180deg"});
421
+ transition: transform 0.2s ease;
422
+
423
+ svg {
424
+ width: 18px;
425
+ height: 18px;
426
+ color: ${theme$1.colors.neutral[600]};
427
+ }
428
+ `;
429
+ const IconPicker = styled__default.default.div`
430
+ display: grid;
431
+ grid-template-columns: repeat(8, 1fr);
432
+ gap: 8px;
433
+ padding: 12px;
434
+ background: ${theme$1.colors.neutral[100]};
435
+ border-radius: 8px;
436
+ max-height: 180px;
437
+ overflow-y: auto;
438
+
439
+ &::-webkit-scrollbar {
440
+ width: 6px;
441
+ }
442
+
443
+ &::-webkit-scrollbar-track {
444
+ background: transparent;
445
+ }
446
+
447
+ &::-webkit-scrollbar-thumb {
448
+ background: ${theme$1.colors.neutral[400]};
449
+ border-radius: 3px;
450
+ }
451
+ `;
452
+ const IconButton = styled__default.default.button`
453
+ display: flex;
454
+ align-items: center;
455
+ justify-content: center;
456
+ padding: 10px;
457
+ border: 2px solid ${(props) => props.$isSelected ? theme$1.colors.primary[500] : "transparent"};
458
+ background: ${(props) => props.$isSelected ? theme$1.colors.primary[100] : theme$1.colors.neutral[0]};
459
+ border-radius: 8px;
460
+ cursor: pointer;
461
+ transition: all 0.15s ease;
462
+
463
+ svg {
464
+ width: 20px;
465
+ height: 20px;
466
+ color: ${(props) => props.$isSelected ? theme$1.colors.primary[500] : theme$1.colors.neutral[600]};
467
+ }
468
+
469
+ &:hover {
470
+ border-color: ${theme$1.colors.primary[500]};
471
+ background: ${theme$1.colors.primary[100]};
472
+ transform: scale(1.08);
473
+
474
+ svg {
475
+ color: ${theme$1.colors.primary[500]};
476
+ }
477
+ }
478
+ `;
479
+ const SelectedIconDisplay = styled__default.default.div`
480
+ display: flex;
481
+ align-items: center;
482
+ gap: 16px;
483
+ padding: 12px 16px;
484
+ background: linear-gradient(135deg, ${theme$1.colors.primary[100]} 0%, ${theme$1.colors.secondary[100]} 100%);
485
+ border-radius: 10px;
486
+ margin-bottom: 12px;
487
+ `;
488
+ const SelectedIconCircle = styled__default.default.div`
489
+ width: 52px;
490
+ height: 52px;
491
+ border-radius: 12px;
492
+ background: ${theme$1.colors.neutral[0]};
493
+ border: 2px solid ${theme$1.colors.primary[500]};
494
+ display: flex;
495
+ align-items: center;
496
+ justify-content: center;
497
+ box-shadow: ${theme$1.shadows.md};
498
+
499
+ svg {
500
+ width: 26px;
501
+ height: 26px;
502
+ color: ${theme$1.colors.primary[500]};
503
+ }
504
+ `;
505
+ const PublicToggleContainer = styled__default.default.div`
506
+ display: flex;
507
+ align-items: center;
508
+ justify-content: space-between;
509
+ padding: 14px 16px;
510
+ background: ${theme$1.colors.neutral[100]};
511
+ border-radius: 10px;
512
+ margin-bottom: 16px;
513
+ `;
514
+ const PublicToggleInfo = styled__default.default.div`
515
+ display: flex;
516
+ align-items: center;
517
+ gap: 12px;
518
+
519
+ svg {
520
+ width: 20px;
521
+ height: 20px;
522
+ color: ${theme$1.colors.primary[500]};
523
+ }
524
+ `;
525
+ const SwitchContainer = styled__default.default.label`
526
+ position: relative;
527
+ display: inline-flex;
528
+ align-items: center;
529
+ cursor: pointer;
530
+ `;
531
+ const SwitchInput = styled__default.default.input`
532
+ opacity: 0;
533
+ width: 0;
534
+ height: 0;
535
+ position: absolute;
536
+ `;
537
+ const SwitchSlider = styled__default.default.span`
538
+ position: relative;
539
+ width: 44px;
540
+ height: 24px;
541
+ background: ${(props) => props.$checked ? theme$1.colors.primary[500] : theme$1.colors.neutral[300]};
542
+ border-radius: 24px;
543
+ transition: all 0.2s ease;
544
+
545
+ &::before {
546
+ content: '';
547
+ position: absolute;
548
+ width: 18px;
549
+ height: 18px;
550
+ left: ${(props) => props.$checked ? "23px" : "3px"};
551
+ top: 3px;
552
+ background: white;
553
+ border-radius: 50%;
554
+ transition: all 0.2s ease;
555
+ box-shadow: 0 1px 3px rgba(0,0,0,0.2);
556
+ }
557
+
558
+ &:hover {
559
+ background: ${(props) => props.$checked ? theme$1.colors.primary[600] : theme$1.colors.neutral[400]};
560
+ }
561
+ `;
562
+ const SelectionList = styled__default.default.div`
563
+ max-height: 140px;
564
+ overflow-y: auto;
565
+ border: 1px solid ${theme$1.colors.neutral[200]};
566
+ border-radius: 8px;
567
+ background: ${(props) => props.$disabled ? theme$1.colors.neutral[100] : theme$1.colors.neutral[0]};
568
+ opacity: ${(props) => props.$disabled ? 0.6 : 1};
569
+ pointer-events: ${(props) => props.$disabled ? "none" : "auto"};
570
+
571
+ &::-webkit-scrollbar {
572
+ width: 6px;
573
+ }
574
+
575
+ &::-webkit-scrollbar-track {
576
+ background: transparent;
577
+ }
578
+
579
+ &::-webkit-scrollbar-thumb {
580
+ background: ${theme$1.colors.neutral[400]};
581
+ border-radius: 3px;
582
+ }
583
+ `;
584
+ const SelectionItem = styled__default.default.label`
585
+ display: flex;
586
+ align-items: center;
587
+ gap: 12px;
588
+ padding: 10px 14px;
589
+ cursor: pointer;
590
+ border-bottom: 1px solid ${theme$1.colors.neutral[200]};
591
+ background: ${(props) => props.$selected ? theme$1.colors.primary[100] : "transparent"};
592
+ transition: all 0.15s ease;
593
+
594
+ &:last-child {
595
+ border-bottom: none;
596
+ }
597
+
598
+ &:hover {
599
+ background: ${(props) => props.$selected ? theme$1.colors.primary[100] : theme$1.colors.neutral[100]};
600
+ }
601
+ `;
602
+ const CustomCheckbox = styled__default.default.div`
603
+ width: 20px;
604
+ height: 20px;
605
+ border-radius: 4px;
606
+ border: 2px solid ${(props) => props.$checked ? theme$1.colors.primary[500] : theme$1.colors.neutral[400]};
607
+ background: ${(props) => props.$checked ? theme$1.colors.primary[500] : "transparent"};
608
+ display: flex;
609
+ align-items: center;
610
+ justify-content: center;
611
+ transition: all 0.15s ease;
612
+ flex-shrink: 0;
613
+
614
+ svg {
615
+ width: 14px;
616
+ height: 14px;
617
+ color: white;
618
+ opacity: ${(props) => props.$checked ? 1 : 0};
619
+ }
620
+ `;
621
+ const ItemLabel = styled__default.default.span`
622
+ font-size: 0.875rem;
623
+ color: ${(props) => props.$selected ? theme$1.colors.primary[600] : theme$1.colors.neutral[800]};
624
+ font-weight: ${(props) => props.$selected ? 600 : 400};
625
+ `;
626
+ const ItemBadge = styled__default.default.span`
627
+ font-size: 0.7rem;
628
+ padding: 2px 6px;
629
+ border-radius: 4px;
630
+ background: ${(props) => props.$type === "custom" ? "#F3E8FF" : theme$1.colors.neutral[200]};
631
+ color: ${(props) => props.$type === "custom" ? "#8B5CF6" : theme$1.colors.neutral[600]};
632
+ font-weight: 500;
633
+ `;
634
+ const FormField = styled__default.default.div`
635
+ margin-bottom: 16px;
636
+
637
+ &:last-child {
638
+ margin-bottom: 0;
639
+ }
640
+ `;
641
+ const Label = styled__default.default.label`
642
+ display: block;
643
+ font-size: 0.875rem;
644
+ font-weight: 600;
645
+ color: ${theme$1.colors.neutral[800]};
646
+ margin-bottom: 8px;
647
+ `;
648
+ const HintText = styled__default.default.p`
649
+ font-size: 0.75rem;
650
+ color: ${theme$1.colors.neutral[600]};
651
+ margin-top: 6px;
652
+ display: flex;
653
+ align-items: center;
654
+ gap: 6px;
655
+
656
+ svg {
657
+ width: 14px;
658
+ height: 14px;
659
+ flex-shrink: 0;
660
+ }
661
+ `;
662
+ const PathDisplay = styled__default.default.div`
663
+ padding: 12px 14px;
664
+ background: ${theme$1.colors.neutral[100]};
665
+ border: 1px solid ${theme$1.colors.neutral[200]};
666
+ border-radius: 8px;
667
+ font-family: 'Monaco', 'Menlo', monospace;
668
+ font-size: 0.8rem;
669
+ color: ${theme$1.colors.neutral[600]};
670
+ word-break: break-all;
671
+ `;
672
+ const ErrorBox = styled__default.default.div`
673
+ padding: 12px 16px;
674
+ background: ${theme$1.colors.danger[100]};
675
+ border: 1px solid ${theme$1.colors.danger[500]};
676
+ border-radius: 8px;
677
+ margin-bottom: 16px;
678
+
679
+ p {
680
+ color: ${theme$1.colors.danger[500]};
681
+ font-size: 0.875rem;
682
+ margin: 0;
683
+ }
684
+ `;
685
+ const SectionLabel = styled__default.default.div`
686
+ font-size: 0.75rem;
687
+ font-weight: 600;
688
+ color: ${theme$1.colors.neutral[600]};
689
+ text-transform: uppercase;
690
+ letter-spacing: 0.5px;
691
+ margin-bottom: 8px;
692
+ margin-top: 12px;
693
+
694
+ &:first-child {
695
+ margin-top: 0;
696
+ }
697
+ `;
698
+ const StyledTextInput = styled__default.default(designSystem.TextInput)`
699
+ input {
700
+ border-radius: 8px;
701
+ border: 1px solid ${theme$1.colors.neutral[200]};
702
+
703
+ &:focus {
704
+ border-color: ${theme$1.colors.primary[500]};
705
+ box-shadow: 0 0 0 3px ${theme$1.colors.primary[100]};
706
+ }
707
+ }
708
+ `;
709
+ const StyledTextarea = styled__default.default(designSystem.Textarea)`
710
+ textarea {
711
+ border-radius: 8px;
712
+ border: 1px solid ${theme$1.colors.neutral[200]};
713
+ min-height: 80px;
714
+
715
+ &:focus {
716
+ border-color: ${theme$1.colors.primary[500]};
717
+ box-shadow: 0 0 0 3px ${theme$1.colors.primary[100]};
718
+ }
719
+ }
720
+ `;
721
+ const CreateEditModal = ({
722
+ bookmark,
723
+ onClose,
724
+ onSuccess,
725
+ pluginId: pluginId2,
726
+ currentPath,
727
+ currentQuery
728
+ }) => {
729
+ const { formatMessage } = reactIntl.useIntl();
730
+ const { post, put, get } = admin.useFetchClient();
731
+ const [name2, setName] = React.useState("");
732
+ const [path, setPath] = React.useState(currentPath || "");
733
+ const [query, setQuery] = React.useState(currentQuery || "");
734
+ const [icon, setIcon] = React.useState("bookmark");
735
+ const [description, setDescription] = React.useState("");
736
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
737
+ const [error, setError] = React.useState("");
738
+ const [isPublic, setIsPublic] = React.useState(false);
739
+ const [sharedWithRoles, setSharedWithRoles] = React.useState([]);
740
+ const [sharedWithUsers, setSharedWithUsers] = React.useState([]);
741
+ const [availableRoles, setAvailableRoles] = React.useState([]);
742
+ const [availableUsers, setAvailableUsers] = React.useState([]);
743
+ const [loadingRoles, setLoadingRoles] = React.useState(false);
744
+ const [loadingUsers, setLoadingUsers] = React.useState(false);
745
+ const [iconSectionOpen, setIconSectionOpen] = React.useState(true);
746
+ const [sharingSectionOpen, setSharingSectionOpen] = React.useState(false);
747
+ const [filtersSectionOpen, setFiltersSectionOpen] = React.useState(false);
748
+ React.useEffect(() => {
749
+ if (bookmark) {
750
+ setName(bookmark.name);
751
+ setPath(bookmark.path);
752
+ setQuery(bookmark.query || "");
753
+ setIcon(bookmark.icon || bookmark.emoji || "bookmark");
754
+ setDescription(bookmark.description || "");
755
+ setIsPublic(bookmark.isPublic || false);
756
+ setSharedWithRoles(bookmark.sharedWithRoles || []);
757
+ setSharedWithUsers(bookmark.sharedWithUsers || []);
758
+ }
759
+ fetchRoles();
760
+ fetchUsers();
761
+ }, [bookmark]);
762
+ const fetchRoles = async () => {
763
+ setLoadingRoles(true);
764
+ try {
765
+ const response = await get(`/${pluginId2}/roles`);
766
+ const roles = response.data?.data?.data || response.data?.data || response.data || [];
767
+ setAvailableRoles(roles);
768
+ } catch (error2) {
769
+ console.error("[Magic-Mark] Error fetching roles:", error2);
770
+ } finally {
771
+ setLoadingRoles(false);
772
+ }
773
+ };
774
+ const fetchUsers = async () => {
775
+ setLoadingUsers(true);
776
+ try {
777
+ const meResponse = await get("/admin/users/me");
778
+ const currentUser = meResponse.data?.data || meResponse.data || meResponse;
779
+ const currentUserId = currentUser?.id;
780
+ const currentUserEmail = currentUser?.email;
781
+ const response = await get("/admin/users?pageSize=100&page=1&sort=firstname");
782
+ const allUsers = response.data?.data?.results || response.data?.results || [];
783
+ const users = Array.isArray(allUsers) ? allUsers.filter((u) => {
784
+ const matchById = u.id === currentUserId || u.id === Number(currentUserId) || String(u.id) === String(currentUserId);
785
+ const matchByEmail = u.email?.toLowerCase() === currentUserEmail?.toLowerCase();
786
+ return !(matchById || matchByEmail);
787
+ }) : [];
788
+ setAvailableUsers(users);
789
+ } catch (error2) {
790
+ console.error("[Magic-Mark] Error fetching users:", error2);
791
+ try {
792
+ const response = await get(`/${pluginId2}/users`);
793
+ const users = response.data?.data?.data || response.data?.data || response.data || [];
794
+ setAvailableUsers(users);
795
+ } catch (fallbackError) {
796
+ setAvailableUsers([]);
797
+ }
798
+ } finally {
799
+ setLoadingUsers(false);
800
+ }
801
+ };
802
+ const validateForm = () => {
803
+ setError("");
804
+ if (!name2.trim()) {
805
+ setError(formatMessage({ id: `${pluginId2}.error.nameRequired`, defaultMessage: "Name is required" }));
806
+ return false;
807
+ }
808
+ if (!path.trim()) {
809
+ setError(formatMessage({ id: `${pluginId2}.error.pathRequired`, defaultMessage: "Path is required" }));
810
+ return false;
811
+ }
812
+ return true;
813
+ };
814
+ const handleSubmit = async () => {
815
+ if (!validateForm()) return;
816
+ setIsSubmitting(true);
817
+ try {
818
+ const bookmarkId = bookmark?.documentId || bookmark?.id;
819
+ const endpoint = bookmark ? `/${pluginId2}/bookmarks/${bookmarkId}` : `/${pluginId2}/bookmarks`;
820
+ const body = {
821
+ name: name2,
822
+ path,
823
+ query,
824
+ icon,
825
+ emoji: icon,
826
+ description,
827
+ isPublic,
828
+ sharedWithRoles,
829
+ sharedWithUsers
830
+ };
831
+ if (bookmark) {
832
+ await put(endpoint, body);
833
+ } else {
834
+ await post(endpoint, body);
835
+ }
836
+ onSuccess();
837
+ } catch (error2) {
838
+ console.error("[Magic-Mark] Error saving bookmark:", error2);
839
+ setError(formatMessage({ id: `${pluginId2}.error.save`, defaultMessage: "Failed to save bookmark" }));
840
+ } finally {
841
+ setIsSubmitting(false);
842
+ }
843
+ };
844
+ const toggleRole = (roleId) => {
845
+ setSharedWithRoles(
846
+ (prev) => prev.includes(roleId) ? prev.filter((id) => id !== roleId) : [...prev, roleId]
847
+ );
848
+ };
849
+ const toggleUser = (userId) => {
850
+ setSharedWithUsers(
851
+ (prev) => prev.includes(userId) ? prev.filter((id) => id !== userId) : [...prev, userId]
852
+ );
853
+ };
854
+ const isEditing = !!bookmark;
855
+ const SelectedIcon = getIconById(icon);
856
+ return /* @__PURE__ */ jsxRuntime.jsx(Overlay, { onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContainer, { onClick: (e) => e.stopPropagation(), children: [
857
+ /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
858
+ /* @__PURE__ */ jsxRuntime.jsxs(HeaderTitle, { children: [
859
+ /* @__PURE__ */ jsxRuntime.jsx(outline.BookmarkIcon, {}),
860
+ isEditing ? formatMessage({ id: `${pluginId2}.modal.edit`, defaultMessage: "Edit Bookmark" }) : formatMessage({ id: `${pluginId2}.modal.create`, defaultMessage: "Save as Bookmark" })
861
+ ] }),
862
+ /* @__PURE__ */ jsxRuntime.jsx(CloseButton, { onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}) })
863
+ ] }),
864
+ /* @__PURE__ */ jsxRuntime.jsxs(ModalBody, { children: [
865
+ error && /* @__PURE__ */ jsxRuntime.jsx(ErrorBox, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: error }) }),
866
+ /* @__PURE__ */ jsxRuntime.jsxs(FormField, { children: [
867
+ /* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
868
+ formatMessage({ id: `${pluginId2}.form.name`, defaultMessage: "Bookmark Name" }),
869
+ " *"
870
+ ] }),
871
+ /* @__PURE__ */ jsxRuntime.jsx(
872
+ StyledTextInput,
873
+ {
874
+ type: "text",
875
+ placeholder: formatMessage({ id: `${pluginId2}.form.namePlaceholder`, defaultMessage: "e.g., Published Articles" }),
876
+ value: name2,
877
+ onChange: (e) => setName(e.target.value)
878
+ }
879
+ )
880
+ ] }),
881
+ /* @__PURE__ */ jsxRuntime.jsxs(Section, { children: [
882
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionHeader, { onClick: () => setIconSectionOpen(!iconSectionOpen), children: [
883
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionTitle, { children: [
884
+ /* @__PURE__ */ jsxRuntime.jsx(outline.SwatchIcon, {}),
885
+ formatMessage({ id: `${pluginId2}.form.icon`, defaultMessage: "Choose Icon" })
886
+ ] }),
887
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { $collapsed: !iconSectionOpen, children: /* @__PURE__ */ jsxRuntime.jsx(outline.ChevronDownIcon, {}) })
888
+ ] }),
889
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionContent, { $collapsed: !iconSectionOpen, children: [
890
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectedIconDisplay, { children: [
891
+ /* @__PURE__ */ jsxRuntime.jsx(SelectedIconCircle, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectedIcon, {}) }),
892
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [
893
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "semiBold", style: { color: theme$1.colors.neutral[800], display: "block" }, children: BOOKMARK_ICONS.find((i) => i.id === icon)?.label || "Bookmark" }),
894
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "0.75rem", display: "block" }, children: "Click below to change" })
895
+ ] })
896
+ ] }),
897
+ /* @__PURE__ */ jsxRuntime.jsx(IconPicker, { children: BOOKMARK_ICONS.map((item) => {
898
+ const IconComp = item.icon;
899
+ return /* @__PURE__ */ jsxRuntime.jsx(
900
+ IconButton,
901
+ {
902
+ $isSelected: icon === item.id,
903
+ onClick: () => setIcon(item.id),
904
+ type: "button",
905
+ title: item.label,
906
+ children: /* @__PURE__ */ jsxRuntime.jsx(IconComp, {})
907
+ },
908
+ item.id
909
+ );
910
+ }) })
911
+ ] })
912
+ ] }),
913
+ /* @__PURE__ */ jsxRuntime.jsxs(Section, { children: [
914
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionHeader, { onClick: () => setSharingSectionOpen(!sharingSectionOpen), children: [
915
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionTitle, { children: [
916
+ /* @__PURE__ */ jsxRuntime.jsx(outline.ShareIcon, {}),
917
+ formatMessage({ id: `${pluginId2}.form.sharing`, defaultMessage: "Sharing Options" }),
918
+ (isPublic || sharedWithRoles.length > 0 || sharedWithUsers.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(ItemBadge, { children: isPublic ? "Public" : `${sharedWithRoles.length + sharedWithUsers.length} shared` })
919
+ ] }),
920
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { $collapsed: !sharingSectionOpen, children: /* @__PURE__ */ jsxRuntime.jsx(outline.ChevronDownIcon, {}) })
921
+ ] }),
922
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionContent, { $collapsed: !sharingSectionOpen, children: [
923
+ /* @__PURE__ */ jsxRuntime.jsxs(PublicToggleContainer, { children: [
924
+ /* @__PURE__ */ jsxRuntime.jsxs(PublicToggleInfo, { children: [
925
+ /* @__PURE__ */ jsxRuntime.jsx(outline.GlobeAltIcon, {}),
926
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [
927
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "semiBold", style: { color: theme$1.colors.neutral[800], display: "block" }, children: "Public Bookmark" }),
928
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", style: { fontSize: "0.75rem", color: theme$1.colors.neutral[600], display: "block" }, children: "All admin users can see this" })
929
+ ] })
930
+ ] }),
931
+ /* @__PURE__ */ jsxRuntime.jsxs(SwitchContainer, { children: [
932
+ /* @__PURE__ */ jsxRuntime.jsx(
933
+ SwitchInput,
934
+ {
935
+ type: "checkbox",
936
+ checked: isPublic,
937
+ onChange: () => setIsPublic(!isPublic)
938
+ }
939
+ ),
940
+ /* @__PURE__ */ jsxRuntime.jsx(SwitchSlider, { $checked: isPublic })
941
+ ] })
942
+ ] }),
943
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Share with Roles" }),
944
+ /* @__PURE__ */ jsxRuntime.jsx(SelectionList, { $disabled: isPublic, children: loadingRoles ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "16px", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Loading..." }) }) : availableRoles.length > 0 ? availableRoles.map((role) => /* @__PURE__ */ jsxRuntime.jsxs(
945
+ SelectionItem,
946
+ {
947
+ $selected: sharedWithRoles.includes(role.id),
948
+ onClick: () => !isPublic && toggleRole(role.id),
949
+ children: [
950
+ /* @__PURE__ */ jsxRuntime.jsx(CustomCheckbox, { $checked: sharedWithRoles.includes(role.id), children: /* @__PURE__ */ jsxRuntime.jsx(outline.CheckCircleIcon, {}) }),
951
+ /* @__PURE__ */ jsxRuntime.jsx(ItemLabel, { $selected: sharedWithRoles.includes(role.id), children: role.name || role.code }),
952
+ role.isCustom && /* @__PURE__ */ jsxRuntime.jsx(ItemBadge, { $type: "custom", children: "Custom" }),
953
+ role.userCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ItemBadge, { $type: "count", children: [
954
+ role.userCount,
955
+ " users"
956
+ ] })
957
+ ]
958
+ },
959
+ role.id
960
+ )) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "16px", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "No roles available" }) }) }),
961
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Share with Users" }),
962
+ /* @__PURE__ */ jsxRuntime.jsx(SelectionList, { $disabled: isPublic, children: loadingUsers ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "16px", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Loading..." }) }) : availableUsers.length > 0 ? availableUsers.map((user) => /* @__PURE__ */ jsxRuntime.jsxs(
963
+ SelectionItem,
964
+ {
965
+ $selected: sharedWithUsers.includes(user.id),
966
+ onClick: () => !isPublic && toggleUser(user.id),
967
+ children: [
968
+ /* @__PURE__ */ jsxRuntime.jsx(CustomCheckbox, { $checked: sharedWithUsers.includes(user.id), children: /* @__PURE__ */ jsxRuntime.jsx(outline.CheckCircleIcon, {}) }),
969
+ /* @__PURE__ */ jsxRuntime.jsxs(ItemLabel, { $selected: sharedWithUsers.includes(user.id), children: [
970
+ user.firstname || "",
971
+ " ",
972
+ user.lastname || ""
973
+ ] }),
974
+ /* @__PURE__ */ jsxRuntime.jsx(ItemBadge, { children: user.email })
975
+ ]
976
+ },
977
+ user.id
978
+ )) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "16px", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "No other users" }) }) })
979
+ ] })
980
+ ] }),
981
+ /* @__PURE__ */ jsxRuntime.jsxs(Section, { children: [
982
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionHeader, { onClick: () => setFiltersSectionOpen(!filtersSectionOpen), children: [
983
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionTitle, { children: [
984
+ /* @__PURE__ */ jsxRuntime.jsx(outline.FunnelIcon, {}),
985
+ formatMessage({ id: `${pluginId2}.form.filterPreview`, defaultMessage: "Captured Filters" })
986
+ ] }),
987
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { $collapsed: !filtersSectionOpen, children: /* @__PURE__ */ jsxRuntime.jsx(outline.ChevronDownIcon, {}) })
988
+ ] }),
989
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionContent, { $collapsed: !filtersSectionOpen, children: [
990
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Content Manager Path" }),
991
+ /* @__PURE__ */ jsxRuntime.jsx(PathDisplay, { children: path || "No path captured" }),
992
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Active Filters" }),
993
+ /* @__PURE__ */ jsxRuntime.jsx(FilterPreview, { query }),
994
+ /* @__PURE__ */ jsxRuntime.jsxs(HintText, { children: [
995
+ /* @__PURE__ */ jsxRuntime.jsx(outline.LightBulbIcon, {}),
996
+ "These filters will be restored when you click this bookmark"
997
+ ] })
998
+ ] })
999
+ ] }),
1000
+ /* @__PURE__ */ jsxRuntime.jsxs(FormField, { children: [
1001
+ /* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
1002
+ formatMessage({ id: `${pluginId2}.form.description`, defaultMessage: "Description" }),
1003
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 400, color: theme$1.colors.neutral[600] }, children: " (Optional)" })
1004
+ ] }),
1005
+ /* @__PURE__ */ jsxRuntime.jsx(
1006
+ StyledTextarea,
1007
+ {
1008
+ placeholder: formatMessage({ id: `${pluginId2}.form.descriptionPlaceholder`, defaultMessage: "Add a description..." }),
1009
+ value: description,
1010
+ onChange: (e) => setDescription(e.target.value)
1011
+ }
1012
+ )
1013
+ ] })
1014
+ ] }),
1015
+ /* @__PURE__ */ jsxRuntime.jsxs(ModalFooter, { children: [
1016
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({ id: `${pluginId2}.button.cancel`, defaultMessage: "Cancel" }) }),
1017
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleSubmit, loading: isSubmitting, children: isEditing ? formatMessage({ id: `${pluginId2}.button.update`, defaultMessage: "Update" }) : formatMessage({ id: `${pluginId2}.button.save`, defaultMessage: "Save Bookmark" }) })
1018
+ ] })
1019
+ ] }) });
1020
+ };
1021
+ const fadeIn$2 = styled.keyframes`
1022
+ from { opacity: 0; transform: translateY(-8px); }
1023
+ to { opacity: 1; transform: translateY(0); }
1024
+ `;
1025
+ const PopoverContainer = styled__default.default.div`
1026
+ position: absolute;
1027
+ top: calc(100% + 8px);
1028
+ right: 0;
1029
+ min-width: 280px;
1030
+ max-width: 360px;
1031
+ max-height: 400px;
1032
+ background: #ffffff;
1033
+ border: 1px solid #dcdce4;
1034
+ border-radius: 8px;
1035
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
1036
+ z-index: 1000;
1037
+ animation: ${fadeIn$2} 0.2s ease-out;
1038
+ overflow: hidden;
1039
+ `;
1040
+ const PopoverHeader = styled__default.default.div`
1041
+ padding: 12px 16px;
1042
+ background: linear-gradient(135deg, #4945FF 0%, #7B79FF 100%);
1043
+ border-bottom: 1px solid #dcdce4;
1044
+ display: flex;
1045
+ align-items: center;
1046
+ gap: 8px;
1047
+
1048
+ svg {
1049
+ width: 16px;
1050
+ height: 16px;
1051
+ color: white;
1052
+ }
1053
+ `;
1054
+ const PopoverTitle = styled__default.default.span`
1055
+ font-size: 13px;
1056
+ font-weight: 600;
1057
+ color: white;
1058
+ `;
1059
+ const PopoverCount = styled__default.default.span`
1060
+ font-size: 11px;
1061
+ color: rgba(255, 255, 255, 0.8);
1062
+ margin-left: auto;
1063
+ `;
1064
+ const BookmarksList = styled__default.default.div`
1065
+ max-height: 300px;
1066
+ overflow-y: auto;
1067
+ padding: 8px;
1068
+
1069
+ &::-webkit-scrollbar {
1070
+ width: 6px;
1071
+ }
1072
+
1073
+ &::-webkit-scrollbar-track {
1074
+ background: #f1f1f1;
1075
+ border-radius: 3px;
1076
+ }
1077
+
1078
+ &::-webkit-scrollbar-thumb {
1079
+ background: #c0c0cf;
1080
+ border-radius: 3px;
1081
+ }
1082
+ `;
1083
+ const BookmarkItem = styled__default.default.button`
1084
+ width: 100%;
1085
+ display: flex;
1086
+ align-items: center;
1087
+ gap: 10px;
1088
+ padding: 10px 12px;
1089
+ border: none;
1090
+ border-radius: 6px;
1091
+ background: ${(props) => props.$isPinned ? "#fffbeb" : "transparent"};
1092
+ cursor: pointer;
1093
+ transition: all 0.15s ease;
1094
+ text-align: left;
1095
+
1096
+ &:hover {
1097
+ background: ${(props) => props.$isPinned ? "#fef3c7" : "#f6f6f9"};
1098
+
1099
+ .arrow-icon {
1100
+ opacity: 1;
1101
+ transform: translateX(0);
1102
+ }
1103
+ }
1104
+
1105
+ &:active {
1106
+ transform: scale(0.98);
1107
+ }
1108
+ `;
1109
+ const BookmarkIconWrapper = styled__default.default.div`
1110
+ display: flex;
1111
+ align-items: center;
1112
+ justify-content: center;
1113
+ width: 32px;
1114
+ height: 32px;
1115
+ background: linear-gradient(135deg, #EEF0FF 0%, #E0E7FF 100%);
1116
+ border-radius: 6px;
1117
+ flex-shrink: 0;
1118
+
1119
+ svg {
1120
+ width: 16px;
1121
+ height: 16px;
1122
+ color: #4945FF;
1123
+ }
1124
+ `;
1125
+ const BookmarkContent = styled__default.default.div`
1126
+ flex: 1;
1127
+ min-width: 0;
1128
+ `;
1129
+ const BookmarkName = styled__default.default.div`
1130
+ font-size: 13px;
1131
+ font-weight: 500;
1132
+ color: #32324d;
1133
+ white-space: nowrap;
1134
+ overflow: hidden;
1135
+ text-overflow: ellipsis;
1136
+ `;
1137
+ const BookmarkDescription = styled__default.default.div`
1138
+ font-size: 11px;
1139
+ color: #8e8ea9;
1140
+ white-space: nowrap;
1141
+ overflow: hidden;
1142
+ text-overflow: ellipsis;
1143
+ margin-top: 2px;
1144
+ `;
1145
+ const ArrowIcon = styled__default.default.div`
1146
+ opacity: 0;
1147
+ transform: translateX(-4px);
1148
+ transition: all 0.15s ease;
1149
+ color: #4945FF;
1150
+
1151
+ svg {
1152
+ width: 14px;
1153
+ height: 14px;
1154
+ }
1155
+ `;
1156
+ const PinIcon = styled__default.default.div`
1157
+ color: #f59e0b;
1158
+ flex-shrink: 0;
1159
+
1160
+ svg {
1161
+ width: 12px;
1162
+ height: 12px;
1163
+ }
1164
+ `;
1165
+ const EmptyState = styled__default.default.div`
1166
+ padding: 24px 16px;
1167
+ text-align: center;
1168
+ `;
1169
+ const EmptyIcon = styled__default.default.div`
1170
+ width: 48px;
1171
+ height: 48px;
1172
+ margin: 0 auto 12px;
1173
+ background: #f6f6f9;
1174
+ border-radius: 50%;
1175
+ display: flex;
1176
+ align-items: center;
1177
+ justify-content: center;
1178
+
1179
+ svg {
1180
+ width: 24px;
1181
+ height: 24px;
1182
+ color: #8e8ea9;
1183
+ }
1184
+ `;
1185
+ const PopoverFooter = styled__default.default.div`
1186
+ padding: 10px 16px;
1187
+ border-top: 1px solid #eaeaef;
1188
+ background: #fafafa;
1189
+ `;
1190
+ const ViewAllLink = styled__default.default.button`
1191
+ width: 100%;
1192
+ display: flex;
1193
+ align-items: center;
1194
+ justify-content: center;
1195
+ gap: 6px;
1196
+ padding: 8px;
1197
+ border: none;
1198
+ border-radius: 4px;
1199
+ background: transparent;
1200
+ color: #4945FF;
1201
+ font-size: 13px;
1202
+ font-weight: 500;
1203
+ cursor: pointer;
1204
+ transition: all 0.15s ease;
1205
+
1206
+ &:hover {
1207
+ background: #eef0ff;
1208
+ }
1209
+
1210
+ svg {
1211
+ width: 14px;
1212
+ height: 14px;
1213
+ }
1214
+ `;
1215
+ const ViewsListPopover = ({
1216
+ views,
1217
+ onViewClick,
1218
+ isLoading = false
1219
+ }) => {
1220
+ const { formatMessage } = reactIntl.useIntl();
1221
+ const navigate = reactRouterDom.useNavigate();
1222
+ const sortedViews = [...views].sort((a, b) => {
1223
+ if (a.isPinned && !b.isPinned) return -1;
1224
+ if (!a.isPinned && b.isPinned) return 1;
1225
+ return a.name.localeCompare(b.name);
1226
+ });
1227
+ return /* @__PURE__ */ jsxRuntime.jsxs(PopoverContainer, { children: [
1228
+ /* @__PURE__ */ jsxRuntime.jsxs(PopoverHeader, { children: [
1229
+ /* @__PURE__ */ jsxRuntime.jsx(outline.BookmarkIcon, {}),
1230
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTitle, { children: "Your Bookmarks" }),
1231
+ /* @__PURE__ */ jsxRuntime.jsxs(PopoverCount, { children: [
1232
+ views.length,
1233
+ " saved"
1234
+ ] })
1235
+ ] }),
1236
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true, children: "Loading..." }) }) : views && views.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1237
+ /* @__PURE__ */ jsxRuntime.jsx(BookmarksList, { children: sortedViews.map((view) => {
1238
+ const IconComponent = getIconById(view.icon || view.emoji || "bookmark");
1239
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1240
+ BookmarkItem,
1241
+ {
1242
+ $isPinned: view.isPinned,
1243
+ onClick: () => onViewClick(view),
1244
+ children: [
1245
+ /* @__PURE__ */ jsxRuntime.jsx(BookmarkIconWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(IconComponent, {}) }),
1246
+ /* @__PURE__ */ jsxRuntime.jsxs(BookmarkContent, { children: [
1247
+ /* @__PURE__ */ jsxRuntime.jsx(BookmarkName, { children: view.name }),
1248
+ view.description && /* @__PURE__ */ jsxRuntime.jsx(BookmarkDescription, { children: view.description })
1249
+ ] }),
1250
+ view.isPinned && /* @__PURE__ */ jsxRuntime.jsx(PinIcon, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.Pin, {}) }),
1251
+ /* @__PURE__ */ jsxRuntime.jsx(ArrowIcon, { className: "arrow-icon", children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowRight, {}) })
1252
+ ]
1253
+ },
1254
+ view.id
1255
+ );
1256
+ }) }),
1257
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverFooter, { children: /* @__PURE__ */ jsxRuntime.jsxs(ViewAllLink, { onClick: () => navigate(`/plugins/${pluginId}`), children: [
1258
+ /* @__PURE__ */ jsxRuntime.jsx(outline.BookmarkIcon, {}),
1259
+ "Manage all bookmarks"
1260
+ ] }) })
1261
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(EmptyState, { children: [
1262
+ /* @__PURE__ */ jsxRuntime.jsx(EmptyIcon, { children: /* @__PURE__ */ jsxRuntime.jsx(outline.BookmarkIcon, {}) }),
1263
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage({
1264
+ id: `${pluginId}.ViewsWidget.ViewsPopover.emptyList`,
1265
+ defaultMessage: "No bookmarks yet. Save your first view!"
1266
+ }) })
251
1267
  ] })
252
1268
  ] });
253
1269
  };
254
- const EmojiPicker = styled__default.default.div`
255
- display: grid;
256
- grid-template-columns: repeat(8, 1fr);
1270
+ const WidgetContainer = styled__default.default.div`
1271
+ display: flex;
1272
+ align-items: center;
257
1273
  gap: 8px;
258
- padding: 12px;
259
- background: ${(props) => props.theme.colors.neutral100};
1274
+ margin-right: 8px;
1275
+ `;
1276
+ const ActionButton$1 = styled__default.default.button`
1277
+ display: inline-flex;
1278
+ align-items: center;
1279
+ justify-content: center;
1280
+ gap: 6px;
1281
+ height: 36px;
1282
+ padding: 0 14px;
1283
+ font-size: 13px;
1284
+ font-weight: 500;
1285
+ border: 1px solid #dcdce4;
260
1286
  border-radius: 4px;
261
- max-height: 200px;
262
- overflow-y: auto;
1287
+ background: #ffffff;
1288
+ color: #32324d;
1289
+ cursor: pointer;
1290
+ transition: all 0.15s ease;
1291
+ white-space: nowrap;
1292
+
1293
+ &:hover {
1294
+ background: #f6f6f9;
1295
+ border-color: #c0c0cf;
1296
+ }
1297
+
1298
+ &:active {
1299
+ transform: scale(0.98);
1300
+ }
1301
+
1302
+ svg {
1303
+ width: 16px;
1304
+ height: 16px;
1305
+ flex-shrink: 0;
1306
+ }
263
1307
  `;
264
- const EmojiButton = styled__default.default.button`
265
- padding: 8px;
266
- font-size: 24px;
267
- border: 2px solid ${(props) => props.isSelected ? props.theme.colors.primary600 : props.theme.colors.neutral200};
268
- background: ${(props) => props.theme.colors.neutral0};
1308
+ const MagicMarkButton = styled__default.default.button`
1309
+ display: inline-flex;
1310
+ align-items: center;
1311
+ justify-content: center;
1312
+ width: 32px;
1313
+ height: 32px;
1314
+ border: 1px solid #dcdce4;
269
1315
  border-radius: 4px;
1316
+ background: #ffffff;
1317
+ color: #32324d;
270
1318
  cursor: pointer;
271
- transition: all 0.2s ease;
1319
+ transition: all 0.15s ease;
1320
+ position: relative;
272
1321
 
273
1322
  &:hover {
274
- border-color: ${(props) => props.theme.colors.primary600};
275
- background: ${(props) => props.theme.colors.neutral100};
1323
+ background: #f6f6f9;
1324
+ border-color: #c0c0cf;
1325
+ }
1326
+
1327
+ &:active {
1328
+ transform: scale(0.98);
1329
+ }
1330
+
1331
+ svg {
1332
+ width: 18px;
1333
+ height: 18px;
1334
+ flex-shrink: 0;
1335
+ color: #666687;
276
1336
  }
277
1337
  `;
278
- const BOOKMARK_EMOJIS = ["🔖", "📌", "⭐", "💫", "❤️", "🎯", "🚀", "📝", "🔗", "🌟", "💼", "🎨", "📚", "🔔", "✅", "🎁"];
279
- const CreateEditModal = ({
280
- bookmark,
281
- onClose,
282
- onSuccess,
283
- pluginId: pluginId2,
284
- currentPath,
285
- currentQuery
286
- }) => {
287
- const { formatMessage } = reactIntl.useIntl();
288
- const { post, put, get } = admin.useFetchClient();
289
- const [name2, setName] = React.useState("");
290
- const [path, setPath] = React.useState(currentPath || "");
291
- const [query, setQuery] = React.useState(currentQuery || "");
292
- const [emoji, setEmoji] = React.useState("🔖");
293
- const [description, setDescription] = React.useState("");
294
- const [isSubmitting, setIsSubmitting] = React.useState(false);
295
- const [showEmojiPicker, setShowEmojiPicker] = React.useState(false);
296
- const [error, setError] = React.useState("");
297
- const [isPublic, setIsPublic] = React.useState(false);
298
- const [sharedWithRoles, setSharedWithRoles] = React.useState([]);
299
- const [sharedWithUsers, setSharedWithUsers] = React.useState([]);
300
- const [availableRoles, setAvailableRoles] = React.useState([]);
301
- const [availableUsers, setAvailableUsers] = React.useState([]);
302
- const [loadingRoles, setLoadingRoles] = React.useState(false);
303
- const [loadingUsers, setLoadingUsers] = React.useState(false);
304
- React.useEffect(() => {
305
- if (bookmark) {
306
- setName(bookmark.name);
307
- setPath(bookmark.path);
308
- setQuery(bookmark.query || "");
309
- setEmoji(bookmark.emoji);
310
- setDescription(bookmark.description || "");
311
- setIsPublic(bookmark.isPublic || false);
312
- setSharedWithRoles(bookmark.sharedWithRoles || []);
313
- setSharedWithUsers(bookmark.sharedWithUsers || []);
314
- }
315
- fetchRoles();
316
- fetchUsers();
317
- }, [bookmark]);
318
- const fetchRoles = async () => {
319
- setLoadingRoles(true);
320
- try {
321
- const response = await get(`/${pluginId2}/roles`);
322
- const roles = response.data?.data?.data || response.data?.data || response.data || [];
323
- setAvailableRoles(roles);
324
- } catch (error2) {
325
- console.error("[Magic-Mark] Error fetching roles:", error2);
326
- } finally {
327
- setLoadingRoles(false);
328
- }
329
- };
330
- const fetchUsers = async () => {
331
- setLoadingUsers(true);
332
- try {
333
- const meResponse = await get("/admin/users/me");
334
- const currentUser = meResponse.data?.data || meResponse.data || meResponse;
335
- const currentUserId = currentUser?.id;
336
- const currentUserEmail = currentUser?.email;
337
- console.log("[CreateEditModal] Current user:", { currentUserId, currentUserEmail, fullResponse: currentUser });
338
- const response = await get("/admin/users?pageSize=100&page=1&sort=firstname");
339
- const allUsers = response.data?.data?.results || response.data?.results || [];
340
- console.log("[CreateEditModal] All users:", allUsers.map((u) => ({ id: u.id, email: u.email })));
341
- const users = Array.isArray(allUsers) ? allUsers.filter((u) => {
342
- const matchById = u.id === currentUserId || u.id === Number(currentUserId) || String(u.id) === String(currentUserId);
343
- const matchByEmail = u.email?.toLowerCase() === currentUserEmail?.toLowerCase();
344
- const shouldExclude = matchById || matchByEmail;
345
- if (shouldExclude) {
346
- console.log("[CreateEditModal] Excluding current user:", u.email);
347
- }
348
- return !shouldExclude;
349
- }) : [];
350
- console.log("[CreateEditModal] Filtered users (without current):", users.map((u) => ({ id: u.id, email: u.email })));
351
- setAvailableUsers(users);
352
- } catch (error2) {
353
- console.error("[Magic-Mark] Error fetching users:", error2);
354
- try {
355
- const response = await get(`/${pluginId2}/users`);
356
- const users = response.data?.data?.data || response.data?.data || response.data || [];
357
- setAvailableUsers(users);
358
- } catch (fallbackError) {
359
- console.warn("[Magic-Mark] Both user endpoints failed, feature disabled");
360
- setAvailableUsers([]);
361
- }
362
- } finally {
363
- setLoadingUsers(false);
364
- }
365
- };
366
- const validateForm = () => {
367
- setError("");
368
- if (!name2.trim()) {
369
- setError(formatMessage({
370
- id: `${pluginId2}.error.nameRequired`,
371
- defaultMessage: "Name is required"
372
- }));
373
- return false;
374
- }
375
- if (!path.trim()) {
376
- setError(formatMessage({
377
- id: `${pluginId2}.error.pathRequired`,
378
- defaultMessage: "Path is required"
379
- }));
380
- return false;
381
- }
382
- return true;
383
- };
384
- const handleSubmit = async () => {
385
- if (!validateForm()) return;
386
- setIsSubmitting(true);
387
- try {
388
- const endpoint = bookmark ? `/${pluginId2}/bookmarks/${bookmark.id}` : `/${pluginId2}/bookmarks`;
389
- const body = {
390
- name: name2,
391
- path,
392
- query,
393
- emoji,
394
- description,
395
- isPublic,
396
- sharedWithRoles,
397
- sharedWithUsers
398
- };
399
- let result;
400
- if (bookmark) {
401
- result = await put(endpoint, body);
402
- } else {
403
- result = await post(endpoint, body);
404
- }
405
- onSuccess();
406
- } catch (error2) {
407
- console.error("[Magic-Mark] Error saving bookmark:", error2);
408
- setError(formatMessage({
409
- id: `${pluginId2}.error.save`,
410
- defaultMessage: "Failed to save bookmark"
411
- }));
412
- } finally {
413
- setIsSubmitting(false);
414
- }
415
- };
416
- const isEditing = !!bookmark;
417
- return /* @__PURE__ */ jsxRuntime.jsx(
418
- "div",
419
- {
420
- style: {
421
- position: "fixed",
422
- top: 0,
423
- left: 0,
424
- right: 0,
425
- bottom: 0,
426
- backgroundColor: "rgba(0, 0, 0, 0.5)",
427
- display: "flex",
428
- alignItems: "center",
429
- justifyContent: "center",
430
- zIndex: 999
431
- },
432
- children: /* @__PURE__ */ jsxRuntime.jsxs(
433
- designSystem.Box,
434
- {
435
- padding: 6,
436
- background: "neutral0",
437
- style: {
438
- borderRadius: "8px",
439
- maxHeight: "90vh",
440
- overflow: "auto",
441
- maxWidth: "600px",
442
- width: "90%"
443
- },
444
- children: [
445
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 6, children: [
446
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h2", variant: "beta", children: isEditing ? formatMessage({
447
- id: `${pluginId2}.modal.edit`,
448
- defaultMessage: "Edit Bookmark"
449
- }) : formatMessage({
450
- id: `${pluginId2}.modal.create`,
451
- defaultMessage: "Save as Bookmark"
452
- }) }),
453
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "ghost", type: "button", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}) })
454
- ] }),
455
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
456
- designSystem.Box,
457
- {
458
- style: {
459
- display: "flex",
460
- flexDirection: "column",
461
- gap: "16px"
462
- },
463
- children: [
464
- error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, background: "danger100", borderRadius: "4px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", children: error }) }),
465
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
466
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: formatMessage({
467
- id: `${pluginId2}.form.emoji`,
468
- defaultMessage: "Choose Icon"
469
- }) }),
470
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
471
- /* @__PURE__ */ jsxRuntime.jsx(
472
- designSystem.Box,
473
- {
474
- as: "button",
475
- padding: 3,
476
- borderRadius: "4px",
477
- border: "1px solid",
478
- borderColor: "neutral200",
479
- fontSize: "32px",
480
- onClick: () => setShowEmojiPicker(!showEmojiPicker),
481
- type: "button",
482
- style: { cursor: "pointer" },
483
- children: emoji
484
- }
485
- ),
486
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage({
487
- id: `${pluginId2}.form.selectEmoji`,
488
- defaultMessage: "Click to select"
489
- }) })
490
- ] }),
491
- showEmojiPicker && /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker, { children: BOOKMARK_EMOJIS.map((e) => /* @__PURE__ */ jsxRuntime.jsx(
492
- EmojiButton,
493
- {
494
- isSelected: emoji === e,
495
- onClick: () => {
496
- setEmoji(e);
497
- setShowEmojiPicker(false);
498
- },
499
- type: "button",
500
- children: e
501
- },
502
- e
503
- )) })
504
- ] }),
505
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
506
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: formatMessage({
507
- id: `${pluginId2}.form.sharing`,
508
- defaultMessage: "Sharing Options"
509
- }) }),
510
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginBottom: 3, children: /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", cursor: "pointer" }, children: [
511
- /* @__PURE__ */ jsxRuntime.jsx(
512
- "input",
513
- {
514
- type: "checkbox",
515
- checked: isPublic,
516
- onChange: (e) => setIsPublic(e.target.checked),
517
- style: { marginRight: "8px" }
518
- }
519
- ),
520
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "14px" }, children: formatMessage({
521
- id: `${pluginId2}.form.publicAccess`,
522
- defaultMessage: "Public (All admin users can see this bookmark)"
523
- }) })
524
- ] }) }),
525
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
526
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 2, children: [
527
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage({
528
- id: `${pluginId2}.form.shareWithRoles`,
529
- defaultMessage: "Share with specific roles:"
530
- }) }),
531
- sharedWithRoles.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", fontWeight: "semiBold", textColor: "primary600", children: [
532
- sharedWithRoles.length,
533
- " selected"
534
- ] })
535
- ] }),
536
- /* @__PURE__ */ jsxRuntime.jsx(
537
- designSystem.Box,
538
- {
539
- background: isPublic ? "neutral100" : "neutral0",
540
- borderColor: "neutral200",
541
- style: {
542
- maxHeight: "150px",
543
- overflowY: "auto",
544
- border: "1px solid",
545
- borderRadius: "4px",
546
- padding: "12px"
547
- },
548
- children: loadingRoles ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: formatMessage({ id: `${pluginId2}.form.loadingRoles`, defaultMessage: "Loading roles..." }) }) : availableRoles.length > 0 ? availableRoles.map((role) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsxs("label", { style: {
549
- display: "flex",
550
- alignItems: "center",
551
- cursor: isPublic ? "not-allowed" : "pointer",
552
- padding: "6px 8px",
553
- borderRadius: "4px",
554
- background: sharedWithRoles.includes(role.id) ? "#eaf5ff" : "transparent",
555
- border: sharedWithRoles.includes(role.id) ? "1px solid #3945C9" : "1px solid transparent"
556
- }, children: [
557
- /* @__PURE__ */ jsxRuntime.jsx(
558
- "input",
559
- {
560
- type: "checkbox",
561
- checked: sharedWithRoles.includes(role.id),
562
- onChange: (e) => {
563
- if (e.target.checked) {
564
- setSharedWithRoles((prev) => {
565
- const newRoles = [...prev, role.id];
566
- return newRoles;
567
- });
568
- } else {
569
- setSharedWithRoles((prev) => {
570
- const newRoles = prev.filter((id) => id !== role.id);
571
- return newRoles;
572
- });
573
- }
574
- },
575
- style: { marginRight: "8px" },
576
- disabled: isPublic
577
- }
578
- ),
579
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
580
- fontSize: "14px",
581
- fontWeight: sharedWithRoles.includes(role.id) ? 600 : 400,
582
- color: isPublic ? "#999" : sharedWithRoles.includes(role.id) ? "#3945C9" : "#32324d"
583
- }, children: [
584
- role.name || role.code || `Role ${role.id}`,
585
- role.isCustom && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "11px", marginLeft: "4px", color: "#8C4BFF" }, children: "(Custom)" }),
586
- role.userCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: "11px", marginLeft: "4px", color: "#666" }, children: [
587
- "(",
588
- role.userCount,
589
- " user",
590
- role.userCount > 1 ? "s" : "",
591
- ")"
592
- ] })
593
- ] })
594
- ] }) }, role.id)) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage({ id: `${pluginId2}.form.noRoles`, defaultMessage: "No roles available" }) })
595
- }
596
- ),
597
- isPublic && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { marginTop: "4px", fontSize: "0.75rem" }, children: formatMessage({ id: `${pluginId2}.form.roleDisabled`, defaultMessage: "Role selection disabled when bookmark is public" }) })
598
- ] }),
599
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { marginTop: 3, children: [
600
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 2, children: [
601
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage({
602
- id: `${pluginId2}.form.shareWithUsers`,
603
- defaultMessage: "Share with specific users:"
604
- }) }),
605
- sharedWithUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", fontWeight: "semiBold", textColor: "primary600", children: [
606
- sharedWithUsers.length,
607
- " selected"
608
- ] })
609
- ] }),
610
- /* @__PURE__ */ jsxRuntime.jsx(
611
- designSystem.Box,
612
- {
613
- background: isPublic ? "neutral100" : "neutral0",
614
- borderColor: "neutral200",
615
- style: {
616
- maxHeight: "150px",
617
- overflowY: "auto",
618
- border: "1px solid",
619
- borderRadius: "4px",
620
- padding: "12px"
621
- },
622
- children: loadingUsers ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: formatMessage({ id: `${pluginId2}.form.loadingUsers`, defaultMessage: "Loading users..." }) }) : availableUsers.length > 0 ? availableUsers.map((user) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsxs("label", { style: {
623
- display: "flex",
624
- alignItems: "center",
625
- cursor: isPublic ? "not-allowed" : "pointer",
626
- padding: "6px 8px",
627
- borderRadius: "4px",
628
- background: sharedWithUsers.includes(user.id) ? "#eaf5ff" : "transparent",
629
- border: sharedWithUsers.includes(user.id) ? "1px solid #3945C9" : "1px solid transparent"
630
- }, children: [
631
- /* @__PURE__ */ jsxRuntime.jsx(
632
- "input",
633
- {
634
- type: "checkbox",
635
- checked: sharedWithUsers.includes(user.id),
636
- onChange: (e) => {
637
- if (e.target.checked) {
638
- setSharedWithUsers((prev) => {
639
- const newUsers = [...prev, user.id];
640
- return newUsers;
641
- });
642
- } else {
643
- setSharedWithUsers((prev) => {
644
- const newUsers = prev.filter((id) => id !== user.id);
645
- return newUsers;
646
- });
647
- }
648
- },
649
- style: { marginRight: "8px" },
650
- disabled: isPublic
651
- }
652
- ),
653
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
654
- fontSize: "14px",
655
- fontWeight: sharedWithUsers.includes(user.id) ? 600 : 400,
656
- color: isPublic ? "#999" : sharedWithUsers.includes(user.id) ? "#3945C9" : "#32324d"
657
- }, children: [
658
- user.firstname || "",
659
- " ",
660
- user.lastname || "",
661
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: "12px", color: "#666", marginLeft: "4px" }, children: [
662
- "(",
663
- user.email || user.username || "No email",
664
- ")"
665
- ] })
666
- ] })
667
- ] }) }, user.id)) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage({ id: `${pluginId2}.form.noUsers`, defaultMessage: "No other users available" }) })
668
- }
669
- ),
670
- isPublic && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { marginTop: "4px", fontSize: "0.75rem" }, children: formatMessage({ id: `${pluginId2}.form.userDisabled`, defaultMessage: "User selection disabled when bookmark is public" }) })
671
- ] })
672
- ] }),
673
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
674
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, as: "label", htmlFor: "name", children: [
675
- formatMessage({
676
- id: `${pluginId2}.form.name`,
677
- defaultMessage: "Bookmark Name"
678
- }),
679
- " *"
680
- ] }),
681
- /* @__PURE__ */ jsxRuntime.jsx(
682
- designSystem.TextInput,
683
- {
684
- id: "name",
685
- type: "text",
686
- placeholder: formatMessage({ id: `${pluginId2}.form.namePlaceholder`, defaultMessage: "e.g., Published Articles" }),
687
- value: name2,
688
- onChange: (e) => setName(e.target.value)
689
- }
690
- )
691
- ] }),
692
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
693
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, as: "label", htmlFor: "path", children: formatMessage({
694
- id: `${pluginId2}.form.path`,
695
- defaultMessage: "Content Manager Path"
696
- }) }),
697
- /* @__PURE__ */ jsxRuntime.jsx(
698
- designSystem.TextInput,
699
- {
700
- id: "path",
701
- type: "text",
702
- placeholder: "/content-manager/collection-types/api::article.article",
703
- value: path,
704
- readOnly: true,
705
- disabled: true
706
- }
707
- ),
708
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { marginTop: "4px", display: "block" }, children: formatMessage({
709
- id: `${pluginId2}.form.pathHelp`,
710
- defaultMessage: "Automatically captured from Content Manager"
711
- }) })
712
- ] }),
713
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
714
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: formatMessage({
715
- id: `${pluginId2}.form.filterPreview`,
716
- defaultMessage: "Captured Filters & Settings"
717
- }) }),
718
- /* @__PURE__ */ jsxRuntime.jsx(FilterPreview, { query }),
719
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 1, style: { marginTop: "8px" }, children: [
720
- /* @__PURE__ */ jsxRuntime.jsx(icons.Lightbulb, { fill: "neutral600", width: "14px", height: "14px" }),
721
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage({
722
- id: `${pluginId2}.form.queryHelp`,
723
- defaultMessage: "These filters will be restored when you click this bookmark"
724
- }) })
725
- ] })
726
- ] }),
727
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
728
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, as: "label", htmlFor: "description", children: formatMessage({
729
- id: `${pluginId2}.form.description`,
730
- defaultMessage: "Description (Optional)"
731
- }) }),
732
- /* @__PURE__ */ jsxRuntime.jsx(
733
- designSystem.Textarea,
734
- {
735
- id: "description",
736
- placeholder: formatMessage({ id: `${pluginId2}.form.descriptionPlaceholder`, defaultMessage: "Add a description..." }),
737
- value: description,
738
- onChange: (e) => setDescription(e.target.value)
739
- }
740
- )
741
- ] })
742
- ]
743
- }
744
- ) }),
745
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "flex-end", gap: 2, children: [
746
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", type: "button", children: formatMessage({
747
- id: `${pluginId2}.button.cancel`,
748
- defaultMessage: "Cancel"
749
- }) }),
750
- /* @__PURE__ */ jsxRuntime.jsx(
751
- designSystem.Button,
752
- {
753
- onClick: handleSubmit,
754
- loading: isSubmitting,
755
- type: "button",
756
- children: isEditing ? formatMessage({
757
- id: `${pluginId2}.button.update`,
758
- defaultMessage: "Update"
759
- }) : formatMessage({
760
- id: `${pluginId2}.button.save`,
761
- defaultMessage: "Save Bookmark"
762
- })
763
- }
764
- )
765
- ] })
766
- ]
767
- }
768
- )
769
- }
770
- );
771
- };
1338
+ const MagicMarkWrapper = styled__default.default.div`
1339
+ position: relative;
1340
+ `;
1341
+ const Badge = styled__default.default.span`
1342
+ position: absolute;
1343
+ top: -6px;
1344
+ right: -6px;
1345
+ display: inline-flex;
1346
+ align-items: center;
1347
+ justify-content: center;
1348
+ min-width: 18px;
1349
+ height: 18px;
1350
+ padding: 0 5px;
1351
+ font-size: 10px;
1352
+ font-weight: 700;
1353
+ background: #4945FF;
1354
+ color: #ffffff;
1355
+ border-radius: 9px;
1356
+ border: 2px solid #ffffff;
1357
+ box-shadow: 0 1px 3px rgba(0,0,0,0.15);
1358
+ `;
772
1359
  const ViewsWidget = () => {
773
1360
  const { formatMessage } = reactIntl.useIntl();
774
1361
  const navigate = reactRouterDom.useNavigate();
@@ -799,8 +1386,6 @@ const ViewsWidget = () => {
799
1386
  path = path.substring(6);
800
1387
  }
801
1388
  const query = window.location.search.substring(1);
802
- console.log("[ViewsWidget] Captured path:", path);
803
- console.log("[ViewsWidget] Captured query:", query);
804
1389
  setCurrentPath(path);
805
1390
  setCurrentQuery(query);
806
1391
  setShowCreateModal(true);
@@ -816,33 +1401,32 @@ const ViewsWidget = () => {
816
1401
  }
817
1402
  setViewsPopoverVisible(false);
818
1403
  };
819
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, marginRight: 1, children: [
820
- /* @__PURE__ */ jsxRuntime.jsx(
821
- designSystem.Button,
1404
+ return /* @__PURE__ */ jsxRuntime.jsxs(WidgetContainer, { children: [
1405
+ /* @__PURE__ */ jsxRuntime.jsxs(
1406
+ ActionButton$1,
822
1407
  {
823
- variant: "tertiary",
824
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
825
1408
  onClick: handleOpenModal,
826
- children: formatMessage({
1409
+ title: formatMessage({
827
1410
  id: `${pluginId}.ViewsWidget.actions.create`,
828
- defaultMessage: "Save Bookmark"
829
- })
1411
+ defaultMessage: "Save current view as bookmark"
1412
+ }),
1413
+ children: [
1414
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
1415
+ "Save"
1416
+ ]
830
1417
  }
831
1418
  ),
832
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
1419
+ /* @__PURE__ */ jsxRuntime.jsxs(MagicMarkWrapper, { children: [
833
1420
  /* @__PURE__ */ jsxRuntime.jsx(
834
- designSystem.Button,
1421
+ MagicMarkButton,
835
1422
  {
836
1423
  ref: viewsButtonRef,
837
- variant: "tertiary",
838
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.List, {}),
839
1424
  onClick: () => setViewsPopoverVisible((s) => !s),
840
- children: formatMessage({
841
- id: `${pluginId}.ViewsWidget.actions.showList`,
842
- defaultMessage: "Magicmark"
843
- })
1425
+ title: "MagicMark Bookmarks",
1426
+ children: /* @__PURE__ */ jsxRuntime.jsx(outline.BookmarkIcon, {})
844
1427
  }
845
1428
  ),
1429
+ bookmarks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { children: bookmarks.length }),
846
1430
  viewsPopoverVisible && viewsButtonRef.current && /* @__PURE__ */ jsxRuntime.jsx(
847
1431
  ViewsListPopover,
848
1432
  {
@@ -1261,7 +1845,7 @@ const Chevron = styled__default.default(icons.ChevronRight)`
1261
1845
  display: none;
1262
1846
  }
1263
1847
  `;
1264
- const ClearButton = styled__default.default.button`
1848
+ const ClearButton$1 = styled__default.default.button`
1265
1849
  display: flex;
1266
1850
  align-items: center;
1267
1851
  justify-content: center;
@@ -1458,7 +2042,7 @@ const RelationFieldSelector = ({
1458
2042
  searchable: true
1459
2043
  }
1460
2044
  ),
1461
- /* @__PURE__ */ jsxRuntime.jsx(ClearButton, { onClick: () => clearFromLevel(1), title: "Clear selection", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}) })
2045
+ /* @__PURE__ */ jsxRuntime.jsx(ClearButton$1, { onClick: () => clearFromLevel(1), title: "Clear selection", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}) })
1462
2046
  ] }) })
1463
2047
  ] })
1464
2048
  ] }),
@@ -1480,7 +2064,7 @@ const RelationFieldSelector = ({
1480
2064
  searchable: true
1481
2065
  }
1482
2066
  ),
1483
- /* @__PURE__ */ jsxRuntime.jsx(ClearButton, { onClick: () => clearFromLevel(2), title: "Clear selection", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}) })
2067
+ /* @__PURE__ */ jsxRuntime.jsx(ClearButton$1, { onClick: () => clearFromLevel(2), title: "Clear selection", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}) })
1484
2068
  ] }) })
1485
2069
  ] })
1486
2070
  ] })
@@ -3064,6 +3648,78 @@ const SimpleAdvancedFilterModal = ({
3064
3648
  ] })
3065
3649
  ] }) });
3066
3650
  };
3651
+ const FilterButtonGroup = styled__default.default.div`
3652
+ display: flex;
3653
+ align-items: center;
3654
+ gap: 6px;
3655
+ `;
3656
+ const FilterButton = styled__default.default.button`
3657
+ display: inline-flex;
3658
+ align-items: center;
3659
+ justify-content: center;
3660
+ gap: 6px;
3661
+ height: 36px;
3662
+ padding: 0 14px;
3663
+ font-size: 13px;
3664
+ font-weight: 500;
3665
+ border: 1px solid ${(props) => props.$isActive ? "#4945FF" : "#dcdce4"};
3666
+ border-radius: 4px;
3667
+ background: ${(props) => props.$isActive ? "#EEF0FF" : "#ffffff"};
3668
+ color: ${(props) => props.$isActive ? "#4945FF" : "#32324d"};
3669
+ cursor: pointer;
3670
+ transition: all 0.15s ease;
3671
+ white-space: nowrap;
3672
+
3673
+ &:hover {
3674
+ background: ${(props) => props.$isActive ? "#E0E7FF" : "#f6f6f9"};
3675
+ border-color: ${(props) => props.$isActive ? "#4945FF" : "#c0c0cf"};
3676
+ }
3677
+
3678
+ &:active {
3679
+ transform: scale(0.98);
3680
+ }
3681
+
3682
+ svg {
3683
+ width: 16px;
3684
+ height: 16px;
3685
+ flex-shrink: 0;
3686
+ }
3687
+ `;
3688
+ const ClearButton = styled__default.default.button`
3689
+ display: inline-flex;
3690
+ align-items: center;
3691
+ justify-content: center;
3692
+ width: 36px;
3693
+ height: 36px;
3694
+ padding: 0;
3695
+ border: 1px solid #fecaca;
3696
+ border-radius: 4px;
3697
+ background: #fef2f2;
3698
+ color: #dc2626;
3699
+ cursor: pointer;
3700
+ transition: all 0.15s ease;
3701
+
3702
+ &:hover {
3703
+ background: #fee2e2;
3704
+ border-color: #fca5a5;
3705
+ }
3706
+
3707
+ &:active {
3708
+ transform: scale(0.98);
3709
+ }
3710
+
3711
+ svg {
3712
+ width: 16px;
3713
+ height: 16px;
3714
+ }
3715
+ `;
3716
+ const ActiveDot = styled__default.default.span`
3717
+ width: 6px;
3718
+ height: 6px;
3719
+ background: #22c55e;
3720
+ border-radius: 50%;
3721
+ margin-left: 2px;
3722
+ `;
3067
3723
  const AdvancedFilterButton = () => {
3068
3724
  const [showModal, setShowModal] = React.useState(false);
3069
3725
  const navigate = reactRouterDom.useNavigate();
@@ -3204,24 +3860,26 @@ const AdvancedFilterButton = () => {
3204
3860
  console.log("[AdvancedFilter] Current query from URL:", currentQuery);
3205
3861
  return currentQuery;
3206
3862
  };
3207
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3208
- /* @__PURE__ */ jsxRuntime.jsx(
3209
- designSystem.Button,
3863
+ return /* @__PURE__ */ jsxRuntime.jsxs(FilterButtonGroup, { children: [
3864
+ /* @__PURE__ */ jsxRuntime.jsxs(
3865
+ FilterButton,
3210
3866
  {
3211
- variant: hasActiveFilters ? "default" : "secondary",
3212
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Filter, {}),
3867
+ $isActive: hasActiveFilters,
3213
3868
  onClick: () => setShowModal(true),
3214
- size: "S",
3215
- children: hasActiveFilters ? "Filters Active" : "Advanced Filters"
3869
+ title: "Open advanced filter builder",
3870
+ children: [
3871
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Filter, {}),
3872
+ "Filters",
3873
+ hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx(ActiveDot, {})
3874
+ ]
3216
3875
  }
3217
3876
  ),
3218
3877
  hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx(
3219
- designSystem.Button,
3878
+ ClearButton,
3220
3879
  {
3221
- variant: "danger-light",
3222
3880
  onClick: handleClearFilters,
3223
- size: "S",
3224
- children: "Clear All"
3881
+ title: "Clear all filters",
3882
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {})
3225
3883
  }
3226
3884
  ),
3227
3885
  showModal && /* @__PURE__ */ jsxRuntime.jsx(
@@ -3248,13 +3906,13 @@ const index = {
3248
3906
  register(app) {
3249
3907
  console.log(`[${pluginId}] Registering plugin...`);
3250
3908
  app.addMenuLink({
3251
- to: `/plugins/${pluginId}`,
3909
+ to: `plugins/${pluginId}`,
3252
3910
  icon: PluginIcon,
3253
3911
  intlLabel: {
3254
3912
  id: `${pluginId}.Admin.MainMenu.PluginName`,
3255
3913
  defaultMessage: name
3256
3914
  },
3257
- Component: () => Promise.resolve().then(() => require("./App-B6x0aSMN.js")),
3915
+ Component: () => Promise.resolve().then(() => require("./App-DduKOTII.js")),
3258
3916
  permissions: []
3259
3917
  });
3260
3918
  app.createSettingSection(
@@ -3275,7 +3933,7 @@ const index = {
3275
3933
  to: `${pluginId}/upgrade`,
3276
3934
  Component: () => Promise.resolve().then(() => require(
3277
3935
  /* webpackChunkName: "magic-mark-upgrade" */
3278
- "./UpgradePage-Bm0SkuCi.js"
3936
+ "./UpgradePage-B5kfn6Np.js"
3279
3937
  )),
3280
3938
  permissions: []
3281
3939
  },
@@ -3360,6 +4018,7 @@ const index = {
3360
4018
  }
3361
4019
  };
3362
4020
  exports.CreateEditModal = CreateEditModal;
4021
+ exports.getIconById = getIconById;
3363
4022
  exports.index = index;
3364
4023
  exports.pluginId = pluginId;
3365
4024
  exports.useLicenseInfo = useLicenseInfo;