astro-tractstack 2.0.0-rc.32 → 2.0.0-rc.33
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 +6 -0
- package/package.json +1 -1
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +127 -35
- package/templates/src/components/form/ActionBuilderField.tsx +3 -1
- package/templates/src/components/storykeep/StoryKeepBackdrop.astro +86 -0
- package/templates/src/pages/storykeep/advanced.astro +2 -0
- package/templates/src/pages/storykeep/branding.astro +2 -0
- package/templates/src/pages/storykeep/content.astro +2 -0
- package/templates/src/pages/storykeep.astro +3 -1
- package/templates/src/stores/nodes.ts +12 -0
- package/utils/inject-files.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -1028,6 +1028,12 @@ async function w(t, e, c) {
|
|
|
1028
1028
|
dest: "src/components/form/advanced/APIConfigSection.tsx"
|
|
1029
1029
|
},
|
|
1030
1030
|
// StoryKeep Dashboard Components
|
|
1031
|
+
{
|
|
1032
|
+
src: t(
|
|
1033
|
+
"../templates/src/components/storykeep/StoryKeepBackdrop.astro"
|
|
1034
|
+
),
|
|
1035
|
+
dest: "src/components/storykeep/StoryKeepBackdrop.astro"
|
|
1036
|
+
},
|
|
1031
1037
|
{
|
|
1032
1038
|
src: t("../templates/src/components/storykeep/Dashboard.tsx"),
|
|
1033
1039
|
dest: "src/components/storykeep/Dashboard.tsx"
|
package/package.json
CHANGED
|
@@ -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
|
) : (
|
|
@@ -202,7 +202,9 @@ export default function ActionBuilderField({
|
|
|
202
202
|
onChange={(e) => {
|
|
203
203
|
const newValue = e.target.value;
|
|
204
204
|
setParam1(newValue);
|
|
205
|
-
|
|
205
|
+
}}
|
|
206
|
+
onBlur={(e) => {
|
|
207
|
+
updateValue(selectedTarget, '', e.target.value);
|
|
206
208
|
}}
|
|
207
209
|
placeholder="https://..."
|
|
208
210
|
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-cyan-700 focus:ring-cyan-700"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
let MODE = 'logo'; // 'wordmark' | 'logo'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
brandConfig: {
|
|
6
|
+
LOGO?: string;
|
|
7
|
+
WORDMARK?: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { brandConfig } = Astro.props;
|
|
12
|
+
|
|
13
|
+
const getAssetPath = (
|
|
14
|
+
configPath: string | undefined,
|
|
15
|
+
fallback: string
|
|
16
|
+
): string => {
|
|
17
|
+
if (configPath && configPath !== '') {
|
|
18
|
+
return configPath;
|
|
19
|
+
}
|
|
20
|
+
return fallback;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let assetUrl;
|
|
24
|
+
if (MODE === `wordmark`)
|
|
25
|
+
assetUrl = getAssetPath(brandConfig?.WORDMARK, '/brand/wordmark.svg');
|
|
26
|
+
else assetUrl = getAssetPath(brandConfig?.LOGO, '/brand/logo.svg');
|
|
27
|
+
|
|
28
|
+
// Generate positions programmatically for triple density
|
|
29
|
+
const generatePositions = () => {
|
|
30
|
+
const positions = [];
|
|
31
|
+
const rows = 15; // More rows to extend beyond boundaries
|
|
32
|
+
const cols = 12; // More cols to extend beyond boundaries
|
|
33
|
+
|
|
34
|
+
for (let row = 0; row < rows; row++) {
|
|
35
|
+
for (let col = 0; col < cols; col++) {
|
|
36
|
+
// Skip some positions for natural spacing
|
|
37
|
+
if ((row + col) % 3 !== 0) continue;
|
|
38
|
+
|
|
39
|
+
// Allow logos to extend beyond container edges (no margins)
|
|
40
|
+
const top = (row / (rows - 1)) * 120 - 10; // Extend 10% beyond top/bottom
|
|
41
|
+
const left = (col / (cols - 1)) * 120 - 10; // Extend 10% beyond left/right
|
|
42
|
+
const rotation = -45 + Math.random() * 90;
|
|
43
|
+
|
|
44
|
+
positions.push({
|
|
45
|
+
top: `${top}%`,
|
|
46
|
+
left: `${left}%`,
|
|
47
|
+
rotation: `${rotation}deg`,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return positions;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const logoPositions = generatePositions();
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
assetUrl && (
|
|
60
|
+
<div
|
|
61
|
+
class="pointer-events-none absolute overflow-hidden rounded-2xl p-1.5 md:p-3.5"
|
|
62
|
+
style={{
|
|
63
|
+
top: '2rem',
|
|
64
|
+
left: '64rem',
|
|
65
|
+
right: '0',
|
|
66
|
+
bottom: '3.5rem',
|
|
67
|
+
opacity: '0.85',
|
|
68
|
+
//filter: 'grayscale(1)',
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{logoPositions.map((position) => (
|
|
72
|
+
<img
|
|
73
|
+
src={assetUrl}
|
|
74
|
+
style={{
|
|
75
|
+
position: 'absolute',
|
|
76
|
+
top: position.top,
|
|
77
|
+
left: position.left,
|
|
78
|
+
width: '120px',
|
|
79
|
+
height: 'auto',
|
|
80
|
+
transform: `rotate(${position.rotation})`,
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
))}
|
|
84
|
+
</div>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Layout from '@/layouts/Layout.astro';
|
|
3
|
+
import StoryKeepBackdrop from '@/components/storykeep/StoryKeepBackdrop.astro';
|
|
3
4
|
import StoryKeepDashboard from '@/components/storykeep/Dashboard';
|
|
4
5
|
import StoryKeepDashboard_Advanced from '@/components/storykeep/Dashboard_Advanced';
|
|
5
6
|
import { requireAdminOrEditor, isAuthenticated, isAdmin } from '@/utils/auth';
|
|
@@ -53,6 +54,7 @@ try {
|
|
|
53
54
|
|
|
54
55
|
<Layout title={title} slug="storykeep" isStoryKeep={true}>
|
|
55
56
|
<main id="main-content" class="min-h-screen w-full">
|
|
57
|
+
<StoryKeepBackdrop brandConfig={brandConfig} />
|
|
56
58
|
<div class="max-w-5xl p-3.5 md:p-8">
|
|
57
59
|
<StoryKeepDashboard
|
|
58
60
|
client:only="react"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Layout from '@/layouts/Layout.astro';
|
|
3
|
+
import StoryKeepBackdrop from '@/components/storykeep/StoryKeepBackdrop.astro';
|
|
3
4
|
import BrandingPageWrapper from '@/components/storykeep/state/BrandingWrapper';
|
|
4
5
|
import { requireAdminOrEditor, isAuthenticated, isAdmin } from '@/utils/auth';
|
|
5
6
|
import { getFullContentMap } from '@/stores/analytics';
|
|
@@ -42,6 +43,7 @@ try {
|
|
|
42
43
|
|
|
43
44
|
<Layout title={title} slug="storykeep" isStoryKeep={true}>
|
|
44
45
|
<main id="main-content" class="min-h-screen w-full">
|
|
46
|
+
<StoryKeepBackdrop brandConfig={brandConfig} />
|
|
45
47
|
<div class="max-w-5xl p-3.5 md:p-8">
|
|
46
48
|
<BrandingPageWrapper
|
|
47
49
|
client:only="react"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Layout from '@/layouts/Layout.astro';
|
|
3
|
+
import StoryKeepBackdrop from '@/components/storykeep/StoryKeepBackdrop.astro';
|
|
3
4
|
import StoryKeepDashboard from '@/components/storykeep/Dashboard';
|
|
4
5
|
import StoryKeepDashboard_Content from '@/components/storykeep/Dashboard_Content';
|
|
5
6
|
import { requireAdminOrEditor, isAuthenticated, isAdmin } from '@/utils/auth';
|
|
@@ -49,6 +50,7 @@ try {
|
|
|
49
50
|
|
|
50
51
|
<Layout title={title} slug="storykeep" isStoryKeep={true}>
|
|
51
52
|
<main id="main-content" class="min-h-screen w-full">
|
|
53
|
+
<StoryKeepBackdrop brandConfig={brandConfig} />
|
|
52
54
|
<div class="max-w-5xl p-3.5 md:p-8">
|
|
53
55
|
<StoryKeepDashboard
|
|
54
56
|
client:only="react"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Layout from '@/layouts/Layout.astro';
|
|
3
|
+
import StoryKeepBackdrop from '@/components/storykeep/StoryKeepBackdrop.astro';
|
|
3
4
|
import StoryKeepDashboard from '@/components/storykeep/Dashboard';
|
|
4
5
|
import StoryKeepDashboard_Analytics from '@/components/storykeep/Dashboard_Analytics';
|
|
5
6
|
import { requireAdminOrEditor, isAuthenticated, isAdmin } from '@/utils/auth';
|
|
@@ -50,7 +51,8 @@ try {
|
|
|
50
51
|
---
|
|
51
52
|
|
|
52
53
|
<Layout title={title} isStoryKeep={true} slug="storykeep">
|
|
53
|
-
<main id="main-content" class="min-h-screen w-full">
|
|
54
|
+
<main id="main-content" class="relative min-h-screen w-full">
|
|
55
|
+
<StoryKeepBackdrop brandConfig={brandConfig} />
|
|
54
56
|
<div class="max-w-5xl p-3.5 md:p-8">
|
|
55
57
|
<StoryKeepDashboard
|
|
56
58
|
client:only="react"
|
|
@@ -340,6 +340,18 @@ export class NodesContext {
|
|
|
340
340
|
handleClickEventDefault(node, dblClick, this.clickedParentLayer.get());
|
|
341
341
|
break;
|
|
342
342
|
case `text`:
|
|
343
|
+
if (
|
|
344
|
+
node.nodeType === 'TagElement' &&
|
|
345
|
+
'tagName' in node &&
|
|
346
|
+
(node.tagName === 'a' || node.tagName === 'button')
|
|
347
|
+
) {
|
|
348
|
+
this.toolModeValStore.set({ value: 'styles' });
|
|
349
|
+
handleClickEventDefault(
|
|
350
|
+
node,
|
|
351
|
+
dblClick,
|
|
352
|
+
this.clickedParentLayer.get()
|
|
353
|
+
);
|
|
354
|
+
}
|
|
343
355
|
if (dblClick && ![`Markdown`].includes(node.nodeType)) {
|
|
344
356
|
this.toolModeValStore.set({ value: 'styles' });
|
|
345
357
|
handleClickEventDefault(
|
package/utils/inject-files.ts
CHANGED
|
@@ -1046,6 +1046,12 @@ export async function injectTemplateFiles(
|
|
|
1046
1046
|
},
|
|
1047
1047
|
|
|
1048
1048
|
// StoryKeep Dashboard Components
|
|
1049
|
+
{
|
|
1050
|
+
src: resolve(
|
|
1051
|
+
'../templates/src/components/storykeep/StoryKeepBackdrop.astro'
|
|
1052
|
+
),
|
|
1053
|
+
dest: 'src/components/storykeep/StoryKeepBackdrop.astro',
|
|
1054
|
+
},
|
|
1049
1055
|
{
|
|
1050
1056
|
src: resolve('../templates/src/components/storykeep/Dashboard.tsx'),
|
|
1051
1057
|
dest: 'src/components/storykeep/Dashboard.tsx',
|