@wix/agent-skills 1.21.0 → 1.22.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/package.json +1 -1
- package/skills/wix-app/SKILL.md +60 -4
- package/skills/wix-app/references/DASHBOARD_PAGE.md +11 -25
- package/skills/wix-app/references/DATA_COLLECTION.md +16 -219
- package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +182 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +97 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +184 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +203 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +44 -0
- package/skills/wix-app/references/dashboard-page/QUERY_AND_PAGING.md +182 -0
- package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +133 -0
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +10 -5
- package/skills/wix-app/references/data-collection/LIFECYCLE.md +68 -0
- package/skills/wix-app/references/data-collection/PERMISSIONS.md +47 -0
- package/skills/wix-app/references/data-collection/SCHEMA.md +181 -0
- package/skills/wix-app/references/data-collection/WIX_DATA.md +38 -66
- package/skills/wix-headless-fast/SKILL.md +61 -223
- package/skills/wix-headless-fast/cold-start/bootstrap.mjs +156 -0
- package/skills/wix-headless-fast/{entry/skill.md → cold-start/cold-start.md} +11 -12
- package/skills/wix-headless-fast/guides/existing-site.md +76 -0
- package/skills/wix-headless-fast/guides/reference-mode.md +97 -0
- package/skills/wix-headless-fast/install/AGENTS.md +6 -3
- package/skills/wix-headless-fast/install/attach.mjs +15 -47
- package/skills/wix-headless-fast/install/deploy.mjs +21 -60
- package/skills/wix-headless-fast/install/lock.mjs +55 -0
- package/skills/wix-headless-fast/install/setup.mjs +32 -12
- package/skills/wix-headless-fast/install/templates.mjs +168 -0
- package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +27 -0
- package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +83 -37
- package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +0 -303
- package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +0 -136
- package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +0 -112
- package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +0 -42
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +0 -31
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +0 -22
- package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +0 -137
- package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +0 -78
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +0 -117
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +0 -52
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +0 -47
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +0 -58
- package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +0 -62
- package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +0 -97
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +0 -24
- package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +0 -16156
- package/skills/wix-headless-fast/references/blog/rest/posts.ts +0 -42
- package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +0 -62
- package/skills/wix-headless-fast/references/blog/seed/SEED.md +0 -81
- package/skills/wix-headless-fast/references/blog/seed/read-site.mjs +0 -22
- package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +0 -287
- package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +0 -277
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +0 -144
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +0 -119
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +0 -32
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +0 -23
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +0 -218
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +0 -169
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +0 -121
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +0 -92
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +0 -90
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +0 -57
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +0 -72
- package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +0 -76
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +0 -22
- package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +0 -11962
- package/skills/wix-headless-fast/references/bookings/rest/booking.ts +0 -113
- package/skills/wix-headless-fast/references/bookings/rest/services.ts +0 -55
- package/skills/wix-headless-fast/references/bookings/seed/SEED.md +0 -71
- package/skills/wix-headless-fast/references/bookings/seed/read-site.mjs +0 -28
- package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +0 -302
- package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +0 -355
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +0 -50
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +0 -37
- package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +0 -158
- package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +0 -93
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +0 -177
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +0 -123
- package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +0 -75
- package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +0 -41
- package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +0 -11262
- package/skills/wix-headless-fast/references/cms/rest/items.ts +0 -125
- package/skills/wix-headless-fast/references/cms/seed/SEED.md +0 -112
- package/skills/wix-headless-fast/references/cms/seed/read-site.mjs +0 -20
- package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +0 -324
- package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +0 -307
- package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +0 -66
- package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +0 -178
- package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +0 -118
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +0 -35
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +0 -24
- package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +0 -130
- package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +0 -97
- package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +0 -55
- package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +0 -113
- package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +0 -156
- package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +0 -97
- package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +0 -61
- package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +0 -12
- package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +0 -80
- package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +0 -21
- package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +0 -11884
- package/skills/wix-headless-fast/references/events/rest/events.ts +0 -57
- package/skills/wix-headless-fast/references/events/rest/registration.ts +0 -83
- package/skills/wix-headless-fast/references/events/seed/SEED.md +0 -95
- package/skills/wix-headless-fast/references/events/seed/read-site.mjs +0 -26
- package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +0 -276
- package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +0 -340
- package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +0 -85
- package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +0 -332
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +0 -238
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +0 -54
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +0 -216
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +0 -59
- package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +0 -135
- package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +0 -10593
- package/skills/wix-headless-fast/references/forms/rest/forms.ts +0 -34
- package/skills/wix-headless-fast/references/forms/rest/submissions.ts +0 -56
- package/skills/wix-headless-fast/references/forms/seed/SEED.md +0 -116
- package/skills/wix-headless-fast/references/forms/seed/read-site.mjs +0 -20
- package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +0 -327
- package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +0 -316
- package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +0 -60
- package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +0 -155
- package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +0 -78
- package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +0 -47
- package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +0 -66
- package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +0 -105
- package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +0 -59
- package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +0 -53
- package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +0 -122
- package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +0 -43
- package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +0 -29
- package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +0 -21
- package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +0 -42
- package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +0 -10
- package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +0 -11
- package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +0 -10329
- package/skills/wix-headless-fast/references/members/rest/auth.ts +0 -215
- package/skills/wix-headless-fast/references/members/rest/members.ts +0 -26
- package/skills/wix-headless-fast/references/members/seed/SEED.md +0 -39
- package/skills/wix-headless-fast/references/members/seed/read-site.mjs +0 -15
- package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +0 -94
- package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +0 -315
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +0 -110
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +0 -90
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +0 -35
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +0 -85
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +0 -32
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +0 -21
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +0 -31
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +0 -82
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +0 -58
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +0 -177
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +0 -78
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +0 -81
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +0 -55
- package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +0 -30
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +0 -21
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +0 -29
- package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +0 -10197
- package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +0 -75
- package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +0 -86
- package/skills/wix-headless-fast/references/portfolio/seed/read-site.mjs +0 -20
- package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +0 -256
- package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +0 -296
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +0 -47
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +0 -101
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +0 -41
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +0 -16
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +0 -22
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +0 -54
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +0 -106
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +0 -64
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +0 -27
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +0 -43
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +0 -22
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +0 -30
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +0 -41
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +0 -40
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +0 -21
- package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +0 -11226
- package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +0 -31
- package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +0 -20
- package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +0 -79
- package/skills/wix-headless-fast/references/pricing-plans/seed/read-site.mjs +0 -21
- package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +0 -279
- package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +0 -360
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +0 -142
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +0 -26
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +0 -121
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +0 -155
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +0 -34
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +0 -43
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +0 -34
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +0 -155
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +0 -89
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +0 -71
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +0 -103
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +0 -124
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +0 -185
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +0 -193
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +0 -94
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +0 -74
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +0 -168
- package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +0 -47
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +0 -22
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +0 -12
- package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +0 -12560
- package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +0 -60
- package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +0 -169
- package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +0 -68
- package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +0 -89
- package/skills/wix-headless-fast/references/restaurants/seed/read-site.mjs +0 -25
- package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +0 -499
- package/skills/wix-headless-fast/references/shared/CONTENT.md +0 -22
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +0 -73
- package/skills/wix-headless-fast/references/shared/DESIGN.md +0 -26
- package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +0 -23
- package/skills/wix-headless-fast/references/shared/app/styles/global.css +0 -52
- package/skills/wix-headless-fast/references/shared/app/wix/config.ts +0 -15
- package/skills/wix-headless-fast/references/shared/app/wix/media.ts +0 -81
- package/skills/wix-headless-fast/references/shared/app/wix/money.ts +0 -24
- package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +0 -89
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +0 -46
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +0 -46
- package/skills/wix-headless-fast/references/shared/rest/client.ts +0 -155
- package/skills/wix-headless-fast/references/shared/rest/config.ts +0 -3
- package/skills/wix-headless-fast/references/shared/rest/media.ts +0 -65
- package/skills/wix-headless-fast/references/shared/seed/images.mjs +0 -145
- package/skills/wix-headless-fast/references/shared/seed/read-site.mjs +0 -99
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +0 -612
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +0 -26
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +0 -155
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +0 -266
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +0 -95
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +0 -136
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +0 -48
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +0 -39
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +0 -34
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +0 -121
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +0 -107
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +0 -138
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +0 -314
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +0 -133
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +0 -147
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +0 -289
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +0 -169
- package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +0 -65
- package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +0 -12247
- package/skills/wix-headless-fast/references/storefront/rest/cart.ts +0 -132
- package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +0 -123
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +0 -130
- package/skills/wix-headless-fast/references/storefront/seed/read-site.mjs +0 -38
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +0 -561
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
# Blog — playbook
|
|
2
|
-
|
|
3
|
-
The blog machinery ships as files — post reads (feed paging, slug lookup with the body
|
|
4
|
-
fieldsets), category/tag taxonomy, the feed and post state machines, and the Ricos body renderer,
|
|
5
|
-
typed end-to-end. **The presentation doesn't ship — you build it** on the shipped hooks/DTOs: the
|
|
6
|
-
post card, the grid, the blog index surface, the post page surface, the home page, and the brand.
|
|
7
|
-
You never write blog data logic; you never skip designing. The vertical is **read-only** —
|
|
8
|
-
visitors read posts; authoring stays in the dashboard.
|
|
9
|
-
|
|
10
|
-
## The file map (deployed into `src/`)
|
|
11
|
-
|
|
12
|
-
**On Astro and React the shipped files are tested and work as they are** — this table and the
|
|
13
|
-
contracts below are everything you need to use them, so don't spend the run reading their source;
|
|
14
|
-
wire them and build your surfaces. Reading them is the right move when something is off (a runtime
|
|
15
|
-
error, a field this playbook doesn't cover) or when the brief wants a behaviour they don't offer —
|
|
16
|
-
then read the file that owns it and change or extend it. On `lib`, `static`, and a port the
|
|
17
|
-
components don't deploy at all, and each wiring section below opens with the files to read before
|
|
18
|
-
writing their equivalents. Files you edit: `SiteLayout.astro`, `styles/global.css`, and the two
|
|
19
|
-
shipped pages' templates. Files you **create**: your feed island (skeleton below), your post
|
|
20
|
-
surface, and your home page.
|
|
21
|
-
|
|
22
|
-
| file | what it is |
|
|
23
|
-
|---|---|
|
|
24
|
-
| `wix/config.ts` · `wix/sdk.ts` | shared auth seam (deploy configures it — nothing to set by hand) |
|
|
25
|
-
| `wix/media.ts` · `wix/money.ts` | `imgAttrs(url, sizes, ratio)` — every `<img>` attribute for a DTO image (`src`, `srcSet`, `sizes`, lazy): `<img {...imgAttrs(post.coverUrl, "(min-width: 1024px) 33vw, 100vw", 9 / 16)} alt={post.title} />`; `imgSrc()` / `imgSrcSet()` underneath |
|
|
26
|
-
| `wix/blog/types.ts` | the DTOs (`PostSummary`, `PostDetail`, `BlogCategory`, `BlogTag`, `PostPage`) — contracts inlined below |
|
|
27
|
-
| `wix/blog/posts.ts` | `fetchPosts` (cursor-paged, category/tag filtered on Wix), `fetchPostBySlug` (full body), `postMetaLine(post)` ("Aug 27, 2026 · 4 min read") — the transport; the rules and DTO mappers are in `posts-core.ts` beside it (shared with the REST layer) |
|
|
28
|
-
| `wix/blog/taxonomy.ts` | `fetchBlogCategories`, `fetchBlogTags`, `fetchCategoryBySlug`, `fetchTagBySlug` — the transport; mappers in `taxonomy-core.ts` |
|
|
29
|
-
| `wix/blog/blog-feed-store.ts` · `post-store.ts` | the feed and post state machines, framework-free (`createBlogFeedStore()`, `createPostStore()` — `getState`/`subscribe` + actions, one instance per surface); the hooks below bind them to React, every other stack uses them directly |
|
|
30
|
-
| `hooks/blog/useBlogFeed.ts` | React binding of `blog-feed-store.ts`: feed + taxonomy filter + load-more — contract below |
|
|
31
|
-
| `hooks/blog/usePost.ts` | React binding of `post-store.ts`: post by slug + resolved chips — contract below |
|
|
32
|
-
| `components/blog/RichContent.tsx` | the post-body renderer — **wire as-is** (machinery, not a reference) |
|
|
33
|
-
| `components/blog/BlogFeedView.tsx` (+ `PostCard`) · `PostView.tsx` | **reference implementations** — correct, plain; build your own instead of shipping them |
|
|
34
|
-
| `styles/global.css` | **the design system**: Tailwind v4 + the `@theme` token block (shared across verticals). Everything, shipped and yours, styles from these tokens |
|
|
35
|
-
|
|
36
|
-
Astro stack additionally gets:
|
|
37
|
-
|
|
38
|
-
| file | what it is |
|
|
39
|
-
|---|---|
|
|
40
|
-
| `layouts/SiteLayout.astro` | site chrome — **yours to brand** (keep the `seo-tags` slot + global.css import). If another vertical is also deployed, its layout won — add a Blog nav link there |
|
|
41
|
-
| `pages/blog.astro` | SSR feed — **keep the frontmatter**, swap the island import to YOUR component |
|
|
42
|
-
| `pages/blog/[...slug].astro` | SSR post page with owner-editable SEO — **keep the frontmatter, the `[...slug]` rest param, and the SEO pieces** (`wixMetadata`, `loadSEOTagsServiceConfig`, `<SEO.Tags>`) exactly; restyle the template. The body island stays `client:only="react"` (the ricos viewer breaks under SSR). A slug that resolves to nothing returns a real 404 |
|
|
43
|
-
|
|
44
|
-
## What you build — the design job
|
|
45
|
-
|
|
46
|
-
1. **The post card + grid** — your tile (cover, title, excerpt, `postMetaLine(post)`) and rhythm,
|
|
47
|
-
with skeletons while `posts === null` and an honest empty state for `[]`.
|
|
48
|
-
2. **The blog index surface** — the feed island on `useBlogFeed`: category filter (only when >1
|
|
49
|
-
non-empty category), the grid, and a load-more control gated on `hasMore`.
|
|
50
|
-
3. **The post page surface** — header (categories eyebrow, title, meta line, cover), the body via
|
|
51
|
-
the shipped `RichContent`, and the tag chips — restyle the `[...slug].astro` template around it.
|
|
52
|
-
4. **The home page** — hero, latest posts (fetch in frontmatter → your components), brand story.
|
|
53
|
-
|
|
54
|
-
Plus the **theme** (`@theme` block, one edit) and the **chrome** (`SiteLayout`, one pass).
|
|
55
|
-
Style everything with Tailwind utilities on the tokens. Dark theme: the ricos CSS hardcodes
|
|
56
|
-
near-black text — add a global override scoping `.ricos-content` to the foreground token
|
|
57
|
-
(in Astro use `<style is:global>`; React islands don't inherit scoped Astro styles).
|
|
58
|
-
|
|
59
|
-
### What a complete blog shows (recommended defaults)
|
|
60
|
-
|
|
61
|
-
Defaults for a blog whose brief says nothing about them; the prompt wins where it differs. Look at
|
|
62
|
-
the seeded content before designing (how many posts, categories, covers, body structure) and design
|
|
63
|
-
for this blog, not for a stereotype of one.
|
|
64
|
-
|
|
65
|
-
- **Home:** what the blog is about and the latest posts (real ones, under a truthful heading) in the
|
|
66
|
-
first screen; a category link goes to the feed filtered to it, never to an anchor.
|
|
67
|
-
- **Index:** a real card — cover, title, meta line — in the first screen at 390px too; the category
|
|
68
|
-
row only when more than one category has posts; loading, empty, and error states that look
|
|
69
|
-
different; load-more, never a raised page size.
|
|
70
|
-
- **Post page:** eyebrow, title, meta line, cover as a bounded band on phones (`max-h-[45vh]`), the
|
|
71
|
-
body, then the tags; a slug that resolves to nothing shows only the not-found state.
|
|
72
|
-
- **Copy:** nothing the author didn't write — no invented bylines, comment counts, likes, or
|
|
73
|
-
"trending" labels; no Wix IDs or technical words in visible text.
|
|
74
|
-
|
|
75
|
-
### The contracts your components consume
|
|
76
|
-
|
|
77
|
-
Tested and working as they are; read the source when something is off or the brief wants more.
|
|
78
|
-
|
|
79
|
-
```ts
|
|
80
|
-
// PostSummary (tiles) — display-ready:
|
|
81
|
-
// { id, slug, title, excerpt, dateLabel /* "Aug 26, 2026" | "" */, dateISO,
|
|
82
|
-
// minutesToRead /* 0 = unknown */, featured, pinned, coverUrl /* "" = no cover, 16:9 */,
|
|
83
|
-
// categoryIds, tagIds }
|
|
84
|
-
// postMetaLine(post) → "Aug 26, 2026 · 4 min read" (either half alone; "" when neither is known) —
|
|
85
|
-
// render it inside <time dateTime={post.dateISO}>; don't hand-assemble the separator.
|
|
86
|
-
// PostDetail adds: richContent (Ricos JSON | null — render ONLY via RichContent),
|
|
87
|
-
// paragraphs (plain-text fallback body).
|
|
88
|
-
// BlogCategory: { id, slug, label, description, postCount, coverUrl } // display .label
|
|
89
|
-
// BlogTag: { id, slug, label, postCount /* published posts */ }
|
|
90
|
-
|
|
91
|
-
// useBlogFeed({ initialPage?, initialCategories?, initialTags?, pageSize? /* 20 */ }) →
|
|
92
|
-
// { posts: PostSummary[]|null /* null = loading → skeletons */,
|
|
93
|
-
// categories, tags,
|
|
94
|
-
// activeCategoryId, setActiveCategoryId(id|null), // server-side filter
|
|
95
|
-
// activeTagId, setActiveTagId(id|null), // mutually exclusive with category
|
|
96
|
-
// hasMore, loadMore(), loadingMore, error }
|
|
97
|
-
// Filters and paging run on Wix (a changed filter restarts the list; a late response is dropped).
|
|
98
|
-
|
|
99
|
-
// usePost({ slug, initialPost?, initialCategories?, initialTags? }) →
|
|
100
|
-
// { post: PostDetail|null, notFound /* true = render a 404 state, never invent a post */,
|
|
101
|
-
// categories, tags /* THIS post's, resolved — display .label */, error }
|
|
102
|
-
|
|
103
|
-
// <RichContent content={post.richContent} fallbackParagraphs={post.paragraphs} />
|
|
104
|
-
// — the ONLY body render path. In Astro: client:only="react".
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### The island you create — skeleton
|
|
108
|
-
|
|
109
|
-
The two Astro pages ship; their frontmatter is machinery (SSR fetch → DTO props → island; the
|
|
110
|
-
post page's SEO block) and stays as shipped. What you create is the feed island `blog.astro` mounts
|
|
111
|
-
(and, in a SPA, the post surface — `PostView.tsx` shows its shape). Hooks first, branches after (an
|
|
112
|
-
early return above a hook changes hook order and React throws). Islands render on the server too,
|
|
113
|
-
after the 200 is sent — nothing in a render path may throw.
|
|
114
|
-
|
|
115
|
-
```tsx
|
|
116
|
-
// src/components/blog/<YourFeed>.tsx — YOU build it; blog.astro mounts it (swap the import there).
|
|
117
|
-
import { useBlogFeed } from "../../hooks/blog/useBlogFeed";
|
|
118
|
-
import { postMetaLine } from "../../wix/blog/posts";
|
|
119
|
-
import { imgAttrs } from "../../wix/media";
|
|
120
|
-
import type { BlogCategory, BlogTag, PostPage } from "../../wix/blog/types";
|
|
121
|
-
|
|
122
|
-
export default function YourFeed(props: {
|
|
123
|
-
initialPage?: PostPage; // SSR props from blog.astro — pass straight to useBlogFeed;
|
|
124
|
-
initialCategories?: BlogCategory[]; // omitted in a SPA (client fetch)
|
|
125
|
-
initialTags?: BlogTag[];
|
|
126
|
-
}) {
|
|
127
|
-
const feed = useBlogFeed(props);
|
|
128
|
-
const { posts, categories, activeCategoryId, setActiveCategoryId, hasMore, loadMore, loadingMore, error } = feed;
|
|
129
|
-
// …you implement the render:
|
|
130
|
-
// • a category row when more than one category has posts (categories.filter(c => c.postCount > 0)):
|
|
131
|
-
// "All" (null) first, the active one marked by activeCategoryId, each calling setActiveCategoryId
|
|
132
|
-
// • error → a short inline message
|
|
133
|
-
// • posts === null → skeleton tiles; [] → your honest empty state
|
|
134
|
-
// • else YOUR grid of YOUR tiles: cover via
|
|
135
|
-
// <img {...imgAttrs(p.coverUrl, "(min-width: 1024px) 33vw, 100vw", 9 / 16)} alt={p.title} /> — {} when
|
|
136
|
-
// there is no cover, render your placeholder then; title WRAPS (no truncate); excerpt clamped;
|
|
137
|
-
// <time dateTime={p.dateISO}>{postMetaLine(p)}</time>; the tile links to `/blog/${p.slug}`
|
|
138
|
-
// • hasMore → your "load more" control calling loadMore() (disabled while loadingMore)
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### The reference files for stacks where the components don't deploy
|
|
143
|
-
|
|
144
|
-
On `lib`, `static`, and a port, nothing under `components/` or `hooks/` arrives. The state
|
|
145
|
-
machines behind the hooks do arrive — `wix/blog/blog-feed-store.ts`, `post-store.ts` — so you never
|
|
146
|
-
rewrite them: create a store per surface, `subscribe`, render from `getState()`, call its actions.
|
|
147
|
-
Their `*State` interfaces are the render contract; read those. What you write is the rendering —
|
|
148
|
-
card, grid, filter row, post header — and for that read these first; they are tested code for
|
|
149
|
-
exactly that behaviour:
|
|
150
|
-
|
|
151
|
-
1. `components/blog/BlogFeedView.tsx` — the filter row (only categories with posts, "All" first,
|
|
152
|
-
one active pill), the skeleton grid while `posts === null`, the empty state, load-more disabled
|
|
153
|
-
while loading; `PostCard` inside it is the tile: 16:9 cover, wrapping title, clamped excerpt,
|
|
154
|
-
the meta line in a `<time>`.
|
|
155
|
-
2. `components/blog/PostView.tsx` — the states in order (not found → error → loading → article),
|
|
156
|
-
the categories eyebrow by `.label`, the tag chips, the body slot.
|
|
157
|
-
3. `components/blog/RichContent.tsx` — what the body renderer is: the `@wix/ricos` viewer, a React
|
|
158
|
-
component that needs a bundler. On these stacks it doesn't run; the body renders from
|
|
159
|
-
`post.paragraphs` (one `<p>` per entry), and headings, lists, quotes, and inline images flatten
|
|
160
|
-
to text — say so in the closing message. A blog whose posts carry structure stays on Astro.
|
|
161
|
-
|
|
162
|
-
All under `references/blog/app/`.
|
|
163
|
-
|
|
164
|
-
### Wiring — Astro (default)
|
|
165
|
-
|
|
166
|
-
1. Set the `@theme` tokens (one edit); brand `SiteLayout.astro` (one pass — merge into the
|
|
167
|
-
other vertical's layout instead if both are deployed).
|
|
168
|
-
2. Write your feed island under `src/components/blog/` (a new name — don't overwrite the
|
|
169
|
-
references), swap the island import in `pages/blog.astro`, and restyle the
|
|
170
|
-
`pages/blog/[...slug].astro` template (keep its frontmatter + SEO pieces + the
|
|
171
|
-
`client:only="react"` RichContent island). **Author your surfaces in as few messages as
|
|
172
|
-
possible** — batch multiple Writes per message.
|
|
173
|
-
3. Write `pages/index.astro` (home) — it exists from the scaffold; Read it before overwriting.
|
|
174
|
-
|
|
175
|
-
### Wiring — another JS framework (`--stack lib`: Vue, Svelte, Solid, plain Vite)
|
|
176
|
-
|
|
177
|
-
Read the reference files listed above before writing any surface.
|
|
178
|
-
|
|
179
|
-
`deploy.mjs blog --stack lib` put the data layer in `src/wix/` and nothing else: `sdk.ts` (the
|
|
180
|
-
visitor client, configured with the public client id), `media.ts`, `money.ts`, and `wix/blog/` —
|
|
181
|
-
`posts.ts`, `taxonomy.ts`, `types.ts`, the `*-core.ts` rules, and the two stores
|
|
182
|
-
`blog-feed-store.ts`, `post-store.ts`. None of it is React. The hooks and components don't ship on
|
|
183
|
-
this stack; the stores replace the hooks, and you write the components in your framework to the
|
|
184
|
-
contracts on this page:
|
|
185
|
-
|
|
186
|
-
- bind the stores with your framework's external-store primitive (Vue: `shallowRef` updated in
|
|
187
|
-
`subscribe`; Svelte: `readable(store.getState(), (set) => store.subscribe(() => set(store.getState())))`;
|
|
188
|
-
Solid: a signal set in `subscribe`). `createBlogFeedStore(options)` per feed (`start()` when
|
|
189
|
-
mounted, `stop()` when unmounted), `createPostStore({ slug, initialPost? })` per post surface.
|
|
190
|
-
State in, actions out — exactly the hooks' contracts above;
|
|
191
|
-
- the body: `@wix/ricos` is a React component — without React it doesn't render; use
|
|
192
|
-
`post.paragraphs` and say so in the closing message.
|
|
193
|
-
|
|
194
|
-
Routes `/blog`, `/blog/:slug` (null → your 404 view); dev server on 4321; a static build goes
|
|
195
|
-
through `npx @wix/cli@latest release` with `site.outputDirectory` pointing at the build folder,
|
|
196
|
-
an SSR build is hosted by you. Post-page tags from `post.title` and `post.excerpt`.
|
|
197
|
-
|
|
198
|
-
### Wiring — static site (`--stack static`, no bundler)
|
|
199
|
-
|
|
200
|
-
Read the reference files listed above before writing any surface.
|
|
201
|
-
|
|
202
|
-
`deploy.mjs blog --stack static --out site` put the REST layer in `site/js/wix/` (browser ESM,
|
|
203
|
-
the `.ts` beside each `.js` for reading). Everything the visitor loads lives under `site/` —
|
|
204
|
-
pages, styles, `js/` — and `wix.config.json`'s `site.outputDirectory` is `"./site"`; the project
|
|
205
|
-
root (config, plan, seed output) is never the upload. Same function names and DTOs as the table
|
|
206
|
-
above, so the contracts on this page hold unchanged: `fetchPosts`, `fetchPostBySlug`,
|
|
207
|
-
`postMetaLine` from `./js/wix/posts.js`; `fetchBlogCategories`, `fetchBlogTags`,
|
|
208
|
-
`fetchCategoryBySlug`, `fetchTagBySlug` from `./js/wix/taxonomy.js`; `imgAttrs` from
|
|
209
|
-
`./js/wix/media.js`. The state machines ship too: `createBlogFeedStore` from
|
|
210
|
-
`./js/wix/blog-feed-store.js` (the feed — filters, cursor paging; `start()` once the page is up)
|
|
211
|
-
and `createPostStore` from `./js/wix/post-store.js` (the post and its resolved chips). No
|
|
212
|
-
components ship — you write the rendering in plain JS: one render function per surface that reads
|
|
213
|
-
`getState()`, called from `subscribe`, with the surface's controls calling the store's actions.
|
|
214
|
-
Pages are `blog.html` and `post.html?slug=…` (Wix static hosting serves files, not directories —
|
|
215
|
-
name the file and link to it). The body renders from `post.paragraphs` (no Ricos viewer without a
|
|
216
|
-
bundler — see the reference files note). Set `document.title` and the meta description from
|
|
217
|
-
`post.title` and `post.excerpt` once the post loads, as the Astro page does. The visitor token
|
|
218
|
-
persists in `localStorage` on its own; never mint per page. `npx @wix/cli@latest release`
|
|
219
|
-
uploads `site/`.
|
|
220
|
-
|
|
221
|
-
### Wiring — server-rendered, another language (Flask, Laravel, Rails, …)
|
|
222
|
-
|
|
223
|
-
Read the reference files listed above before writing any surface.
|
|
224
|
-
|
|
225
|
-
Run `deploy.mjs blog --stack static` in the project folder anyway: `js/wix/` is both the
|
|
226
|
-
browser-side code and the readable spec. Reads render on the server: port `js/wix/posts.ts`,
|
|
227
|
-
`taxonomy.ts` and their `*-core.ts` to your language — the same six functions returning the same
|
|
228
|
-
DTO shapes as dicts, one anonymous visitor token per process for these public reads (mint and
|
|
229
|
-
refresh per `client.ts`) — and render the feed and the post page in your templates to the
|
|
230
|
-
contracts above, so titles and excerpts are in the HTML; post-page tags from `post.title` and
|
|
231
|
-
`post.excerpt`. The body is `paragraphs` server-side too (the Ricos viewer is React). Nothing in
|
|
232
|
-
this vertical runs on the visitor's behalf, so the browser side is optional: the feed's category
|
|
233
|
-
filter and load-more can run client-side on `./js/wix/blog-feed-store.js` exactly as the static
|
|
234
|
-
wiring above, or as plain server routes (`/blog?category=<slug>` via `fetchCategoryBySlug`,
|
|
235
|
-
paging by cursor). Routes stay `/blog`, `/blog/<slug>`.
|
|
236
|
-
|
|
237
|
-
**Pre-rendered (Frozen-Flask, Pelican, any static-site generator) → Wix-hosted.** Same port for
|
|
238
|
-
the reads, run at build time with one anonymous token; the generator must emit a page for every
|
|
239
|
-
post — walk `fetchPosts` by `nextCursor` until it is null, never only the first page. Run
|
|
240
|
-
`deploy.mjs blog --stack static --out <build dir>` so `js/wix/` is inside the output the pages
|
|
241
|
-
import from, point `site.outputDirectory` at that folder, `wix release`. Pages sit at different
|
|
242
|
-
depths (`/`, `/blog/…`): give the templates one base path to `js/wix/` (a template variable, or
|
|
243
|
-
root-relative `/js/wix/…`), never a relative `./js/wix/`. The frozen grid is the first paint; the
|
|
244
|
-
category filter and load-more still run client-side on it through `createBlogFeedStore()` from
|
|
245
|
-
`./js/wix/blog-feed-store.js`. Close with the live URL, the rebuild + release command, and one
|
|
246
|
-
line for the owner: posts published in the dashboard reach the site when that command runs.
|
|
247
|
-
|
|
248
|
-
### Wiring — React SPA (Vite etc.)
|
|
249
|
-
|
|
250
|
-
Import `./styles/global.css` once at the app entry (needs `@tailwindcss/vite` in the vite
|
|
251
|
-
plugins — deploy added the dep). Routes: `/blog` → your feed on `useBlogFeed`;
|
|
252
|
-
`/blog/:slug` → your post surface on `usePost({ slug })` (the `PostView` reference shows the
|
|
253
|
-
shape; `notFound` → your 404 view). Deploy wrote the public client id into `wix/config.ts`;
|
|
254
|
-
nothing else to configure.
|
|
255
|
-
|
|
256
|
-
Routes on Wix hosting: the host serves files only, so a clean route answers 404 when loaded directly — hash routes, or one HTML file per route, decided before the first route is written; any URL handed to Wix as a return target must be one the host serves (SKILL.md step 1).
|
|
257
|
-
|
|
258
|
-
## Hard rules
|
|
259
|
-
|
|
260
|
-
- **The body renders only through `RichContent`** where it deploys (Astro, React) — a post body
|
|
261
|
-
is a Ricos document, not HTML and not text: never `set:html`/innerHTML it, never stringify its
|
|
262
|
-
nodes, never write your own node walker. Where it doesn't deploy, `paragraphs` is the honest
|
|
263
|
-
body, and the closing message says so.
|
|
264
|
-
- **Data logic only through the shipped exports** — never rewrite their internals or re-derive a
|
|
265
|
-
request shape; extend by adding a function in `wix/blog/` (API contracts: the `wix-docs` skill).
|
|
266
|
-
- **Route by `slug` through the shipped functions** — never hand-build a post/category/tag URL
|
|
267
|
-
from ids; display taxonomy by `.label` (the API has no `.name`).
|
|
268
|
-
- **`notFound` means not found** — render your 404 state; never invent a post. Only published
|
|
269
|
-
posts come back, so a "missing" post is usually an unseeded/unpublished one.
|
|
270
|
-
- **Filter and page at the source** — `useBlogFeed`'s filters and `fetchPosts` run on Wix before
|
|
271
|
-
cursor paging; never filter a loaded page client-side, never raise the page limit instead of
|
|
272
|
-
paging (`hasMore`/`loadMore`).
|
|
273
|
-
- **Never hand-build a wixstatic image URL** — `coverUrl` is already resolved; anything else goes
|
|
274
|
-
through `wix/media.ts`.
|
|
275
|
-
- Where the shipped components deploy: theme via the `@theme` tokens, your markup in Tailwind
|
|
276
|
-
utilities on the same tokens; no parallel theme files, no hardcoded palettes. Where they don't
|
|
277
|
-
(`lib`, `static`, a port): style with what your stack does well, on one token set of your own.
|
|
278
|
-
- Live data or an honest empty state — never mock posts, authors, dates, or read times; no stock
|
|
279
|
-
placeholder covers. No author bylines or comment/like UI — the DTOs don't carry them.
|
|
280
|
-
- Keep the post page's SEO pieces and `[...slug]` rest param exactly as shipped.
|
|
281
|
-
- **Call every hook before any conditional return.** Hooks first, branches after.
|
|
282
|
-
|
|
283
|
-
## Point the user to their dashboard
|
|
284
|
-
|
|
285
|
-
Hand the owner these links — `{siteId}` is `siteId` in `wix.config.json` (the deploy JSON prints it as
|
|
286
|
-
`dashboardUrl`).
|
|
287
|
-
|
|
288
|
-
| page | `https://manage.wix.com/dashboard/{siteId}/` + |
|
|
289
|
-
|---|---|
|
|
290
|
-
| Posts (published and drafts) | `blog/posts` |
|
|
291
|
-
| Categories | `blog/categories` |
|
|
292
|
-
| Tags | `blog/tags` |
|
|
293
|
-
| Writers | `blog/writers` |
|
|
294
|
-
| Comments | `blog/comments` |
|
|
295
|
-
| Blog settings | `blog/settings` |
|
|
296
|
-
|
|
297
|
-
Only published posts appear on the site.
|
|
298
|
-
|
|
299
|
-
## Seeding
|
|
300
|
-
|
|
301
|
-
Per `seed/SEED.md` — plain-data `plan.json` into `seed-blog.mjs` from the project root.
|
|
302
|
-
Seed posts that exercise the UI (~3 posts, 2 categories when the brief has sections, varied
|
|
303
|
-
content blocks, a cover image per post).
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
// REFERENCE feed surface: taxonomy filter chips + post grid + load-more on the @theme tokens.
|
|
2
|
-
// Correct and complete; per the skill's model you design and build your own on useBlogFeed.
|
|
3
|
-
import type { ComponentType, ReactNode } from "react";
|
|
4
|
-
import { useBlogFeed } from "../../hooks/blog/useBlogFeed";
|
|
5
|
-
import { postMetaLine } from "../../wix/blog/posts";
|
|
6
|
-
import type { BlogCategory, BlogTag, PostPage, PostSummary } from "../../wix/blog/types";
|
|
7
|
-
|
|
8
|
-
export interface LinkLikeProps {
|
|
9
|
-
href: string;
|
|
10
|
-
className?: string;
|
|
11
|
-
children?: ReactNode;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const PlainLink = ({ href, className, children }: LinkLikeProps) => (
|
|
15
|
-
<a href={href} className={className}>
|
|
16
|
-
{children}
|
|
17
|
-
</a>
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
export interface PostCardProps {
|
|
21
|
-
post: PostSummary;
|
|
22
|
-
postHref?: (slug: string) => string;
|
|
23
|
-
LinkComponent?: ComponentType<LinkLikeProps>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function PostCard({ post, postHref = (slug) => `/blog/${slug}`, LinkComponent = PlainLink }: PostCardProps) {
|
|
27
|
-
return (
|
|
28
|
-
<LinkComponent href={postHref(post.slug)} className="group block no-underline">
|
|
29
|
-
{post.coverUrl && (
|
|
30
|
-
<div className="aspect-[16/9] overflow-hidden rounded-lg bg-secondary">
|
|
31
|
-
<img
|
|
32
|
-
src={post.coverUrl}
|
|
33
|
-
alt={post.title}
|
|
34
|
-
loading="lazy"
|
|
35
|
-
className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.03]"
|
|
36
|
-
/>
|
|
37
|
-
</div>
|
|
38
|
-
)}
|
|
39
|
-
<h3 className="mt-3 text-base font-semibold leading-snug text-foreground">{post.title}</h3>
|
|
40
|
-
{post.excerpt && <p className="mt-1 line-clamp-2 text-sm text-muted-foreground">{post.excerpt}</p>}
|
|
41
|
-
<p className="mt-2 text-xs text-muted-foreground">
|
|
42
|
-
<time dateTime={post.dateISO}>{postMetaLine(post)}</time>
|
|
43
|
-
</p>
|
|
44
|
-
</LinkComponent>
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface BlogFeedViewProps {
|
|
49
|
-
initialPage?: PostPage;
|
|
50
|
-
initialCategories?: BlogCategory[];
|
|
51
|
-
initialTags?: BlogTag[];
|
|
52
|
-
emptyMessage?: string;
|
|
53
|
-
postHref?: PostCardProps["postHref"];
|
|
54
|
-
LinkComponent?: ComponentType<LinkLikeProps>;
|
|
55
|
-
CardComponent?: ComponentType<PostCardProps>;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const pill = (active: boolean) =>
|
|
59
|
-
`rounded-full border px-4 py-1.5 text-sm font-medium transition-colors ${
|
|
60
|
-
active
|
|
61
|
-
? "border-primary bg-primary text-primary-foreground"
|
|
62
|
-
: "border-border text-foreground hover:bg-secondary"
|
|
63
|
-
}`;
|
|
64
|
-
|
|
65
|
-
export default function BlogFeedView({
|
|
66
|
-
initialPage,
|
|
67
|
-
initialCategories,
|
|
68
|
-
initialTags,
|
|
69
|
-
emptyMessage = "No posts yet — check back soon.",
|
|
70
|
-
postHref,
|
|
71
|
-
LinkComponent,
|
|
72
|
-
CardComponent = PostCard,
|
|
73
|
-
}: BlogFeedViewProps) {
|
|
74
|
-
const {
|
|
75
|
-
posts,
|
|
76
|
-
categories,
|
|
77
|
-
activeCategoryId,
|
|
78
|
-
setActiveCategoryId,
|
|
79
|
-
hasMore,
|
|
80
|
-
loadMore,
|
|
81
|
-
loadingMore,
|
|
82
|
-
error,
|
|
83
|
-
} = useBlogFeed({ initialPage, initialCategories, initialTags });
|
|
84
|
-
|
|
85
|
-
const visibleCategories = categories.filter((c) => c.postCount > 0);
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<div>
|
|
89
|
-
{visibleCategories.length > 1 && (
|
|
90
|
-
<div className="mb-8 flex flex-wrap gap-2" role="group" aria-label="Categories">
|
|
91
|
-
<button type="button" className={pill(activeCategoryId === null)} onClick={() => setActiveCategoryId(null)}>
|
|
92
|
-
All
|
|
93
|
-
</button>
|
|
94
|
-
{visibleCategories.map((c) => (
|
|
95
|
-
<button key={c.id} type="button" className={pill(activeCategoryId === c.id)} onClick={() => setActiveCategoryId(c.id)}>
|
|
96
|
-
{c.label}
|
|
97
|
-
</button>
|
|
98
|
-
))}
|
|
99
|
-
</div>
|
|
100
|
-
)}
|
|
101
|
-
{error && <p className="mb-4 text-sm text-red-600">{error}</p>}
|
|
102
|
-
{posts === null ? (
|
|
103
|
-
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3" aria-busy="true">
|
|
104
|
-
{Array.from({ length: 6 }, (_, i) => (
|
|
105
|
-
<div key={i}>
|
|
106
|
-
<div className="aspect-[16/9] animate-pulse rounded-lg bg-secondary" />
|
|
107
|
-
<div className="mt-3 h-3.5 w-2/3 animate-pulse rounded bg-secondary" />
|
|
108
|
-
</div>
|
|
109
|
-
))}
|
|
110
|
-
</div>
|
|
111
|
-
) : posts.length === 0 ? (
|
|
112
|
-
<p className="py-16 text-center text-muted-foreground">{emptyMessage}</p>
|
|
113
|
-
) : (
|
|
114
|
-
<>
|
|
115
|
-
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
|
|
116
|
-
{posts.map((p) => (
|
|
117
|
-
<CardComponent key={p.id} post={p} postHref={postHref} LinkComponent={LinkComponent} />
|
|
118
|
-
))}
|
|
119
|
-
</div>
|
|
120
|
-
{hasMore && (
|
|
121
|
-
<div className="mt-10 text-center">
|
|
122
|
-
<button
|
|
123
|
-
type="button"
|
|
124
|
-
onClick={loadMore}
|
|
125
|
-
disabled={loadingMore}
|
|
126
|
-
className="rounded-lg border border-border px-6 py-2.5 text-sm font-medium text-foreground transition-colors hover:bg-secondary disabled:opacity-50"
|
|
127
|
-
>
|
|
128
|
-
{loadingMore ? "Loading…" : "Load more"}
|
|
129
|
-
</button>
|
|
130
|
-
</div>
|
|
131
|
-
)}
|
|
132
|
-
</>
|
|
133
|
-
)}
|
|
134
|
-
</div>
|
|
135
|
-
);
|
|
136
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
// REFERENCE post surface (SPA use — Astro renders the header statically and mounts only
|
|
2
|
-
// RichContent as an island). Correct and complete; per the skill's model you design and
|
|
3
|
-
// build your own on usePost. Chips display .label; the body renders ONLY via RichContent.
|
|
4
|
-
import type { ComponentType } from "react";
|
|
5
|
-
import { usePost } from "../../hooks/blog/usePost";
|
|
6
|
-
import { postMetaLine } from "../../wix/blog/posts";
|
|
7
|
-
import type { BlogCategory, BlogTag, PostDetail } from "../../wix/blog/types";
|
|
8
|
-
import RichContent from "./RichContent";
|
|
9
|
-
import type { LinkLikeProps } from "./BlogFeedView";
|
|
10
|
-
|
|
11
|
-
export interface PostViewProps {
|
|
12
|
-
slug: string;
|
|
13
|
-
initialPost?: PostDetail;
|
|
14
|
-
initialCategories?: BlogCategory[];
|
|
15
|
-
initialTags?: BlogTag[];
|
|
16
|
-
/** Where a chip routes; omit to render chips as plain labels. */
|
|
17
|
-
categoryHref?: (slug: string) => string;
|
|
18
|
-
tagHref?: (slug: string) => string;
|
|
19
|
-
LinkComponent?: ComponentType<LinkLikeProps>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const PlainLink = ({ href, className, children }: LinkLikeProps) => (
|
|
23
|
-
<a href={href} className={className}>
|
|
24
|
-
{children}
|
|
25
|
-
</a>
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
const chipClass =
|
|
29
|
-
"rounded-full border border-border px-3 py-1 text-xs font-medium text-muted-foreground no-underline";
|
|
30
|
-
|
|
31
|
-
export default function PostView({
|
|
32
|
-
slug,
|
|
33
|
-
initialPost,
|
|
34
|
-
initialCategories,
|
|
35
|
-
initialTags,
|
|
36
|
-
categoryHref,
|
|
37
|
-
tagHref,
|
|
38
|
-
LinkComponent = PlainLink,
|
|
39
|
-
}: PostViewProps) {
|
|
40
|
-
const { post, notFound, categories, tags, error } = usePost({
|
|
41
|
-
slug,
|
|
42
|
-
initialPost,
|
|
43
|
-
initialCategories,
|
|
44
|
-
initialTags,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
if (notFound) {
|
|
48
|
-
return (
|
|
49
|
-
<div className="py-24 text-center">
|
|
50
|
-
<p className="text-lg font-medium">Post not found</p>
|
|
51
|
-
<p className="mt-2 text-sm text-muted-foreground">It may have been unpublished or moved.</p>
|
|
52
|
-
</div>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
if (error) return <p className="py-8 text-sm text-red-600">{error}</p>;
|
|
56
|
-
if (post === null) {
|
|
57
|
-
return (
|
|
58
|
-
<div aria-busy="true">
|
|
59
|
-
<div className="h-8 w-2/3 animate-pulse rounded bg-secondary" />
|
|
60
|
-
<div className="mt-6 aspect-[16/9] animate-pulse rounded-lg bg-secondary" />
|
|
61
|
-
</div>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<article className="mx-auto max-w-3xl">
|
|
67
|
-
{categories.length > 0 && (
|
|
68
|
-
<p className="eyebrow">
|
|
69
|
-
{categories.map((c, i) => (
|
|
70
|
-
<span key={c.id}>
|
|
71
|
-
{i > 0 && " · "}
|
|
72
|
-
{categoryHref ? (
|
|
73
|
-
<LinkComponent href={categoryHref(c.slug)} className="no-underline">
|
|
74
|
-
{c.label}
|
|
75
|
-
</LinkComponent>
|
|
76
|
-
) : (
|
|
77
|
-
c.label
|
|
78
|
-
)}
|
|
79
|
-
</span>
|
|
80
|
-
))}
|
|
81
|
-
</p>
|
|
82
|
-
)}
|
|
83
|
-
<h1 className="mt-2 text-3xl font-semibold tracking-tight">{post.title}</h1>
|
|
84
|
-
<p className="mt-3 text-sm text-muted-foreground">
|
|
85
|
-
<time dateTime={post.dateISO}>{postMetaLine(post)}</time>
|
|
86
|
-
</p>
|
|
87
|
-
{post.coverUrl && (
|
|
88
|
-
<div className="mt-6 aspect-[16/9] overflow-hidden rounded-xl bg-secondary">
|
|
89
|
-
<img src={post.coverUrl} alt={post.title} className="h-full w-full object-cover" />
|
|
90
|
-
</div>
|
|
91
|
-
)}
|
|
92
|
-
<div className="mt-8">
|
|
93
|
-
<RichContent content={post.richContent} fallbackParagraphs={post.paragraphs} />
|
|
94
|
-
</div>
|
|
95
|
-
{tags.length > 0 && (
|
|
96
|
-
<div className="mt-10 flex flex-wrap gap-2">
|
|
97
|
-
{tags.map((t) =>
|
|
98
|
-
tagHref ? (
|
|
99
|
-
<LinkComponent key={t.id} href={tagHref(t.slug)} className={chipClass}>
|
|
100
|
-
{t.label}
|
|
101
|
-
</LinkComponent>
|
|
102
|
-
) : (
|
|
103
|
-
<span key={t.id} className={chipClass}>
|
|
104
|
-
{t.label}
|
|
105
|
-
</span>
|
|
106
|
-
),
|
|
107
|
-
)}
|
|
108
|
-
</div>
|
|
109
|
-
)}
|
|
110
|
-
</article>
|
|
111
|
-
);
|
|
112
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// The post-body renderer — wire AS-IS (machinery, not a reference). A post body is a Ricos
|
|
2
|
-
// document, not HTML and not text: never innerHTML it, never String() its nodes. This is the
|
|
3
|
-
// documented render path (@wix/ricos viewer + quick-start plugins).
|
|
4
|
-
//
|
|
5
|
-
// In Astro this component MUST be a `client:only="react"` island — the ricos viewer breaks
|
|
6
|
-
// under SSR. Dark theme: the ricos CSS hardcodes near-black text; scope an override on
|
|
7
|
-
// `.ricos-content` forcing the foreground token (in Astro use <style is:global> — React
|
|
8
|
-
// islands don't inherit scoped Astro styles).
|
|
9
|
-
import { quickStartViewerPlugins, RicosViewer } from "@wix/ricos";
|
|
10
|
-
import "@wix/ricos/css/all-plugins-viewer.css";
|
|
11
|
-
|
|
12
|
-
// Module-level, once — never rebuild the plugin list per render.
|
|
13
|
-
const plugins = quickStartViewerPlugins();
|
|
14
|
-
|
|
15
|
-
export interface RichContentProps {
|
|
16
|
-
/** PostDetail.richContent — the Ricos document (plain JSON). */
|
|
17
|
-
content: Record<string, unknown> | null;
|
|
18
|
-
/** PostDetail.paragraphs — the honest fallback body when richContent is null. */
|
|
19
|
-
fallbackParagraphs?: string[];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default function RichContent({ content, fallbackParagraphs = [] }: RichContentProps) {
|
|
23
|
-
if (content) {
|
|
24
|
-
return (
|
|
25
|
-
<div className="ricos-content">
|
|
26
|
-
<RicosViewer content={content as any} plugins={plugins} />
|
|
27
|
-
</div>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
if (fallbackParagraphs.length > 0) {
|
|
31
|
-
return (
|
|
32
|
-
<div className="space-y-4">
|
|
33
|
-
{fallbackParagraphs.map((p, i) => (
|
|
34
|
-
<p key={i} className="leading-relaxed">
|
|
35
|
-
{p}
|
|
36
|
-
</p>
|
|
37
|
-
))}
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// React binding of the blog feed store (wix/blog/blog-feed-store.ts) — the feed state machine
|
|
2
|
-
// (taxonomy filter, cursor paging) lives there, framework-free; this hook subscribes to one
|
|
3
|
-
// instance per mounted feed and exposes its state and actions under one name. Astro islands and
|
|
4
|
-
// React SPAs use this; a static page, Vue, or Svelte uses the store directly.
|
|
5
|
-
//
|
|
6
|
-
// SSR-friendly: pass server-fetched data as `initial*` (Astro frontmatter / server component) and
|
|
7
|
-
// no client fetch happens; a SPA passes nothing. Category/tag filtering fetches live
|
|
8
|
-
// (server-side-filtered); the two filters are mutually exclusive — setting one clears the other.
|
|
9
|
-
import { useEffect, useRef, useSyncExternalStore } from "react";
|
|
10
|
-
import { createBlogFeedStore, type BlogFeedState, type BlogFeedStore, type BlogFeedStoreOptions } from "../../wix/blog/blog-feed-store";
|
|
11
|
-
|
|
12
|
-
export type UseBlogFeedOptions = BlogFeedStoreOptions;
|
|
13
|
-
|
|
14
|
-
export type UseBlogFeed = BlogFeedState & Pick<BlogFeedStore, "setActiveCategoryId" | "setActiveTagId" | "loadMore">;
|
|
15
|
-
|
|
16
|
-
export function useBlogFeed(options: UseBlogFeedOptions = {}): UseBlogFeed {
|
|
17
|
-
const ref = useRef<BlogFeedStore | null>(null);
|
|
18
|
-
if (!ref.current) ref.current = createBlogFeedStore(options);
|
|
19
|
-
const store = ref.current;
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
store.start();
|
|
22
|
-
return () => store.stop();
|
|
23
|
-
}, [store]);
|
|
24
|
-
const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
25
|
-
return {
|
|
26
|
-
...state,
|
|
27
|
-
setActiveCategoryId: store.setActiveCategoryId,
|
|
28
|
-
setActiveTagId: store.setActiveTagId,
|
|
29
|
-
loadMore: store.loadMore,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// React binding of the post store (wix/blog/post-store.ts) — post-by-slug loading and the resolved
|
|
2
|
-
// category/tag chips live there, framework-free; this hook subscribes to one instance per slug.
|
|
3
|
-
//
|
|
4
|
-
// SSR-friendly: pass the server-fetched post (and taxonomy) as `initial*` and no client fetch
|
|
5
|
-
// happens; a SPA passes only the slug. A slug change creates a fresh store and refetches.
|
|
6
|
-
import { useEffect, useRef, useSyncExternalStore } from "react";
|
|
7
|
-
import { createPostStore, type PostState, type PostStore, type PostStoreOptions } from "../../wix/blog/post-store";
|
|
8
|
-
|
|
9
|
-
export type UsePostOptions = PostStoreOptions;
|
|
10
|
-
|
|
11
|
-
export type UsePost = PostState;
|
|
12
|
-
|
|
13
|
-
export function usePost({ slug, initialPost, initialCategories, initialTags }: UsePostOptions): UsePost {
|
|
14
|
-
const ref = useRef<{ slug: string; store: PostStore } | null>(null);
|
|
15
|
-
if (!ref.current || ref.current.slug !== slug) ref.current = { slug, store: createPostStore({ slug, initialPost, initialCategories, initialTags }) };
|
|
16
|
-
const store = ref.current.store;
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
store.start();
|
|
19
|
-
return () => store.stop();
|
|
20
|
-
}, [store]);
|
|
21
|
-
return useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
22
|
-
}
|