astro-tractstack 2.0.0-rc.9 → 2.0.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.
- 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 +1 -0
- 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
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { FullContentMapItem } from '@/types/tractstack';
|
|
3
|
-
|
|
4
|
-
export interface Props {
|
|
5
|
-
options?: {
|
|
6
|
-
params?: {
|
|
7
|
-
options?: string;
|
|
8
|
-
};
|
|
9
|
-
};
|
|
10
|
-
contentMap: FullContentMapItem[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const { options, contentMap } = Astro.props;
|
|
14
|
-
|
|
15
|
-
// Parse component options
|
|
16
|
-
let parsedOptions;
|
|
17
|
-
try {
|
|
18
|
-
parsedOptions = JSON.parse(options?.params?.options || '{}');
|
|
19
|
-
} catch (e) {
|
|
20
|
-
console.error('Invalid options', e);
|
|
21
|
-
parsedOptions = {
|
|
22
|
-
defaultMode: 'ordered',
|
|
23
|
-
featuredId: '',
|
|
24
|
-
storyfragmentIds: '',
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const defaultMode = parsedOptions.defaultMode || 'ordered';
|
|
29
|
-
const featuredId = parsedOptions.featuredId || '';
|
|
30
|
-
const storyfragmentIdsArray = parsedOptions.storyfragmentIds
|
|
31
|
-
? parsedOptions.storyfragmentIds.split(',')
|
|
32
|
-
: [];
|
|
33
|
-
|
|
34
|
-
// Find the featured story from the contentMap
|
|
35
|
-
const featuredStory = contentMap.find(
|
|
36
|
-
(item: FullContentMapItem) =>
|
|
37
|
-
item.id === featuredId && item.type === 'StoryFragment'
|
|
38
|
-
);
|
|
39
|
-
// Filter and sort the included stories, excluding the featured story
|
|
40
|
-
let includedStories = contentMap.filter(
|
|
41
|
-
(item: FullContentMapItem) =>
|
|
42
|
-
storyfragmentIdsArray.includes(item.id) &&
|
|
43
|
-
item.type === 'StoryFragment' &&
|
|
44
|
-
item.id !== featuredId
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
// Sort included stories based on defaultMode ('ordered' or 'recent')
|
|
48
|
-
// The 'popular' mode will be handled on the client-side
|
|
49
|
-
if (defaultMode === 'ordered') {
|
|
50
|
-
includedStories.sort(
|
|
51
|
-
(a: FullContentMapItem, b: FullContentMapItem) =>
|
|
52
|
-
storyfragmentIdsArray.indexOf(a.id) - storyfragmentIdsArray.indexOf(b.id)
|
|
53
|
-
);
|
|
54
|
-
} else if (defaultMode === 'recent') {
|
|
55
|
-
includedStories.sort((a: FullContentMapItem, b: FullContentMapItem) => {
|
|
56
|
-
const dateA = a.changed ? new Date(a.changed).getTime() : 0;
|
|
57
|
-
const dateB = b.changed ? new Date(b.changed).getTime() : 0;
|
|
58
|
-
return dateB - dateA;
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Limit to 5 stories for display
|
|
63
|
-
const displayedStories = includedStories.slice(0, 5);
|
|
64
|
-
|
|
65
|
-
// Function to format dates
|
|
66
|
-
function formatDate(dateString: string | null): string {
|
|
67
|
-
if (!dateString) return 'Unknown';
|
|
68
|
-
const date = new Date(dateString);
|
|
69
|
-
return new Intl.DateTimeFormat('en-US', {
|
|
70
|
-
year: 'numeric',
|
|
71
|
-
month: 'long',
|
|
72
|
-
day: 'numeric',
|
|
73
|
-
}).format(date);
|
|
74
|
-
}
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
<div class="mx-auto flex max-w-7xl flex-col gap-4 py-12 md:flex-row">
|
|
78
|
-
<div class="p-4 md:w-3/5">
|
|
79
|
-
{
|
|
80
|
-
featuredStory ? (
|
|
81
|
-
<a href={`/${featuredStory.slug}`} class="group block">
|
|
82
|
-
<div class="space-y-6 p-2 group-hover:bg-slate-50">
|
|
83
|
-
{featuredStory.thumbSrc && (
|
|
84
|
-
<img
|
|
85
|
-
src={featuredStory.thumbSrc}
|
|
86
|
-
alt={featuredStory.title}
|
|
87
|
-
class="h-auto w-full rounded-lg object-cover"
|
|
88
|
-
/>
|
|
89
|
-
)}
|
|
90
|
-
<h2 class="text-2xl font-bold text-black transition-colors group-hover:text-gray-900">
|
|
91
|
-
{featuredStory.title}
|
|
92
|
-
</h2>
|
|
93
|
-
{featuredStory.description && (
|
|
94
|
-
<p class="text-base text-gray-800">{featuredStory.description}</p>
|
|
95
|
-
)}
|
|
96
|
-
<p class="text-sm text-gray-600">
|
|
97
|
-
{featuredStory.changed && formatDate(featuredStory.changed)}
|
|
98
|
-
</p>
|
|
99
|
-
</div>
|
|
100
|
-
</a>
|
|
101
|
-
) : (
|
|
102
|
-
<p class="italic text-cyan-600">No featured story selected.</p>
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
<div
|
|
108
|
-
class="border-t-2 border-slate-100 p-4 md:w-2/5 md:border-l-2 md:border-t-0"
|
|
109
|
-
>
|
|
110
|
-
{
|
|
111
|
-
displayedStories.length > 0 ? (
|
|
112
|
-
<div class="space-y-4">
|
|
113
|
-
{displayedStories.map((story: FullContentMapItem) => (
|
|
114
|
-
<a href={`/${story.slug}`} class="group block">
|
|
115
|
-
<div class="flex items-start space-x-4 p-1 group-hover:bg-slate-50">
|
|
116
|
-
{story.thumbSrc && (
|
|
117
|
-
<img
|
|
118
|
-
src={story.thumbSrc}
|
|
119
|
-
alt={story.title}
|
|
120
|
-
style="width: 100px; height: auto;"
|
|
121
|
-
class="rounded-md"
|
|
122
|
-
/>
|
|
123
|
-
)}
|
|
124
|
-
<div class="flex-1">
|
|
125
|
-
<h3 class="text-lg font-bold text-black transition-colors group-hover:text-gray-900">
|
|
126
|
-
{story.title}
|
|
127
|
-
</h3>
|
|
128
|
-
{story.description && (
|
|
129
|
-
<p class="line-clamp-2 text-sm text-gray-800">
|
|
130
|
-
{story.description}
|
|
131
|
-
</p>
|
|
132
|
-
)}
|
|
133
|
-
<p class="mt-1 text-xs text-gray-600">
|
|
134
|
-
{story.changed && formatDate(story.changed)}
|
|
135
|
-
</p>
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
</a>
|
|
139
|
-
))}
|
|
140
|
-
</div>
|
|
141
|
-
) : (
|
|
142
|
-
<p class="italic text-cyan-600">Check back soon for more stories.</p>
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
|
-
|
|
148
|
-
<script
|
|
149
|
-
is:inline
|
|
150
|
-
define:vars={{
|
|
151
|
-
includedStories,
|
|
152
|
-
defaultMode,
|
|
153
|
-
}}
|
|
154
|
-
>
|
|
155
|
-
// Client-side script to fetch and apply "hot content" analytics
|
|
156
|
-
let hotContent = [];
|
|
157
|
-
let hasHotContent = false;
|
|
158
|
-
let isLoading = false;
|
|
159
|
-
let retryCount = 0;
|
|
160
|
-
const maxRetries = 2;
|
|
161
|
-
|
|
162
|
-
// Fetches hot content data from the analytics endpoint with polling
|
|
163
|
-
async function fetchHotContent() {
|
|
164
|
-
if (isLoading) return;
|
|
165
|
-
isLoading = true;
|
|
166
|
-
|
|
167
|
-
try {
|
|
168
|
-
const goBackend = window.location.protocol + '//' + window.location.host;
|
|
169
|
-
const tenantId = window.TRACTSTACK_CONFIG?.tenantId || 'default';
|
|
170
|
-
const response = await fetch(
|
|
171
|
-
`${goBackend}/api/v1/analytics/content-summary`,
|
|
172
|
-
{
|
|
173
|
-
method: 'GET',
|
|
174
|
-
headers: {
|
|
175
|
-
'Content-Type': 'application/json',
|
|
176
|
-
'X-Tenant-ID': tenantId,
|
|
177
|
-
},
|
|
178
|
-
}
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
if (!response.ok) {
|
|
182
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const data = await response.json();
|
|
186
|
-
|
|
187
|
-
// If data is fetched, update state and re-order content
|
|
188
|
-
if (data.hotContent && data.hotContent.length > 0) {
|
|
189
|
-
hotContent = data.hotContent;
|
|
190
|
-
hasHotContent = true;
|
|
191
|
-
updateContentOrder();
|
|
192
|
-
} else if (retryCount < maxRetries) {
|
|
193
|
-
retryCount++;
|
|
194
|
-
const delayMs = retryCount === 1 ? 3000 : 6000;
|
|
195
|
-
setTimeout(fetchHotContent, delayMs);
|
|
196
|
-
}
|
|
197
|
-
} catch (error) {
|
|
198
|
-
console.warn('Could not fetch hot content:', error);
|
|
199
|
-
if (retryCount < maxRetries) {
|
|
200
|
-
retryCount++;
|
|
201
|
-
const delayMs = retryCount === 1 ? 3000 : 6000;
|
|
202
|
-
setTimeout(fetchHotContent, delayMs);
|
|
203
|
-
}
|
|
204
|
-
} finally {
|
|
205
|
-
isLoading = false;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Re-orders stories based on popularity if mode is 'popular'
|
|
210
|
-
function updateContentOrder() {
|
|
211
|
-
if (hasHotContent && defaultMode === 'popular') {
|
|
212
|
-
const viewsMap = new Map(
|
|
213
|
-
hotContent.map((item) => [item.id, item.totalEvents])
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
const sortedByPopular = [...includedStories].sort((a, b) => {
|
|
217
|
-
const aViews = viewsMap.get(a.id) || 0;
|
|
218
|
-
const bViews = viewsMap.get(b.id) || 0;
|
|
219
|
-
// Fallback to date sort if views are equal
|
|
220
|
-
if (bViews === aViews) {
|
|
221
|
-
const dateA = a.changed ? new Date(a.changed).getTime() : 0;
|
|
222
|
-
const dateB = b.changed ? new Date(b.changed).getTime() : 0;
|
|
223
|
-
return dateB - dateA;
|
|
224
|
-
}
|
|
225
|
-
return bViews - aViews;
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
updateDisplayedStories(sortedByPopular.slice(0, 5));
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Updates the DOM with the new list of stories
|
|
233
|
-
function updateDisplayedStories(stories) {
|
|
234
|
-
const rightColumn = document.querySelector('.md\\:w-2\\/5 .space-y-4');
|
|
235
|
-
if (!rightColumn) return;
|
|
236
|
-
|
|
237
|
-
rightColumn.innerHTML = stories
|
|
238
|
-
.map((story) => {
|
|
239
|
-
const formattedDate = story.changed
|
|
240
|
-
? new Intl.DateTimeFormat('en-US', {
|
|
241
|
-
year: 'numeric',
|
|
242
|
-
month: 'long',
|
|
243
|
-
day: 'numeric',
|
|
244
|
-
}).format(new Date(story.changed))
|
|
245
|
-
: 'Unknown';
|
|
246
|
-
const imageHtml = story.thumbSrc
|
|
247
|
-
? `<img src="${story.thumbSrc}" alt="${story.title}" style="width: 100px; height: auto;" class="rounded-md">`
|
|
248
|
-
: '';
|
|
249
|
-
const descriptionHtml = story.description
|
|
250
|
-
? `<p class="line-clamp-2 text-sm text-gray-800">${story.description}</p>`
|
|
251
|
-
: '';
|
|
252
|
-
|
|
253
|
-
return `
|
|
254
|
-
<a href="/${story.slug}" class="group block">
|
|
255
|
-
<div class="flex items-start space-x-4 p-1 group-hover:bg-slate-50">
|
|
256
|
-
${imageHtml}
|
|
257
|
-
<div class="flex-1">
|
|
258
|
-
<h3 class="text-lg font-bold text-black transition-colors group-hover:text-gray-900">
|
|
259
|
-
${story.title}
|
|
260
|
-
</h3>
|
|
261
|
-
${descriptionHtml}
|
|
262
|
-
<p class="mt-1 text-xs text-gray-600">${formattedDate}</p>
|
|
263
|
-
</div>
|
|
264
|
-
</div>
|
|
265
|
-
</a>
|
|
266
|
-
`;
|
|
267
|
-
})
|
|
268
|
-
.join('');
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Start fetching analytics on page load
|
|
272
|
-
document.addEventListener('DOMContentLoaded', fetchHotContent);
|
|
273
|
-
</script>
|