astro-tractstack 2.3.1 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +36 -3
- package/package.json +1 -1
- package/templates/custom/shopify/Cart.tsx +16 -5
- package/templates/custom/shopify/CheckoutModal.tsx +4 -4
- package/templates/custom/shopify/ShopifyCartManager.tsx +27 -36
- package/templates/custom/shopify/ShopifyCheckout.tsx +4 -33
- package/templates/custom/shopify/ShopifyProductGrid.tsx +42 -14
- package/templates/custom/shopify/ShopifyServiceList.tsx +94 -50
- package/templates/src/components/Footer.astro +2 -2
- package/templates/src/components/Header.astro +14 -8
- package/templates/src/components/Menu.tsx +157 -135
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +2 -2
- package/templates/src/components/codehooks/EpinetDurationSelector.tsx +27 -6
- package/templates/src/components/codehooks/EpinetTableView.tsx +153 -112
- package/templates/src/components/codehooks/EpinetWrapper.tsx +4 -1
- package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +8 -1
- package/templates/src/components/codehooks/ProductCardSetup.tsx +9 -1
- package/templates/src/components/codehooks/ProductGridSetup.tsx +9 -1
- package/templates/src/components/compositor/nodes/BgPaneWrapper.tsx +2 -1
- package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +1 -1
- package/templates/src/components/edit/ToolBar.tsx +2 -1
- package/templates/src/components/edit/context/ContextPaneConfig_slug.tsx +2 -2
- package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +13 -0
- package/templates/src/components/edit/pane/AddPanePanel_newCustomCopy.tsx +2 -2
- package/templates/src/components/edit/pane/ConfigPanePanel.tsx +1 -1
- package/templates/src/components/edit/state/SaveModal.tsx +1 -1
- package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +8 -3
- package/templates/src/components/form/DateTimeInput.tsx +10 -3
- package/templates/src/components/form/FileUpload.tsx +11 -5
- package/templates/src/components/form/NumberInput.tsx +2 -2
- package/templates/src/components/form/advanced/APIConfigSection.tsx +2 -38
- package/templates/src/components/form/brand/SiteConfigSection.tsx +10 -0
- package/templates/src/components/storykeep/Dashboard_Shopify.tsx +7 -8
- package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +2 -2
- package/templates/src/components/storykeep/controls/content/ProductTable.tsx +2 -2
- package/templates/src/components/storykeep/controls/content/ResourceBulkIngest.tsx +79 -51
- package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +1 -0
- package/templates/src/components/storykeep/email-builder/Blocks.tsx +169 -0
- package/templates/src/components/storykeep/email-builder/EmailBuilder.tsx +223 -0
- package/templates/src/components/storykeep/email-builder/PreviewModal.tsx +136 -0
- package/templates/src/components/storykeep/email-builder/PropertyPanel.tsx +154 -0
- package/templates/src/components/storykeep/shopify/ShopifyDashboard.tsx +1 -8
- package/templates/src/components/storykeep/shopify/ShopifyDashboard_Bookings.tsx +32 -6
- package/templates/src/components/storykeep/shopify/ShopifyDashboard_Emails.tsx +105 -0
- package/templates/src/layouts/Layout.astro +8 -5
- package/templates/src/stores/shopify.ts +16 -0
- package/templates/src/types/formTypes.ts +4 -2
- package/templates/src/types/tractstack.ts +5 -2
- package/templates/src/utils/api/brandConfig.ts +2 -0
- package/templates/src/utils/api/brandHelpers.ts +16 -0
- package/templates/src/utils/api/emailHelpers.ts +105 -0
- package/templates/src/utils/tenantResolver.ts +1 -1
- package/utils/inject-files.ts +34 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
2
|
import { useStore } from '@nanostores/react';
|
|
3
|
+
import { classNames } from '@/utils/helpers';
|
|
3
4
|
import { epinetCustomFilters } from '@/stores/analytics';
|
|
4
5
|
import { Accordion } from '@ark-ui/react';
|
|
5
6
|
import ChevronLeftIcon from '@heroicons/react/24/outline/ChevronLeftIcon';
|
|
@@ -68,6 +69,7 @@ const EpinetTableView = ({
|
|
|
68
69
|
const [currentDay, setCurrentDay] = useState<string | null>(null);
|
|
69
70
|
const [availableDays, setAvailableDays] = useState<string[]>([]);
|
|
70
71
|
const [currentDayIndex, setCurrentDayIndex] = useState(0);
|
|
72
|
+
const [openAccordionValues, setOpenAccordionValues] = useState<string[]>([]);
|
|
71
73
|
|
|
72
74
|
const getContentInfo = (
|
|
73
75
|
contentId: string
|
|
@@ -215,6 +217,12 @@ const EpinetTableView = ({
|
|
|
215
217
|
setCurrentDay(availableDays[newIndex]);
|
|
216
218
|
};
|
|
217
219
|
|
|
220
|
+
useEffect(() => {
|
|
221
|
+
setOpenAccordionValues((prev) =>
|
|
222
|
+
prev.filter((v) => !v.startsWith('empty-'))
|
|
223
|
+
);
|
|
224
|
+
}, [currentDay]);
|
|
225
|
+
|
|
218
226
|
const getCurrentDayData = (): {
|
|
219
227
|
data: HourData[];
|
|
220
228
|
dailyTotal: number;
|
|
@@ -485,129 +493,162 @@ const EpinetTableView = ({
|
|
|
485
493
|
</div>
|
|
486
494
|
</div>
|
|
487
495
|
|
|
488
|
-
<Accordion.Root
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
496
|
+
<Accordion.Root
|
|
497
|
+
multiple
|
|
498
|
+
className="w-full"
|
|
499
|
+
value={openAccordionValues}
|
|
500
|
+
onValueChange={({ value }) =>
|
|
501
|
+
setOpenAccordionValues(value.filter((v) => !v.startsWith('empty-')))
|
|
502
|
+
}
|
|
503
|
+
>
|
|
504
|
+
{dayData.map((item, index) => {
|
|
505
|
+
const itemValue =
|
|
506
|
+
item.type === 'active' ? item.hourKey : `empty-${index}`;
|
|
507
|
+
const isExpandable = item.type === 'active';
|
|
508
|
+
const isOpen = openAccordionValues.includes(itemValue);
|
|
509
|
+
return (
|
|
510
|
+
<Accordion.Item
|
|
511
|
+
key={item.type === 'active' ? item.hourKey : `empty-${index}`}
|
|
512
|
+
value={itemValue}
|
|
513
|
+
disabled={!isExpandable}
|
|
514
|
+
className="border-b border-gray-100 last:border-b-0"
|
|
515
|
+
>
|
|
516
|
+
<Accordion.ItemTrigger
|
|
517
|
+
className={classNames(
|
|
518
|
+
'flex w-full items-center justify-between p-3 text-left transition-colors duration-200',
|
|
519
|
+
isExpandable
|
|
520
|
+
? 'cursor-pointer hover:bg-gray-100'
|
|
521
|
+
: 'cursor-default hover:bg-transparent'
|
|
522
|
+
)}
|
|
523
|
+
>
|
|
524
|
+
{item.type === 'active' ? (
|
|
525
|
+
<div className="flex flex-grow items-center justify-between space-x-3">
|
|
526
|
+
<div className="flex flex-grow items-center space-x-3">
|
|
527
|
+
<span className="text-sm font-bold text-gray-700">
|
|
528
|
+
{item.humanReadableTime}
|
|
529
|
+
</span>
|
|
530
|
+
<span className="text-xs text-gray-600">
|
|
531
|
+
{item.hourlyTotal} event
|
|
532
|
+
{item.hourlyTotal !== 1 ? 's' : ''} /{' '}
|
|
533
|
+
{item.hourlyVisitors} visitor
|
|
534
|
+
{item.hourlyVisitors !== 1 ? 's' : ''}
|
|
535
|
+
</span>
|
|
536
|
+
<div className="relative h-2 w-full max-w-48 rounded bg-gray-200">
|
|
537
|
+
<div
|
|
538
|
+
className="absolute left-0 top-0 h-2 rounded bg-cyan-600"
|
|
539
|
+
style={{
|
|
540
|
+
width: `${Math.max(item.relativeToMax * 100, 5)}%`,
|
|
541
|
+
}}
|
|
542
|
+
title={`${item.hourlyTotal} events (${(
|
|
543
|
+
item.relativeToMax * 100
|
|
544
|
+
).toFixed(1)}% of busiest hour)`}
|
|
545
|
+
/>
|
|
546
|
+
</div>
|
|
518
547
|
</div>
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
onClick={(e) => {
|
|
523
|
-
e.stopPropagation();
|
|
524
|
-
focusOnThisHour(item.hourKey);
|
|
525
|
-
}}
|
|
526
|
-
className="flex cursor-pointer items-center rounded-md bg-orange-100 px-2 py-1 text-xs font-bold text-orange-800 transition-colors duration-200 hover:bg-orange-200"
|
|
527
|
-
role="button"
|
|
528
|
-
tabIndex={0}
|
|
529
|
-
onKeyDown={(e) => {
|
|
530
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
531
|
-
e.preventDefault();
|
|
548
|
+
<div className="flex items-center space-x-2">
|
|
549
|
+
<div
|
|
550
|
+
onClick={(e) => {
|
|
532
551
|
e.stopPropagation();
|
|
533
552
|
focusOnThisHour(item.hourKey);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
553
|
+
}}
|
|
554
|
+
className="flex cursor-pointer items-center rounded-md bg-orange-100 px-2 py-1 text-xs font-bold text-orange-800 transition-colors duration-200 hover:bg-orange-200"
|
|
555
|
+
role="button"
|
|
556
|
+
tabIndex={0}
|
|
557
|
+
onKeyDown={(e) => {
|
|
558
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
559
|
+
e.preventDefault();
|
|
560
|
+
e.stopPropagation();
|
|
561
|
+
focusOnThisHour(item.hourKey);
|
|
562
|
+
}
|
|
563
|
+
}}
|
|
564
|
+
>
|
|
565
|
+
<MagnifyingGlassIcon className="mr-1 h-3 w-3" />
|
|
566
|
+
Journeys this Hour
|
|
567
|
+
</div>
|
|
568
|
+
<div className="flex items-center rounded-md bg-orange-100 px-2 py-1 text-xs font-bold text-orange-800">
|
|
569
|
+
<Accordion.ItemIndicator>
|
|
570
|
+
<ChevronDownIcon
|
|
571
|
+
className={classNames(
|
|
572
|
+
'h-3 w-3 transition-transform duration-200',
|
|
573
|
+
isOpen && 'rotate-180'
|
|
574
|
+
)}
|
|
575
|
+
/>
|
|
576
|
+
</Accordion.ItemIndicator>
|
|
577
|
+
<span
|
|
578
|
+
className={classNames(
|
|
579
|
+
'ml-1',
|
|
580
|
+
isOpen ? 'hidden' : 'block'
|
|
581
|
+
)}
|
|
582
|
+
>
|
|
583
|
+
Expand Details
|
|
584
|
+
</span>
|
|
585
|
+
<span
|
|
586
|
+
className={classNames(
|
|
587
|
+
'ml-1',
|
|
588
|
+
isOpen ? 'block' : 'hidden'
|
|
589
|
+
)}
|
|
590
|
+
>
|
|
591
|
+
Hide Details
|
|
592
|
+
</span>
|
|
593
|
+
</div>
|
|
539
594
|
</div>
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
<span className="
|
|
545
|
-
|
|
595
|
+
</div>
|
|
596
|
+
) : (
|
|
597
|
+
<div className="flex flex-grow items-center">
|
|
598
|
+
<div className="flex items-center">
|
|
599
|
+
<span className="text-sm text-gray-700">
|
|
600
|
+
{item.humanReadableDisplay}
|
|
546
601
|
</span>
|
|
547
|
-
<span className="ml-
|
|
548
|
-
|
|
602
|
+
<span className="ml-2 text-xs italic text-gray-500">
|
|
603
|
+
{item.isFuture ? 'The future awaits!' : 'No activity'}
|
|
549
604
|
</span>
|
|
550
605
|
</div>
|
|
551
606
|
</div>
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
)}
|
|
568
|
-
</Accordion.ItemTrigger>
|
|
569
|
-
|
|
570
|
-
<Accordion.ItemContent className="p-4">
|
|
571
|
-
{item.type === 'active' && (
|
|
572
|
-
<div className="space-y-4">
|
|
573
|
-
{item.contentItems.map((content) => (
|
|
574
|
-
<div
|
|
575
|
-
key={`${item.hourKey}-${content.contentId}`}
|
|
576
|
-
className="mb-3"
|
|
577
|
-
>
|
|
578
|
-
<div className="mb-1 flex items-center justify-between text-sm font-bold text-gray-700">
|
|
579
|
-
<div className="flex items-center">
|
|
580
|
-
{getContentIcon(content.contentType)}
|
|
581
|
-
{content.title}
|
|
582
|
-
</div>
|
|
583
|
-
{content.visitorIds.length > 0 && (
|
|
584
|
-
<div
|
|
585
|
-
className="flex items-center text-xs text-gray-600"
|
|
586
|
-
title={content.visitorIds.join(', ')}
|
|
587
|
-
>
|
|
588
|
-
<UserGroupIcon className="mr-1 h-3 w-3" />
|
|
589
|
-
{content.visitorIds.length} unique visitor
|
|
590
|
-
{content.visitorIds.length !== 1 ? 's' : ''}
|
|
591
|
-
</div>
|
|
592
|
-
)}
|
|
593
|
-
</div>
|
|
594
|
-
<div className="flex flex-wrap gap-2">
|
|
595
|
-
{content.events.map((event, eventIdx) => (
|
|
596
|
-
<div
|
|
597
|
-
key={`${item.hourKey}-${content.contentId}-${event.verb}-${eventIdx}`}
|
|
598
|
-
className="rounded-full bg-cyan-100 px-2 py-0.5 text-xs font-bold text-cyan-800"
|
|
599
|
-
>
|
|
600
|
-
{event.verb} [{event.count}]
|
|
607
|
+
)}
|
|
608
|
+
</Accordion.ItemTrigger>
|
|
609
|
+
|
|
610
|
+
{isExpandable && (
|
|
611
|
+
<Accordion.ItemContent className="p-4">
|
|
612
|
+
<div className="space-y-4">
|
|
613
|
+
{item.contentItems.map((content) => (
|
|
614
|
+
<div
|
|
615
|
+
key={`${item.hourKey}-${content.contentId}`}
|
|
616
|
+
className="mb-3"
|
|
617
|
+
>
|
|
618
|
+
<div className="mb-1 flex items-center justify-between text-sm font-bold text-gray-700">
|
|
619
|
+
<div className="flex items-center">
|
|
620
|
+
{getContentIcon(content.contentType)}
|
|
621
|
+
{content.title}
|
|
601
622
|
</div>
|
|
602
|
-
|
|
623
|
+
{content.visitorIds.length > 0 && (
|
|
624
|
+
<div
|
|
625
|
+
className="flex items-center text-xs text-gray-600"
|
|
626
|
+
title={content.visitorIds.join(', ')}
|
|
627
|
+
>
|
|
628
|
+
<UserGroupIcon className="mr-1 h-3 w-3" />
|
|
629
|
+
{content.visitorIds.length} unique visitor
|
|
630
|
+
{content.visitorIds.length !== 1 ? 's' : ''}
|
|
631
|
+
</div>
|
|
632
|
+
)}
|
|
633
|
+
</div>
|
|
634
|
+
<div className="flex flex-wrap gap-2">
|
|
635
|
+
{content.events.map((event, eventIdx) => (
|
|
636
|
+
<div
|
|
637
|
+
key={`${item.hourKey}-${content.contentId}-${event.verb}-${eventIdx}`}
|
|
638
|
+
className="rounded-full bg-cyan-100 px-2 py-0.5 text-xs font-bold text-cyan-800"
|
|
639
|
+
>
|
|
640
|
+
{event.verb} [{event.count}]
|
|
641
|
+
</div>
|
|
642
|
+
))}
|
|
643
|
+
</div>
|
|
603
644
|
</div>
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
</
|
|
645
|
+
))}
|
|
646
|
+
</div>
|
|
647
|
+
</Accordion.ItemContent>
|
|
607
648
|
)}
|
|
608
|
-
</Accordion.
|
|
609
|
-
|
|
610
|
-
)
|
|
649
|
+
</Accordion.Item>
|
|
650
|
+
);
|
|
651
|
+
})}
|
|
611
652
|
|
|
612
653
|
{dayData.length === 0 && (
|
|
613
654
|
<div className="py-6 text-center text-sm text-gray-500">
|
|
@@ -269,7 +269,10 @@ const EpinetWrapper = ({
|
|
|
269
269
|
return (
|
|
270
270
|
<div className="flex h-96 w-full items-center justify-center rounded bg-gray-100">
|
|
271
271
|
<div className="text-center">
|
|
272
|
-
<div
|
|
272
|
+
<div
|
|
273
|
+
className="inline-block h-8 w-8 animate-spin rounded-full border-4 border-solid border-cyan-600 border-r-transparent motion-reduce:animate-none"
|
|
274
|
+
style={{ verticalAlign: '-0.125em' }}
|
|
275
|
+
></div>
|
|
273
276
|
<p className="mt-4 text-sm text-gray-600">
|
|
274
277
|
Discovering analytics configuration...
|
|
275
278
|
</p>
|
|
@@ -22,6 +22,13 @@ const comboboxItemStyles = `
|
|
|
22
22
|
.combo-item[data-state="checked"] .check-indicator {
|
|
23
23
|
display: flex;
|
|
24
24
|
}
|
|
25
|
+
.combo-item[data-highlighted] {
|
|
26
|
+
background-color: #0891b2;
|
|
27
|
+
color: #fff;
|
|
28
|
+
}
|
|
29
|
+
.combo-item[data-highlighted] .check-indicator {
|
|
30
|
+
color: #fff;
|
|
31
|
+
}
|
|
25
32
|
`;
|
|
26
33
|
|
|
27
34
|
const FeaturedArticleSetup = ({
|
|
@@ -268,7 +275,7 @@ const FeaturedArticleSetup = ({
|
|
|
268
275
|
<Combobox.Item
|
|
269
276
|
key={item.slug}
|
|
270
277
|
item={item}
|
|
271
|
-
className="combo-item relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900
|
|
278
|
+
className="combo-item relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900"
|
|
272
279
|
>
|
|
273
280
|
<span className="block truncate">{item.title}</span>
|
|
274
281
|
<span className="check-indicator absolute inset-y-0 left-0 flex items-center pl-3 text-cyan-600">
|
|
@@ -7,6 +7,13 @@ import { fullContentMapStore } from '@/stores/storykeep';
|
|
|
7
7
|
import { getCtx } from '@/stores/nodes';
|
|
8
8
|
import type { PaneNode } from '@/types/compositorTypes';
|
|
9
9
|
|
|
10
|
+
const productCardComboItemHighlightStyles = `
|
|
11
|
+
.product-card-combo-item[data-highlighted] {
|
|
12
|
+
background-color: #0891b2;
|
|
13
|
+
color: #fff;
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
|
|
10
17
|
interface ProductCardSetupProps {
|
|
11
18
|
nodeId: string;
|
|
12
19
|
params: Record<string, any> | null;
|
|
@@ -118,6 +125,7 @@ export const ProductCardSetup = (props: ProductCardSetupProps) => {
|
|
|
118
125
|
<Combobox.Label className="text-sm font-bold text-gray-700">
|
|
119
126
|
Find a product
|
|
120
127
|
</Combobox.Label>
|
|
128
|
+
<style>{productCardComboItemHighlightStyles}</style>
|
|
121
129
|
<Combobox.Control>
|
|
122
130
|
<Combobox.Input
|
|
123
131
|
className="w-full rounded-md border-gray-300 px-3 py-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 md:text-sm"
|
|
@@ -131,7 +139,7 @@ export const ProductCardSetup = (props: ProductCardSetupProps) => {
|
|
|
131
139
|
<Combobox.Item
|
|
132
140
|
key={item.value}
|
|
133
141
|
item={item}
|
|
134
|
-
className="relative cursor-pointer select-none px-4 py-2 text-gray-900
|
|
142
|
+
className="product-card-combo-item relative cursor-pointer select-none px-4 py-2 text-gray-900"
|
|
135
143
|
>
|
|
136
144
|
<Combobox.ItemText>{item.label}</Combobox.ItemText>
|
|
137
145
|
</Combobox.Item>
|
|
@@ -35,6 +35,13 @@ const modes = [
|
|
|
35
35
|
},
|
|
36
36
|
];
|
|
37
37
|
|
|
38
|
+
const productGridComboItemHighlightStyles = `
|
|
39
|
+
.product-grid-combo-item[data-highlighted] {
|
|
40
|
+
background-color: #0891b2;
|
|
41
|
+
color: #fff;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
|
|
38
45
|
export const ProductGridSetup = (props: ProductGridSetupProps) => {
|
|
39
46
|
const { nodeId, params } = props;
|
|
40
47
|
const ctx = getCtx();
|
|
@@ -235,6 +242,7 @@ export const ProductGridSetup = (props: ProductGridSetupProps) => {
|
|
|
235
242
|
<Combobox.Label className="text-sm font-bold text-gray-700">
|
|
236
243
|
Find products to include
|
|
237
244
|
</Combobox.Label>
|
|
245
|
+
<style>{productGridComboItemHighlightStyles}</style>
|
|
238
246
|
<Combobox.Control>
|
|
239
247
|
<Combobox.Input
|
|
240
248
|
className="w-full rounded-md border-gray-300 px-3 py-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 md:text-sm"
|
|
@@ -248,7 +256,7 @@ export const ProductGridSetup = (props: ProductGridSetupProps) => {
|
|
|
248
256
|
<Combobox.Item
|
|
249
257
|
key={item.value}
|
|
250
258
|
item={item}
|
|
251
|
-
className="relative flex cursor-pointer select-none items-center px-4 py-2 text-gray-900
|
|
259
|
+
className="product-grid-combo-item relative flex cursor-pointer select-none items-center px-4 py-2 text-gray-900"
|
|
252
260
|
>
|
|
253
261
|
<Combobox.ItemText>{item.label}</Combobox.ItemText>
|
|
254
262
|
<Combobox.ItemIndicator className="ml-auto">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MouseEvent } from 'react';
|
|
1
2
|
import { getCtx } from '@/stores/nodes';
|
|
2
3
|
import { viewportKeyStore } from '@/stores/storykeep';
|
|
3
4
|
import {
|
|
@@ -15,7 +16,7 @@ export const BgPaneWrapper = (props: NodeProps) => {
|
|
|
15
16
|
|
|
16
17
|
const viewport = viewportKeyStore.get().value;
|
|
17
18
|
|
|
18
|
-
const handleClick = (e:
|
|
19
|
+
const handleClick = (e: MouseEvent) => {
|
|
19
20
|
getCtx(props).setClickedNodeId(props.nodeId, true);
|
|
20
21
|
e.stopPropagation();
|
|
21
22
|
};
|
|
@@ -85,7 +85,7 @@ export const GhostInsertBlock = memo((props: GhostInsertBlockProps) => {
|
|
|
85
85
|
setShowInsertOptions(false);
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
const handleClose = (e:
|
|
88
|
+
const handleClose = (e: MouseEvent) => {
|
|
89
89
|
e.stopPropagation();
|
|
90
90
|
getCtx(props).setPanelMode('', '', '');
|
|
91
91
|
setShowInsertOptions(false);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MouseEvent } from 'react';
|
|
1
2
|
import { useStore } from '@nanostores/react';
|
|
2
3
|
import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
|
3
4
|
import { getCtx } from '@/stores/nodes';
|
|
@@ -20,7 +21,7 @@ const AddElementsPanel = ({
|
|
|
20
21
|
ctx.notifyNode('root');
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
const handleMouseDown = (e:
|
|
24
|
+
const handleMouseDown = (e: MouseEvent, mode: ToolAddMode) => {
|
|
24
25
|
e.preventDefault();
|
|
25
26
|
startToolDrag('insert', mode, e.clientX, e.clientY);
|
|
26
27
|
initToolDragListeners();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { useState, useEffect, type ChangeEvent } from 'react';
|
|
2
2
|
import ExclamationTriangleIcon from '@heroicons/react/24/outline/ExclamationTriangleIcon';
|
|
3
3
|
import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
|
|
4
4
|
import { getCtx } from '@/stores/nodes';
|
|
@@ -42,7 +42,7 @@ const PaneSlugPanel = ({ nodeId, setMode }: PaneSlugPanelProps) => {
|
|
|
42
42
|
//.replace(/^-+|-+$/g, '');
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
const handleSlugChange = (e:
|
|
45
|
+
const handleSlugChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
46
46
|
const newSlug = validateSlug(e.target.value);
|
|
47
47
|
if (newSlug.length <= 75) {
|
|
48
48
|
// Prevent more than 75 chars
|
|
@@ -103,6 +103,19 @@ const AddPaneCodeHookPanel = ({
|
|
|
103
103
|
parentId: '',
|
|
104
104
|
codeHookTarget: selected,
|
|
105
105
|
isContextPane: isContextPane,
|
|
106
|
+
...(selected === 'shopify-product-grid' ||
|
|
107
|
+
selected === 'shopify-service-list'
|
|
108
|
+
? {
|
|
109
|
+
codeHookPayload: {
|
|
110
|
+
options: JSON.stringify({
|
|
111
|
+
category: 'product|service',
|
|
112
|
+
group: '',
|
|
113
|
+
title: '',
|
|
114
|
+
bgColor: '#f9f9f9',
|
|
115
|
+
}),
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
: {}),
|
|
106
119
|
};
|
|
107
120
|
const targetId =
|
|
108
121
|
isStoryFragment || isContextPane
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useState, type ChangeEvent } from 'react';
|
|
2
2
|
|
|
3
3
|
interface AddPaneNewCustomCopyProps {
|
|
4
4
|
value: string;
|
|
@@ -11,7 +11,7 @@ export const AddPaneNewCustomCopy = ({
|
|
|
11
11
|
}: AddPaneNewCustomCopyProps) => {
|
|
12
12
|
const [localValue, setLocalValue] = useState(initialValue);
|
|
13
13
|
|
|
14
|
-
const handleChange = (e:
|
|
14
|
+
const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
|
15
15
|
setLocalValue(e.target.value);
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -302,7 +302,7 @@ const ConfigPanePanel = ({
|
|
|
302
302
|
{/* Right Aligned Tools */}
|
|
303
303
|
<div className="ml-auto flex items-center gap-2 px-2">
|
|
304
304
|
{/* Delete & Reorder Tools */}
|
|
305
|
-
{!isTemplate && !isContextPane &&
|
|
305
|
+
{!isTemplate && !isContextPane && (
|
|
306
306
|
<div className="flex items-center gap-1 border-r border-gray-300 pr-2">
|
|
307
307
|
<button
|
|
308
308
|
onClick={handleMoveUp}
|
|
@@ -71,7 +71,12 @@ const IconSelector = ({
|
|
|
71
71
|
() => createListCollection({ items: filteredIcons }),
|
|
72
72
|
[filteredIcons]
|
|
73
73
|
);
|
|
74
|
-
const iconSelectorStyles =
|
|
74
|
+
const iconSelectorStyles = `
|
|
75
|
+
.icon-item .icon-indicator { display: none; }
|
|
76
|
+
.icon-item[data-state="checked"] .icon-indicator { display: flex; }
|
|
77
|
+
.icon-item[data-highlighted] { background-color: #0891b2; color: #fff; }
|
|
78
|
+
.icon-item[data-highlighted] .icon-indicator { color: #fff; }
|
|
79
|
+
`;
|
|
75
80
|
return (
|
|
76
81
|
<div>
|
|
77
82
|
<style>{iconSelectorStyles}</style>
|
|
@@ -100,12 +105,12 @@ const IconSelector = ({
|
|
|
100
105
|
<Combobox.Item
|
|
101
106
|
key={icon}
|
|
102
107
|
item={icon}
|
|
103
|
-
className="icon-item relative cursor-pointer select-none py-2 pl-10 pr-4 text-gray-900
|
|
108
|
+
className="icon-item relative cursor-pointer select-none py-2 pl-10 pr-4 text-gray-900"
|
|
104
109
|
>
|
|
105
110
|
<Combobox.ItemText>
|
|
106
111
|
<i className={`bi bi-${icon} mr-2 text-lg`}></i> {icon}
|
|
107
112
|
</Combobox.ItemText>
|
|
108
|
-
<Combobox.ItemIndicator className="icon-indicator absolute inset-y-0 left-0 flex items-center pl-3 text-cyan-600
|
|
113
|
+
<Combobox.ItemIndicator className="icon-indicator absolute inset-y-0 left-0 flex items-center pl-3 text-cyan-600">
|
|
109
114
|
<CheckIcon className="h-5 w-5" />
|
|
110
115
|
</Combobox.ItemIndicator>
|
|
111
116
|
</Combobox.Item>
|
|
@@ -40,6 +40,12 @@ const ampmOptions = [
|
|
|
40
40
|
{ value: 'PM', label: 'PM' },
|
|
41
41
|
];
|
|
42
42
|
|
|
43
|
+
const datetimeSelectItemHighlightStyles = `
|
|
44
|
+
.datetime-select-item[data-highlighted] {
|
|
45
|
+
background-color: #eff6ff;
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
|
|
43
49
|
const DateTimeInput = ({
|
|
44
50
|
value,
|
|
45
51
|
onChange,
|
|
@@ -450,6 +456,7 @@ const DateTimeInput = ({
|
|
|
450
456
|
{/* Time Picker Section (only show if withTime is true and not date-only) */}
|
|
451
457
|
{withTime && displayFormat !== 'date' && (
|
|
452
458
|
<div className="space-y-2">
|
|
459
|
+
<style>{datetimeSelectItemHighlightStyles}</style>
|
|
453
460
|
<div className="text-xs font-bold text-gray-600">
|
|
454
461
|
Time (Local Timezone)
|
|
455
462
|
</div>
|
|
@@ -489,7 +496,7 @@ const DateTimeInput = ({
|
|
|
489
496
|
<Select.Item
|
|
490
497
|
key={option.value}
|
|
491
498
|
item={option}
|
|
492
|
-
className="flex cursor-pointer items-center justify-between px-3 py-2 text-sm hover:bg-blue-50
|
|
499
|
+
className="datetime-select-item flex cursor-pointer items-center justify-between px-3 py-2 text-sm hover:bg-blue-50"
|
|
493
500
|
>
|
|
494
501
|
<Select.ItemText>{option.label}</Select.ItemText>
|
|
495
502
|
<Select.ItemIndicator>
|
|
@@ -540,7 +547,7 @@ const DateTimeInput = ({
|
|
|
540
547
|
<Select.Item
|
|
541
548
|
key={option.value}
|
|
542
549
|
item={option}
|
|
543
|
-
className="flex cursor-pointer items-center justify-between px-3 py-2 text-sm hover:bg-blue-50
|
|
550
|
+
className="datetime-select-item flex cursor-pointer items-center justify-between px-3 py-2 text-sm hover:bg-blue-50"
|
|
544
551
|
>
|
|
545
552
|
<Select.ItemText>{option.label}</Select.ItemText>
|
|
546
553
|
<Select.ItemIndicator>
|
|
@@ -589,7 +596,7 @@ const DateTimeInput = ({
|
|
|
589
596
|
<Select.Item
|
|
590
597
|
key={option.value}
|
|
591
598
|
item={option}
|
|
592
|
-
className="flex cursor-pointer items-center justify-between px-3 py-2 text-sm hover:bg-blue-50
|
|
599
|
+
className="datetime-select-item flex cursor-pointer items-center justify-between px-3 py-2 text-sm hover:bg-blue-50"
|
|
593
600
|
>
|
|
594
601
|
<Select.ItemText>{option.label}</Select.ItemText>
|
|
595
602
|
<Select.ItemIndicator>
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useRef,
|
|
3
|
+
useState,
|
|
4
|
+
useId,
|
|
5
|
+
type ChangeEvent,
|
|
6
|
+
type DragEvent,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import { classNames } from '@/utils/helpers';
|
|
3
9
|
import {
|
|
4
10
|
validateFile,
|
|
@@ -151,14 +157,14 @@ const FileUpload = ({
|
|
|
151
157
|
}
|
|
152
158
|
};
|
|
153
159
|
|
|
154
|
-
const handleFileSelect = (e:
|
|
160
|
+
const handleFileSelect = (e: ChangeEvent<HTMLInputElement>) => {
|
|
155
161
|
const file = e.target.files?.[0];
|
|
156
162
|
if (file) {
|
|
157
163
|
processFile(file);
|
|
158
164
|
}
|
|
159
165
|
};
|
|
160
166
|
|
|
161
|
-
const handleDrop = (e:
|
|
167
|
+
const handleDrop = (e: DragEvent<HTMLDivElement>) => {
|
|
162
168
|
e.preventDefault();
|
|
163
169
|
setDragOver(false);
|
|
164
170
|
|
|
@@ -170,14 +176,14 @@ const FileUpload = ({
|
|
|
170
176
|
}
|
|
171
177
|
};
|
|
172
178
|
|
|
173
|
-
const handleDragOver = (e:
|
|
179
|
+
const handleDragOver = (e: DragEvent<HTMLDivElement>) => {
|
|
174
180
|
e.preventDefault();
|
|
175
181
|
if (!disabled) {
|
|
176
182
|
setDragOver(true);
|
|
177
183
|
}
|
|
178
184
|
};
|
|
179
185
|
|
|
180
|
-
const handleDragLeave = (e:
|
|
186
|
+
const handleDragLeave = (e: DragEvent<HTMLDivElement>) => {
|
|
181
187
|
e.preventDefault();
|
|
182
188
|
setDragOver(false);
|
|
183
189
|
};
|