astro-tractstack 2.0.0-rc.9 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +8 -97
- package/README.md +7 -5
- package/bin/create-tractstack.js +31 -8
- package/dist/index.js +106 -29
- package/package.json +10 -5
- package/templates/css/frontend.css +1 -1
- package/templates/custom/minimal/CodeHook.astro +13 -12
- package/templates/custom/minimal/CustomRoutes.astro +25 -31
- package/templates/custom/with-examples/CodeHook.astro +22 -11
- package/templates/custom/with-examples/CustomRoutes.astro +4 -8
- package/templates/custom/with-examples/ProductCard.astro +29 -0
- package/templates/custom/with-examples/ProductCardWrapper.astro +43 -0
- package/templates/custom/with-examples/ProductGrid.astro +64 -0
- package/templates/custom/with-examples/pages/Collections.astro +58 -98
- package/templates/gitignore +42 -0
- package/templates/prettierignore +5 -0
- package/templates/prettierrc +19 -0
- package/templates/src/client/app.js +127 -0
- package/templates/src/client/htmx.min.js +3519 -0
- package/templates/src/client/view.js +429 -0
- package/templates/src/components/Footer.astro +4 -9
- package/templates/src/components/Header.astro +67 -60
- package/templates/src/components/Menu.tsx +188 -52
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +2 -2
- package/templates/src/components/codehooks/EpinetDurationSelector.tsx +9 -13
- package/templates/src/components/codehooks/EpinetTableView.tsx +11 -7
- package/templates/src/components/codehooks/EpinetWrapper.tsx +10 -9
- package/templates/src/components/codehooks/FeaturedArticle.astro +105 -0
- package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +318 -0
- package/templates/src/components/codehooks/ListContent.astro +32 -162
- package/templates/src/components/codehooks/ListContentSetup.tsx +43 -138
- package/templates/src/components/codehooks/ProductCardSetup.tsx +152 -0
- package/templates/src/components/codehooks/ProductGridSetup.tsx +274 -0
- package/templates/src/components/codehooks/SearchWidget.tsx +453 -0
- package/templates/src/components/compositor/Node.tsx +3 -6
- package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +21 -11
- package/templates/src/components/compositor/elements/BunnyVideo.tsx +21 -20
- package/templates/src/components/compositor/nodes/Pane.tsx +51 -21
- package/templates/src/components/compositor/nodes/RenderChildren.tsx +6 -1
- package/templates/src/components/compositor/nodes/Widget.tsx +16 -2
- package/templates/src/components/compositor/preview/FeaturedArticlePreview.tsx +155 -0
- package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +20 -1
- package/templates/src/components/edit/Header.tsx +10 -4
- package/templates/src/components/edit/PanelSwitch.tsx +11 -7
- package/templates/src/components/edit/SettingsPanel.tsx +29 -18
- package/templates/src/components/edit/ToolBar.tsx +1 -28
- package/templates/src/components/edit/ToolMode.tsx +45 -32
- package/templates/src/components/edit/pane/AddPanePanel_break.tsx +12 -2
- package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +8 -2
- package/templates/src/components/edit/pane/AddPanePanel_newAICopy_modal.tsx +1 -1
- package/templates/src/components/edit/pane/ConfigPanePanel.tsx +17 -27
- package/templates/src/components/edit/pane/PageGenSelector.tsx +16 -16
- package/templates/src/components/edit/pane/PageGenSpecial.tsx +26 -49
- package/templates/src/components/edit/pane/PageGen_preview.tsx +17 -2
- package/templates/src/components/edit/pane/PanePanel_path.tsx +2 -4
- package/templates/src/components/edit/pane/PanePanel_title.tsx +243 -76
- package/templates/src/components/edit/panels/StyleBreakPanel.tsx +17 -19
- package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +48 -37
- package/templates/src/components/edit/panels/StyleElementPanel_add.tsx +60 -55
- package/templates/src/components/edit/panels/StyleImagePanel_add.tsx +56 -50
- package/templates/src/components/edit/panels/StyleLiElementPanel_add.tsx +54 -47
- package/templates/src/components/edit/panels/StyleLinkPanel_add.tsx +54 -44
- package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +113 -138
- package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +54 -40
- package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +3 -3
- package/templates/src/components/edit/panels/StyleWidgetPanel_add.tsx +56 -49
- package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +14 -5
- package/templates/src/components/edit/state/SaveModal.tsx +316 -169
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +1 -1
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +56 -55
- package/templates/src/components/edit/widgets/BunnyWidget.tsx +538 -59
- package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +656 -0
- package/templates/src/components/edit/widgets/ToggleWidget.tsx +9 -16
- package/templates/src/components/fields/ArtpackImage.tsx +4 -1
- package/templates/src/components/fields/BackgroundImage.tsx +1 -1
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +127 -35
- package/templates/src/components/fields/ColorPickerCombo.tsx +66 -62
- package/templates/src/components/fields/ImageUpload.tsx +1 -1
- package/templates/src/components/fields/ViewportComboBox.tsx +59 -42
- package/templates/src/components/form/ActionBuilderBeliefSelector.tsx +117 -0
- package/templates/src/components/form/ActionBuilderField.tsx +306 -87
- package/templates/src/components/search/SearchModal.tsx +420 -0
- package/templates/src/components/search/SearchResults.tsx +367 -0
- package/templates/src/components/search/SearchWrapper.tsx +46 -0
- package/templates/src/components/storykeep/Dashboard_Advanced.tsx +1 -1
- package/templates/src/components/storykeep/Dashboard_Analytics.tsx +34 -8
- package/templates/src/components/storykeep/Dashboard_Branding.tsx +1 -1
- package/templates/src/components/storykeep/Dashboard_Content.tsx +6 -0
- package/templates/src/components/storykeep/StoryKeepBackdrop.astro +87 -0
- package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +38 -34
- package/templates/src/components/storykeep/controls/content/KnownResourceForm.tsx +1 -1
- package/templates/src/components/storykeep/controls/content/MenuForm.tsx +56 -8
- package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +18 -3
- package/templates/src/components/storykeep/controls/content/StoryFragmentTable.tsx +5 -8
- package/templates/src/components/storykeep/state/FetchAnalytics.tsx +274 -228
- package/templates/src/components/storykeep/widgets/Wizard.tsx +14 -7
- package/templates/src/components/widgets/ImpressionWrapper.tsx +0 -1
- package/templates/src/constants/shapes.ts +9 -0
- package/templates/src/constants.ts +2121 -16
- package/templates/src/hooks/useSearch.ts +228 -0
- package/templates/src/layouts/Layout.astro +213 -104
- package/templates/src/lib/storyData.ts +4 -1
- package/templates/src/pages/[...slug]/edit.astro +14 -14
- package/templates/src/pages/[...slug].astro +82 -21
- package/templates/src/pages/api/orphan-analysis.ts +0 -1
- package/templates/src/pages/api/tailwind.ts +23 -21
- package/templates/src/pages/context/[...contextSlug]/edit.astro +14 -14
- package/templates/src/pages/context/[...contextSlug].astro +7 -2
- package/templates/src/pages/storykeep/advanced.astro +5 -4
- package/templates/src/pages/storykeep/branding.astro +5 -4
- package/templates/src/pages/storykeep/content.astro +5 -4
- package/templates/src/pages/storykeep/init.astro +40 -1
- package/templates/src/pages/storykeep/login.astro +1 -1
- package/templates/src/pages/storykeep.astro +5 -4
- package/templates/src/stores/nodes.ts +59 -88
- package/templates/src/stores/orphanAnalysis.ts +19 -21
- package/templates/src/stores/storykeep.ts +7 -0
- package/templates/src/types/compositorTypes.ts +6 -0
- package/templates/src/types/tractstack.ts +17 -0
- package/templates/src/utils/actions/lispLexer.ts +2 -2
- package/templates/src/utils/actions/preParse_Action.ts +3 -0
- package/templates/src/utils/api/beliefHelpers.ts +12 -36
- package/templates/src/utils/api/menuHelpers.ts +2 -2
- package/templates/src/utils/api.ts +26 -0
- package/templates/src/utils/compositor/TemplateNodes.ts +7 -0
- package/templates/src/utils/compositor/allowInsert.ts +5 -3
- package/templates/src/utils/compositor/nodesHelper.ts +4 -0
- package/templates/src/utils/compositor/processMarkdown.ts +16 -2
- package/templates/src/utils/compositor/reduceNodesClassNames.ts +4 -0
- package/templates/src/utils/compositor/templateMarkdownStyles.ts +13 -13
- package/templates/src/utils/compositor/typeGuards.ts +1 -0
- package/templates/src/utils/customHelpers.ts +38 -0
- package/templates/src/utils/helpers.ts +2 -2
- package/templates/src/utils/layout.ts +65 -144
- package/utils/inject-files.ts +95 -18
- package/templates/src/client/analytics-events.js +0 -207
- package/templates/src/client/belief-events.js +0 -191
- package/templates/src/client/sse.js +0 -613
- package/templates/src/components/codehooks/FeaturedContent.astro +0 -273
- package/templates/src/components/codehooks/FeaturedContentSetup.tsx +0 -738
- package/templates/src/components/compositor/preview/FeaturedContentPreview.tsx +0 -128
- package/templates/src/components/edit/pane/PanePanel_slug.tsx +0 -219
|
@@ -12,28 +12,27 @@ export default function ToggleWidget({ node, onUpdate }: ToggleWidgetProps) {
|
|
|
12
12
|
const [beliefs, setBeliefs] = useState<BeliefNode[]>([]);
|
|
13
13
|
const [selectedBeliefTag, setSelectedBeliefTag] = useState<string>('');
|
|
14
14
|
const [currentPrompt, setCurrentPrompt] = useState<string>('');
|
|
15
|
+
const [currentScale, setCurrentScale] = useState<string>('');
|
|
15
16
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
16
17
|
|
|
17
|
-
// Get parameter metadata from the widgetMeta constant
|
|
18
18
|
const widgetInfo = widgetMeta.toggle;
|
|
19
19
|
|
|
20
20
|
const params = node.codeHookParams || [];
|
|
21
21
|
const beliefTag = String(params[0] || '');
|
|
22
22
|
const prompt = String(params[1] || '');
|
|
23
|
+
const scale = String(params[2] || '');
|
|
23
24
|
|
|
24
|
-
// Check if beliefTag is the placeholder value
|
|
25
25
|
const isPlaceholder = beliefTag === 'BeliefTag';
|
|
26
26
|
|
|
27
|
-
// Update local state when props change
|
|
28
27
|
useEffect(() => {
|
|
29
28
|
if (!isPlaceholder && beliefTag) {
|
|
30
29
|
setSelectedBeliefTag(beliefTag);
|
|
31
30
|
}
|
|
32
31
|
setCurrentPrompt(prompt);
|
|
32
|
+
setCurrentScale(scale);
|
|
33
33
|
setIsInitialized(true);
|
|
34
|
-
}, [beliefTag, prompt, isPlaceholder]);
|
|
34
|
+
}, [beliefTag, prompt, scale, isPlaceholder]);
|
|
35
35
|
|
|
36
|
-
// Fetch beliefs using new Go backend pattern
|
|
37
36
|
useEffect(() => {
|
|
38
37
|
const fetchData = async () => {
|
|
39
38
|
try {
|
|
@@ -41,7 +40,6 @@ export default function ToggleWidget({ node, onUpdate }: ToggleWidgetProps) {
|
|
|
41
40
|
import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
|
|
42
41
|
const tenantId = import.meta.env.PUBLIC_TENANTID || 'default';
|
|
43
42
|
|
|
44
|
-
// Step 1: Get all belief IDs
|
|
45
43
|
const idsResponse = await fetch(`${goBackend}/api/v1/nodes/beliefs`, {
|
|
46
44
|
headers: {
|
|
47
45
|
'X-Tenant-ID': tenantId,
|
|
@@ -60,7 +58,6 @@ export default function ToggleWidget({ node, onUpdate }: ToggleWidgetProps) {
|
|
|
60
58
|
return;
|
|
61
59
|
}
|
|
62
60
|
|
|
63
|
-
// Step 2: Get belief data by IDs
|
|
64
61
|
const beliefsResponse = await fetch(
|
|
65
62
|
`${goBackend}/api/v1/nodes/beliefs`,
|
|
66
63
|
{
|
|
@@ -92,34 +89,30 @@ export default function ToggleWidget({ node, onUpdate }: ToggleWidgetProps) {
|
|
|
92
89
|
const handleBeliefChange = (selectedValue: string) => {
|
|
93
90
|
if (!isInitialized) return;
|
|
94
91
|
setSelectedBeliefTag(selectedValue);
|
|
95
|
-
|
|
92
|
+
const selectedBelief = beliefs.find((b) => b.slug === selectedValue);
|
|
93
|
+
const newScale = selectedBelief ? selectedBelief.scale || '' : '';
|
|
94
|
+
setCurrentScale(newScale);
|
|
95
|
+
onUpdate([selectedValue, currentPrompt, newScale]);
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
const handlePromptChange = (value: string) => {
|
|
99
99
|
if (!isInitialized) return;
|
|
100
|
-
// Sanitize the input value (remove newlines and pipe characters)
|
|
101
100
|
const sanitizedValue = value.replace(/[\n\r|]/g, '');
|
|
102
101
|
setCurrentPrompt(sanitizedValue);
|
|
103
|
-
|
|
104
|
-
// Use the actual selected tag (from state) or the original belief tag as fallback
|
|
105
102
|
const tagToUse = selectedBeliefTag || (isPlaceholder ? '' : beliefTag);
|
|
106
|
-
onUpdate([tagToUse, sanitizedValue]);
|
|
103
|
+
onUpdate([tagToUse, sanitizedValue, currentScale]);
|
|
107
104
|
};
|
|
108
105
|
|
|
109
|
-
// Show beliefs that can be selected for the toggle
|
|
110
106
|
const filteredBeliefs = beliefs.filter(
|
|
111
107
|
(b) => b.scale === 'yn' || b.scale === 'tf'
|
|
112
108
|
);
|
|
113
109
|
|
|
114
|
-
// Find the selected belief (if any)
|
|
115
110
|
const selectedBelief = beliefs.find(
|
|
116
111
|
(b) => b.slug === (selectedBeliefTag || (isPlaceholder ? '' : beliefTag))
|
|
117
112
|
);
|
|
118
113
|
|
|
119
|
-
// Determine if we have a real selection - either from state or props
|
|
120
114
|
const hasRealSelection = !!selectedBelief || (!isPlaceholder && !!beliefTag);
|
|
121
115
|
|
|
122
|
-
// Calculate the current value to show in the select dropdown
|
|
123
116
|
const selectValue = selectedBeliefTag || (isPlaceholder ? '' : beliefTag);
|
|
124
117
|
|
|
125
118
|
return (
|
|
@@ -351,7 +351,10 @@ const ArtpackImage = ({ paneId, onUpdate }: ArtpackImageProps) => {
|
|
|
351
351
|
className="fixed inset-0 flex items-center justify-center p-4"
|
|
352
352
|
style={{ zIndex: 10010 }}
|
|
353
353
|
>
|
|
354
|
-
<Dialog.Content
|
|
354
|
+
<Dialog.Content
|
|
355
|
+
className="dialog-content overflow-y-auto"
|
|
356
|
+
style={{ maxHeight: '80vh' }}
|
|
357
|
+
>
|
|
355
358
|
<Dialog.Title className="mb-4 text-lg font-bold">
|
|
356
359
|
Select Artpack Image
|
|
357
360
|
</Dialog.Title>
|
|
@@ -504,7 +504,7 @@ const BackgroundImage = ({ paneId, onUpdate }: BackgroundImageProps) => {
|
|
|
504
504
|
/>
|
|
505
505
|
</div>
|
|
506
506
|
<div className="flex-1">
|
|
507
|
-
<div className="font-
|
|
507
|
+
<div className="font-bold">
|
|
508
508
|
{file.altDescription || file.filename}
|
|
509
509
|
</div>
|
|
510
510
|
{file.altDescription && (
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { useState, useCallback } from 'react';
|
|
1
|
+
import { useState, useCallback, useMemo } from 'react';
|
|
2
2
|
import { useStore } from '@nanostores/react';
|
|
3
|
+
import { Select } from '@ark-ui/react/select';
|
|
4
|
+
import { createListCollection } from '@ark-ui/react/collection';
|
|
3
5
|
import BackgroundImage from './BackgroundImage';
|
|
4
6
|
import ArtpackImage from './ArtpackImage';
|
|
5
7
|
import ColorPickerCombo from './ColorPickerCombo';
|
|
6
8
|
import { getCtx } from '@/stores/nodes';
|
|
7
|
-
import { hasArtpacksStore } from '@/stores/storykeep';
|
|
9
|
+
import { hasArtpacksStore, settingsPanelStore } from '@/stores/storykeep';
|
|
8
10
|
import { cloneDeep } from '@/utils/helpers';
|
|
9
11
|
import type { BrandConfig } from '@/types/tractstack';
|
|
10
12
|
import type {
|
|
@@ -19,6 +21,36 @@ export interface BackgroundImageWrapperProps {
|
|
|
19
21
|
config?: BrandConfig;
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
const CheckIcon = () => (
|
|
25
|
+
<svg
|
|
26
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
27
|
+
className="h-5 w-5"
|
|
28
|
+
viewBox="0 0 20 20"
|
|
29
|
+
fill="currentColor"
|
|
30
|
+
>
|
|
31
|
+
<path
|
|
32
|
+
fillRule="evenodd"
|
|
33
|
+
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
|
34
|
+
clipRule="evenodd"
|
|
35
|
+
/>
|
|
36
|
+
</svg>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const ChevronDownIcon = () => (
|
|
40
|
+
<svg
|
|
41
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
42
|
+
className="h-5 w-5"
|
|
43
|
+
viewBox="0 0 20 20"
|
|
44
|
+
fill="currentColor"
|
|
45
|
+
>
|
|
46
|
+
<path
|
|
47
|
+
fillRule="evenodd"
|
|
48
|
+
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
49
|
+
clipRule="evenodd"
|
|
50
|
+
/>
|
|
51
|
+
</svg>
|
|
52
|
+
);
|
|
53
|
+
|
|
22
54
|
const BackgroundImageWrapper = ({
|
|
23
55
|
paneId,
|
|
24
56
|
config,
|
|
@@ -27,11 +59,8 @@ const BackgroundImageWrapper = ({
|
|
|
27
59
|
const allNodes = useStore(ctx.allNodes);
|
|
28
60
|
const $artpacks = useStore(hasArtpacksStore);
|
|
29
61
|
const hasArtpacks = $artpacks && Object.keys($artpacks).length > 0;
|
|
30
|
-
|
|
31
|
-
// State to force re-renders when child components need it
|
|
32
62
|
const [, setUpdateCounter] = useState(0);
|
|
33
63
|
|
|
34
|
-
// Using useCallback to create a stable reference to the update function
|
|
35
64
|
const onUpdate = useCallback(() => {
|
|
36
65
|
setUpdateCounter((prev) => prev + 1);
|
|
37
66
|
}, []);
|
|
@@ -89,8 +118,47 @@ const BackgroundImageWrapper = ({
|
|
|
89
118
|
const position = bgNode?.position || 'background';
|
|
90
119
|
const size = bgNode?.size || 'equal';
|
|
91
120
|
|
|
121
|
+
const positionOptions = [
|
|
122
|
+
{ label: 'Background', value: 'background' },
|
|
123
|
+
{ label: 'Left', value: 'left' },
|
|
124
|
+
{ label: 'Right', value: 'right' },
|
|
125
|
+
{ label: 'Left Bleed', value: 'leftBleed' },
|
|
126
|
+
{ label: 'Right Bleed', value: 'rightBleed' },
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
const collection = useMemo(
|
|
130
|
+
() =>
|
|
131
|
+
createListCollection({
|
|
132
|
+
items: positionOptions,
|
|
133
|
+
itemToValue: (item) => item.value,
|
|
134
|
+
itemToString: (item) => item.label,
|
|
135
|
+
}),
|
|
136
|
+
[]
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const selectItemStyles = `
|
|
140
|
+
.position-item[data-highlighted] {
|
|
141
|
+
background-color: #0891b2; /* bg-cyan-600 */
|
|
142
|
+
color: white;
|
|
143
|
+
}
|
|
144
|
+
.position-item[data-highlighted] .position-indicator {
|
|
145
|
+
color: white;
|
|
146
|
+
}
|
|
147
|
+
.position-item[data-state="checked"] .position-indicator {
|
|
148
|
+
display: flex;
|
|
149
|
+
}
|
|
150
|
+
.position-item .position-indicator {
|
|
151
|
+
display: none;
|
|
152
|
+
}
|
|
153
|
+
.position-item[data-state="checked"] {
|
|
154
|
+
font-weight: bold;
|
|
155
|
+
}
|
|
156
|
+
`;
|
|
157
|
+
|
|
92
158
|
return (
|
|
93
159
|
<div className="w-full space-y-6">
|
|
160
|
+
<style>{selectItemStyles}</style>
|
|
161
|
+
|
|
94
162
|
<h3 className="text-sm font-bold text-gray-700">Background</h3>
|
|
95
163
|
|
|
96
164
|
<ColorPickerCombo
|
|
@@ -115,39 +183,64 @@ const BackgroundImageWrapper = ({
|
|
|
115
183
|
)}
|
|
116
184
|
{bgNode && (
|
|
117
185
|
<div className="w-full space-y-6">
|
|
118
|
-
{/* Position Toggle */}
|
|
119
186
|
<div className="space-y-2">
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
{(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
187
|
+
<Select.Root
|
|
188
|
+
collection={collection}
|
|
189
|
+
positioning={{ sameWidth: true }}
|
|
190
|
+
value={[position]}
|
|
191
|
+
onValueChange={(details) => {
|
|
192
|
+
const currentSignal = settingsPanelStore.get();
|
|
193
|
+
if (currentSignal) {
|
|
194
|
+
settingsPanelStore.set({
|
|
195
|
+
...currentSignal,
|
|
196
|
+
editLock: Date.now(),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
handlePositionChange(
|
|
200
|
+
details.value[0] as
|
|
201
|
+
| 'background'
|
|
202
|
+
| 'left'
|
|
203
|
+
| 'right'
|
|
204
|
+
| 'leftBleed'
|
|
205
|
+
| 'rightBleed'
|
|
206
|
+
);
|
|
207
|
+
}}
|
|
208
|
+
>
|
|
209
|
+
<Select.Label className="block text-sm font-bold text-gray-700">
|
|
210
|
+
Position
|
|
211
|
+
</Select.Label>
|
|
212
|
+
<Select.Control>
|
|
213
|
+
<Select.Trigger className="focus:border-myblue focus:ring-myblue flex w-full items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-1">
|
|
214
|
+
<Select.ValueText
|
|
215
|
+
className="capitalize"
|
|
216
|
+
placeholder="Select a position"
|
|
141
217
|
/>
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
</
|
|
145
|
-
</
|
|
146
|
-
|
|
147
|
-
|
|
218
|
+
<Select.Indicator>
|
|
219
|
+
<ChevronDownIcon />
|
|
220
|
+
</Select.Indicator>
|
|
221
|
+
</Select.Trigger>
|
|
222
|
+
</Select.Control>
|
|
223
|
+
<Select.Positioner>
|
|
224
|
+
<Select.Content className="z-10 mt-1 w-full rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
|
225
|
+
<Select.ItemGroup>
|
|
226
|
+
{collection.items.map((item) => (
|
|
227
|
+
<Select.Item
|
|
228
|
+
key={item.value}
|
|
229
|
+
item={item}
|
|
230
|
+
className="position-item relative cursor-pointer select-none py-2 pl-10 pr-4 text-sm text-gray-900"
|
|
231
|
+
>
|
|
232
|
+
<Select.ItemText>{item.label}</Select.ItemText>
|
|
233
|
+
<Select.ItemIndicator className="position-indicator absolute inset-y-0 left-0 flex items-center pl-3 text-cyan-600">
|
|
234
|
+
<CheckIcon />
|
|
235
|
+
</Select.ItemIndicator>
|
|
236
|
+
</Select.Item>
|
|
237
|
+
))}
|
|
238
|
+
</Select.ItemGroup>
|
|
239
|
+
</Select.Content>
|
|
240
|
+
</Select.Positioner>
|
|
241
|
+
</Select.Root>
|
|
148
242
|
</div>
|
|
149
243
|
|
|
150
|
-
{/* Size Toggle - Only show when position is left or right */}
|
|
151
244
|
{position !== 'background' && (
|
|
152
245
|
<div className="space-y-2">
|
|
153
246
|
<label className="block text-sm font-bold text-gray-700">
|
|
@@ -177,7 +270,6 @@ const BackgroundImageWrapper = ({
|
|
|
177
270
|
</div>
|
|
178
271
|
)}
|
|
179
272
|
|
|
180
|
-
{/* Render the appropriate image component */}
|
|
181
273
|
{isArtpackImageNode(bgNode) ? (
|
|
182
274
|
<ArtpackImage paneId={paneId} onUpdate={onUpdate} />
|
|
183
275
|
) : (
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState, useCallback, useMemo, useEffect, useRef } from 'react';
|
|
2
2
|
import { Combobox } from '@ark-ui/react';
|
|
3
|
+
import { Portal } from '@ark-ui/react/portal';
|
|
3
4
|
import { createListCollection } from '@ark-ui/react/collection';
|
|
4
5
|
import ChevronUpDownIcon from '@heroicons/react/24/outline/ChevronUpDownIcon';
|
|
5
6
|
import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
|
@@ -42,7 +43,7 @@ const ColorPickerCombo = ({
|
|
|
42
43
|
|
|
43
44
|
// Add ref and useDropdownDirection hook
|
|
44
45
|
const comboboxRef = useRef<HTMLDivElement>(null);
|
|
45
|
-
const { openAbove
|
|
46
|
+
const { openAbove } = useDropdownDirection(comboboxRef);
|
|
46
47
|
|
|
47
48
|
// Get all available Tailwind color options
|
|
48
49
|
const allTailwindColorOptions = useMemo(() => {
|
|
@@ -59,19 +60,10 @@ const ColorPickerCombo = ({
|
|
|
59
60
|
}, [allTailwindColorOptions, query]);
|
|
60
61
|
|
|
61
62
|
// Create collection for combobox
|
|
62
|
-
const collection = useMemo(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// Ensure the initial color is in the collection if it exists
|
|
67
|
-
if (initialTailwindColor && !items.includes(initialTailwindColor)) {
|
|
68
|
-
items.push(initialTailwindColor);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return createListCollection({
|
|
72
|
-
items,
|
|
73
|
-
});
|
|
74
|
-
}, [allTailwindColorOptions, initialTailwindColor]);
|
|
63
|
+
const collection = useMemo(
|
|
64
|
+
() => createListCollection({ items: filteredColors }),
|
|
65
|
+
[filteredColors]
|
|
66
|
+
);
|
|
75
67
|
|
|
76
68
|
// Set default value during initial render
|
|
77
69
|
useEffect(() => {
|
|
@@ -223,56 +215,68 @@ const ColorPickerCombo = ({
|
|
|
223
215
|
onValueChange={handleTailwindColorChange}
|
|
224
216
|
onInputValueChange={handleInputChange}
|
|
225
217
|
selectionBehavior="replace"
|
|
218
|
+
loopFocus={true}
|
|
219
|
+
openOnKeyPress={true}
|
|
220
|
+
positioning={{
|
|
221
|
+
placement: openAbove ? 'top' : 'bottom',
|
|
222
|
+
gutter: 4,
|
|
223
|
+
sameWidth: true,
|
|
224
|
+
}}
|
|
226
225
|
>
|
|
227
|
-
<
|
|
228
|
-
<
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
<Combobox.Trigger className="absolute inset-y-0 right-0 flex items-center pr-2">
|
|
234
|
-
<ChevronUpDownIcon
|
|
235
|
-
className="text-mydarkgrey h-5 w-5"
|
|
236
|
-
aria-hidden="true"
|
|
226
|
+
<Combobox.Control ref={comboboxRef}>
|
|
227
|
+
<div className="relative">
|
|
228
|
+
<Combobox.Input
|
|
229
|
+
className="border-mydarkgrey focus:border-myblue focus:ring-myblue xs:text-sm w-full max-w-xl rounded-md py-2 pl-3 pr-10 shadow-sm"
|
|
230
|
+
placeholder="Search Tailwind colors..."
|
|
231
|
+
autoComplete="off"
|
|
237
232
|
/>
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
>
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
filteredColors.
|
|
251
|
-
<
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
<
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
233
|
+
<Combobox.Trigger className="absolute inset-y-0 right-0 flex items-center pr-2">
|
|
234
|
+
<ChevronUpDownIcon
|
|
235
|
+
className="text-mydarkgrey h-5 w-5"
|
|
236
|
+
aria-hidden="true"
|
|
237
|
+
/>
|
|
238
|
+
</Combobox.Trigger>
|
|
239
|
+
</div>
|
|
240
|
+
</Combobox.Control>
|
|
241
|
+
|
|
242
|
+
<Portal>
|
|
243
|
+
<Combobox.Positioner style={{ zIndex: 1002 }}>
|
|
244
|
+
<Combobox.Content className="xs:text-sm max-h-64 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
|
245
|
+
{filteredColors.length === 0 ? (
|
|
246
|
+
<div className="relative cursor-default select-none py-2 pl-3 pr-4 text-black">
|
|
247
|
+
Nothing found.
|
|
248
|
+
</div>
|
|
249
|
+
) : (
|
|
250
|
+
filteredColors.map((color) => (
|
|
251
|
+
<Combobox.Item
|
|
252
|
+
key={color}
|
|
253
|
+
item={color}
|
|
254
|
+
className="color-item relative cursor-default select-none py-2 pl-3 pr-4"
|
|
255
|
+
>
|
|
256
|
+
<div className="flex items-center">
|
|
257
|
+
<div
|
|
258
|
+
className="mr-3 h-6 w-6 flex-shrink-0 rounded"
|
|
259
|
+
style={{
|
|
260
|
+
backgroundColor: tailwindToHex(
|
|
261
|
+
`bg-${color}`,
|
|
262
|
+
config.BRAND_COLOURS || null
|
|
263
|
+
),
|
|
264
|
+
}}
|
|
265
|
+
/>
|
|
266
|
+
<span className="block truncate">{color}</span>
|
|
267
|
+
<span className="color-indicator absolute inset-y-0 right-0 flex items-center pr-3 text-cyan-600">
|
|
268
|
+
<CheckIcon
|
|
269
|
+
className="h-5 w-5"
|
|
270
|
+
aria-hidden="true"
|
|
271
|
+
/>
|
|
272
|
+
</span>
|
|
273
|
+
</div>
|
|
274
|
+
</Combobox.Item>
|
|
275
|
+
))
|
|
276
|
+
)}
|
|
277
|
+
</Combobox.Content>
|
|
278
|
+
</Combobox.Positioner>
|
|
279
|
+
</Portal>
|
|
276
280
|
</Combobox.Root>
|
|
277
281
|
</div>
|
|
278
282
|
)}
|
|
@@ -323,7 +323,7 @@ export const ImageUpload = ({
|
|
|
323
323
|
{isSelectingFile && (
|
|
324
324
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
|
|
325
325
|
<div className="w-full max-w-md rounded-lg bg-white p-6 shadow-lg">
|
|
326
|
-
<h3 className="text-mydarkgrey mb-4 text-lg font-
|
|
326
|
+
<h3 className="text-mydarkgrey mb-4 text-lg font-bold">
|
|
327
327
|
Select an Image
|
|
328
328
|
</h3>
|
|
329
329
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
useRef,
|
|
3
2
|
useState,
|
|
4
3
|
useEffect,
|
|
5
4
|
useCallback,
|
|
6
5
|
useMemo,
|
|
7
6
|
type ChangeEvent,
|
|
8
7
|
} from 'react';
|
|
9
|
-
import { Combobox } from '@ark-ui/react';
|
|
8
|
+
import { Combobox, Portal } from '@ark-ui/react';
|
|
10
9
|
import { createListCollection } from '@ark-ui/react/collection';
|
|
11
10
|
import ChevronUpDownIcon from '@heroicons/react/20/solid/ChevronUpDownIcon';
|
|
12
11
|
import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
|
|
@@ -14,6 +13,7 @@ import DevicePhoneMobileIcon from '@heroicons/react/24/outline/DevicePhoneMobile
|
|
|
14
13
|
import DeviceTabletIcon from '@heroicons/react/24/outline/DeviceTabletIcon';
|
|
15
14
|
import ComputerDesktopIcon from '@heroicons/react/24/outline/ComputerDesktopIcon';
|
|
16
15
|
import { classNames } from '@/utils/helpers';
|
|
16
|
+
import { settingsPanelStore } from '@/stores/storykeep';
|
|
17
17
|
import { tailwindToHex, colorValues } from '@/utils/compositor/tailwindColors';
|
|
18
18
|
import type { BrandConfig } from '@/types/tractstack';
|
|
19
19
|
|
|
@@ -45,7 +45,6 @@ const ViewportComboBox = ({
|
|
|
45
45
|
const [internalValue, setInternalValue] = useState(value);
|
|
46
46
|
const [query, setQuery] = useState('');
|
|
47
47
|
const [isNowNegative, setIsNowNegative] = useState(isNegative);
|
|
48
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
49
48
|
|
|
50
49
|
const Icon =
|
|
51
50
|
viewport === 'mobile'
|
|
@@ -100,6 +99,13 @@ const ViewportComboBox = ({
|
|
|
100
99
|
const selectedValue = details.value[0] || '';
|
|
101
100
|
setInternalValue(selectedValue);
|
|
102
101
|
setQuery('');
|
|
102
|
+
const currentSignal = settingsPanelStore.get();
|
|
103
|
+
if (currentSignal) {
|
|
104
|
+
settingsPanelStore.set({
|
|
105
|
+
...currentSignal,
|
|
106
|
+
editLock: Date.now(),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
103
109
|
onFinalChange(selectedValue, viewport, isNowNegative);
|
|
104
110
|
},
|
|
105
111
|
[onFinalChange, viewport, isNowNegative]
|
|
@@ -154,8 +160,13 @@ const ViewportComboBox = ({
|
|
|
154
160
|
loopFocus={true}
|
|
155
161
|
openOnKeyPress={true}
|
|
156
162
|
composite={true}
|
|
163
|
+
positioning={{
|
|
164
|
+
placement: 'bottom',
|
|
165
|
+
gutter: 4,
|
|
166
|
+
sameWidth: true,
|
|
167
|
+
}}
|
|
157
168
|
>
|
|
158
|
-
<
|
|
169
|
+
<Combobox.Control>
|
|
159
170
|
<div className="relative flex items-center">
|
|
160
171
|
{isColorValue && (
|
|
161
172
|
<div
|
|
@@ -169,7 +180,6 @@ const ViewportComboBox = ({
|
|
|
169
180
|
/>
|
|
170
181
|
)}
|
|
171
182
|
<Combobox.Input
|
|
172
|
-
ref={inputRef}
|
|
173
183
|
className={classNames(
|
|
174
184
|
'border-mydarkgrey w-full rounded-md border py-2 text-xl leading-5 focus:border-cyan-600 focus:ring-1 focus:ring-cyan-600',
|
|
175
185
|
isInferred ? 'text-black/20' : 'text-black',
|
|
@@ -186,44 +196,51 @@ const ViewportComboBox = ({
|
|
|
186
196
|
/>
|
|
187
197
|
</Combobox.Trigger>
|
|
188
198
|
</div>
|
|
189
|
-
</
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
collection.items.map((item) => (
|
|
197
|
-
<Combobox.Item
|
|
198
|
-
key={item}
|
|
199
|
-
item={item}
|
|
200
|
-
className="viewport-item relative cursor-default select-none py-2"
|
|
201
|
-
>
|
|
202
|
-
<div className="flex items-center">
|
|
203
|
-
{colorValues.includes(item) && (
|
|
204
|
-
<div
|
|
205
|
-
className="absolute left-3 top-1/2 h-6 w-6 -translate-y-1/2 rounded border border-black/10 shadow-sm"
|
|
206
|
-
style={{
|
|
207
|
-
backgroundColor: tailwindToHex(
|
|
208
|
-
item,
|
|
209
|
-
config.BRAND_COLOURS || null
|
|
210
|
-
),
|
|
211
|
-
}}
|
|
212
|
-
/>
|
|
213
|
-
)}
|
|
214
|
-
<span
|
|
215
|
-
className={`block truncate ${colorValues.includes(item) ? 'pl-12' : 'pl-6'} pr-9`}
|
|
216
|
-
>
|
|
217
|
-
{item}
|
|
218
|
-
</span>
|
|
219
|
-
<span className="viewport-indicator absolute inset-y-0 right-0 flex items-center pr-4 text-cyan-600">
|
|
220
|
-
<CheckIcon className="h-5 w-5" aria-hidden="true" />
|
|
221
|
-
</span>
|
|
199
|
+
</Combobox.Control>
|
|
200
|
+
<Portal>
|
|
201
|
+
<Combobox.Positioner style={{ zIndex: 1002 }}>
|
|
202
|
+
<Combobox.Content className="max-h-64 w-full overflow-auto rounded-md bg-white py-1 text-xl shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
|
203
|
+
{collection.items.length === 0 ? (
|
|
204
|
+
<div className="text-mydarkgrey relative cursor-default select-none px-4 py-2">
|
|
205
|
+
Nothing found.
|
|
222
206
|
</div>
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
207
|
+
) : (
|
|
208
|
+
collection.items.map((item) => (
|
|
209
|
+
<Combobox.Item
|
|
210
|
+
key={item}
|
|
211
|
+
item={item}
|
|
212
|
+
className="viewport-item relative cursor-default select-none py-2"
|
|
213
|
+
>
|
|
214
|
+
<div className="flex items-center">
|
|
215
|
+
{colorValues.includes(item) && (
|
|
216
|
+
<div
|
|
217
|
+
className="absolute left-3 top-1/2 h-6 w-6 -translate-y-1/2 rounded border border-black/10 shadow-sm"
|
|
218
|
+
style={{
|
|
219
|
+
backgroundColor: tailwindToHex(
|
|
220
|
+
item,
|
|
221
|
+
config.BRAND_COLOURS || null
|
|
222
|
+
),
|
|
223
|
+
}}
|
|
224
|
+
/>
|
|
225
|
+
)}
|
|
226
|
+
<span
|
|
227
|
+
className={`block truncate ${colorValues.includes(item) ? 'pl-12' : 'pl-6'} pr-9`}
|
|
228
|
+
>
|
|
229
|
+
{item}
|
|
230
|
+
</span>
|
|
231
|
+
<span className="viewport-indicator absolute inset-y-0 right-0 flex items-center pr-4 text-cyan-600">
|
|
232
|
+
<CheckIcon
|
|
233
|
+
className="h-5 w-5"
|
|
234
|
+
aria-hidden="true"
|
|
235
|
+
/>
|
|
236
|
+
</span>
|
|
237
|
+
</div>
|
|
238
|
+
</Combobox.Item>
|
|
239
|
+
))
|
|
240
|
+
)}
|
|
241
|
+
</Combobox.Content>
|
|
242
|
+
</Combobox.Positioner>
|
|
243
|
+
</Portal>
|
|
227
244
|
</Combobox.Root>
|
|
228
245
|
</div>
|
|
229
246
|
{allowNegative && (
|