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