simple-module-pagebuilder 0.0.8__tar.gz → 0.0.10__tar.gz
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.
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/PKG-INFO +1 -1
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/package.json +1 -1
- simple_module_pagebuilder-0.0.10/pagebuilder/components/editor/noHeaderActions.tsx +9 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/puckConfig.test.tsx +13 -1
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/puckConfig.tsx +14 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_internal/eyebrow-split-section.tsx +1 -1
- simple_module_pagebuilder-0.0.10/pagebuilder/components/widgets/_internal/inline-image.tsx +37 -0
- simple_module_pagebuilder-0.0.10/pagebuilder/components/widgets/_internal/markdown-list.tsx +35 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_internal/rich-text.tsx +45 -21
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/faq-render.tsx +10 -8
- simple_module_pagebuilder-0.0.10/pagebuilder/components/widgets/markdown-widget.test.tsx +68 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/markdown-widget.tsx +7 -7
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/quote-widget.tsx +20 -3
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/section-intro-widget.tsx +1 -1
- simple_module_pagebuilder-0.0.10/pagebuilder/components/widgets/site-header-account.tsx +53 -0
- simple_module_pagebuilder-0.0.10/pagebuilder/components/widgets/site-header-widget.test.tsx +89 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/site-header-widget.tsx +26 -2
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/public_views.py +5 -2
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/seo.py +4 -2
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/locales/en.json +5 -1
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/LayoutEditor.tsx +5 -9
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/MediaLibrary.tsx +2 -1
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/PageEditor.tsx +15 -4
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/PageList.tsx +6 -3
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/PendingReview.tsx +2 -1
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/service/__init__.py +3 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/tenancy.py +26 -0
- simple_module_pagebuilder-0.0.10/pagebuilder/utils/markdown.test.ts +65 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/markdown.ts +48 -8
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pyproject.toml +12 -1
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_pages_api.py +25 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_tenancy_public.py +37 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/.gitignore +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/README.md +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/__init__.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/board.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/boot.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/ConfirmDialog.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/DiffSummary.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/NewPageDialog.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/NoteDialog.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/PageBoard.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/PageBoardCard.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/PageListFilters.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/PageListRow.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/ScheduledBadge.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/StatusBadge.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/TranslatePageDialog.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blockRegistry.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blockRegistry.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blocks/Button.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blocks/Columns.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blocks/Heading.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blocks/Image.test.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blocks/Image.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blocks/MediaPicker.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blocks/Spacer.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/blocks/Text.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/BlockOutline.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/NarrowCanvas.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/PageActions.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/PageEditorToolbar.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/PageInspectorDrawer.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/PageSettingsPanel.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/RevisionHistoryPanel.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/SchedulePanel.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/SeoPreview.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/SeoSettingsPanel.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/editor/TranslationsPanel.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/layoutPuckConfig.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/lazyBlock.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/localizeConfig.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/localizeConfig.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/media/MediaFilters.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/media/MediaFolderSidebar.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/media/MediaGrid.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/media/MediaHeader.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/media/MediaUploadQueue.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/media/MediaUsageList.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/media/types.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/migrateContent.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/migrateContent.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/snapshots/ImportPlanSummary.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/snapshots/SnapshotList.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/snapshots/UploadBundleDialog.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/snapshots/planSummary.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/snapshots/planSummary.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgetCatalog.test.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgetCatalog.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_internal/accent-text.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_internal/disclosure-chevron.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_internal/link-arrow.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_internal/solid-icons.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/background-media.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/content-media.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/cta-button.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/empty-placeholder.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/eyebrow-text.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/heading.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/image-srcset.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/index.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/mask.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/section.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/social-icon.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/_shared/text-link.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/accordion-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/alert-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/app-store-badges-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/article-cards-render.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/article-cards-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/call-to-action-render.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/call-to-action-styles.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/call-to-action-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/carousel-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/centered-hero-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/colored-action-list-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/column-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/contact-cards-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/contact-form-render.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/contact-form-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/container-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/definition-list-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/divider-widget.test.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/divider-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/eyebrow-section-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/faq-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/feature-card-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/feature-cards-render.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/feature-cards-styles.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/feature-cards-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/feature-grid-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/feature-showcase-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/gallery-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/grid-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/hero-widget-props.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/hero-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/html-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/iframe-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/leaderboard-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/list-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/logo-cloud-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/media-object-layout.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/media-object-render.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/media-object-text.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/media-object-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/newsletter-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/page-header-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/prose-section-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/row-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/signup-banner-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/simple-action-list-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/site-footer-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/site-header-nav.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/social-banner-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/stats-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/steps-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/story-cards-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/table-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/tabs-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/tags-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/testimonial-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/timeline-layout.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/timeline-render.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/timeline-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/under-construction-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/video-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/components/widgets/welcome-widget.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/contracts/__init__.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/contracts/events.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/contracts/schemas/__init__.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/contracts/schemas/_layout.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/contracts/schemas/_media.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/contracts/schemas/_pages.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/contracts/schemas/_snapshots.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/conversion/blocks-to-html.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/conversion/blocks-to-html.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/conversion/index.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/conversion/types.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/deps.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/diff.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/__init__.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/__init__.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/_deps.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/layout.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/media_detail.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/pages.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/revisions.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/snapshots.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/uploads.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/api/workflow.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/content_views.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/endpoints/views.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/fields/checkbox-field.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/fields/file-picker/file-gallery.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/fields/file-picker/image-picker-field.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/fields/file-picker/index.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/fields/file-picker/types.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/fields/index.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/fields/media-adapter.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/useAutosave.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/useEditorForm.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/useIsNarrow.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/useMediaDetail.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/useMediaUploads.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/usePageRevisions.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/usePageSchedule.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/usePageWorkflow.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/usePendingDialog.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/hooks/useSnapshots.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/layout_service.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/locales.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/media_files.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/media_images.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/media_queries.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/media_service.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/media_usage.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/models/__init__.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/models/_base.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/models/_layout.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/models/_media.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/models/_page.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/models/_redirect.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/models/_snapshot.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/module.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/ContentImportReview.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/ContentSnapshots.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/MediaDetail.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/PublicPage.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/pages/Trash.tsx +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/permissions.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/public_claims.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/py.typed +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/redirects.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/scheduler.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/security.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/service/_common.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/service/_revisions.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/service/_translations.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/service/_trash.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/service/_workflow.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/services.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/settings.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/__init__.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/apply.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/archive.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/assets.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/blobs.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/capture.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/format.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/media_match.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/pages.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/plan.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/service.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/snapshots/validate.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/static/widgets-base.css +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/translation/apply.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/translation/extract.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/translation/index.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/translation/translatable-fields.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/translation/translation.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/api.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/blockOutline.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/blockOutline.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/datetime.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/decorative-image.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/editorSnapshot.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/i18n.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/i18n.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/locale.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/measure.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/mediaApi.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/mediaFormat.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/pagesApi.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/parse-list.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/request.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/request.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/slugify.test.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/slugify.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/snapshotsApi.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/types.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/pagebuilder/utils/widgetUtils.ts +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/conftest.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/db_fixture.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/locale_fixture.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/page_helpers.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/pg_support.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/snapshot_fixture.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/tenant_app.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/tenant_fixture.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_admin_list_view.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_approval_workflow.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_auth_gating.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_csrf.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_draft_preview.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_hreflang_and_sitemap.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_i18n.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_image_processing.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_media_detail.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_media_files.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_media_security.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_media_usage_escaping.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_module.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_multilingual.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_page_templates.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_page_translations.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_pages_search.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_public_claims.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_public_routes.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_public_view_headers.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_public_viewer.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_redirects.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_revision_notes_and_diff.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_revisions_api.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_scheduled_publish.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_scheduler_stop.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_scheduler_tenancy.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_seo_meta.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_settings_source.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_site_layout.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_sitemap_robots.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_apply.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_apply_media.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_archive.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_assets.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_blobs.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_capture.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_media_match.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_models.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_multilingual.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_page_payload.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_plan.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_validate.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshot_views.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_snapshots_api.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_tenancy_blobs.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_tenancy_core.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_tenancy_isolation.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_tenancy_media.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_tenancy_routes.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_trash.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_trash_preconditions.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tests/test_uploads_api.py +0 -0
- {simple_module_pagebuilder-0.0.8 → simple_module_pagebuilder-0.0.10}/tsconfig.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: simple_module_pagebuilder
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.10
|
|
4
4
|
Summary: Drag-and-drop visual page builder for simple_module apps
|
|
5
5
|
Project-URL: Repository, https://github.com/antosubash/simple_module_python_modules
|
|
6
6
|
Author-email: Anto Subash <antosubash@live.com>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Puck `overrides` that drop the header's own "Publish" (#59).
|
|
3
|
+
*
|
|
4
|
+
* Both editors have a toolbar that owns saving and publishing, so Puck's
|
|
5
|
+
* button would be a second, duplicate control. The title, undo/redo and
|
|
6
|
+
* sidebar toggles stay. Module scope so Puck sees a stable object rather than
|
|
7
|
+
* a fresh one on every render.
|
|
8
|
+
*/
|
|
9
|
+
export const NO_HEADER_ACTIONS = { headerActions: () => <></> };
|
|
@@ -4,7 +4,7 @@ import { translate } from '../utils/i18n';
|
|
|
4
4
|
import { type AnyBlock, registerPuckBlocks, resetBlockRegistry } from './blockRegistry';
|
|
5
5
|
import { getLayoutPuckConfig } from './layoutPuckConfig';
|
|
6
6
|
import { localizeConfig } from './localizeConfig';
|
|
7
|
-
import { getPuckConfig } from './puckConfig';
|
|
7
|
+
import { getPuckConfig, withRootTitle } from './puckConfig';
|
|
8
8
|
|
|
9
9
|
const stub = { render: () => null } as unknown as AnyBlock;
|
|
10
10
|
|
|
@@ -139,3 +139,15 @@ describe('getLayoutPuckConfig', () => {
|
|
|
139
139
|
expect(Object.keys(getLayoutPuckConfig().components)).toContain('Banner');
|
|
140
140
|
});
|
|
141
141
|
});
|
|
142
|
+
|
|
143
|
+
describe('withRootTitle', () => {
|
|
144
|
+
it('defaults the root title to the page’s own, not "Untitled page"', () => {
|
|
145
|
+
const config = withRootTitle(getPuckConfig(), 'About us');
|
|
146
|
+
expect(config.root?.defaultProps).toEqual({ title: 'About us', width: 'contained' });
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('leaves the config alone when the page has no title yet', () => {
|
|
150
|
+
const base = getPuckConfig();
|
|
151
|
+
expect(withRootTitle(base, null)).toBe(base);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -106,6 +106,20 @@ export function getPuckConfig(): PageConfig {
|
|
|
106
106
|
return cachedConfig;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Seed the root `title` field from the page row (#59).
|
|
111
|
+
*
|
|
112
|
+
* Puck fills a missing root prop from `defaultProps`, so a document saved
|
|
113
|
+
* without `root.props.title` — every seeded one — opened as "Untitled page"
|
|
114
|
+
* even though the page has a title. Defaulting to the page's own title shows
|
|
115
|
+
* the right thing without rewriting a stored document nobody has edited.
|
|
116
|
+
*/
|
|
117
|
+
export function withRootTitle(config: PageConfig, title: string | null | undefined): PageConfig {
|
|
118
|
+
if (!title) return config;
|
|
119
|
+
const defaultProps = { ...config.root?.defaultProps, title } as PageRootProps;
|
|
120
|
+
return { ...config, root: { ...config.root, defaultProps } };
|
|
121
|
+
}
|
|
122
|
+
|
|
109
123
|
export const emptyData = {
|
|
110
124
|
content: [],
|
|
111
125
|
root: { props: { title: 'Untitled page', width: 'contained' } },
|
|
@@ -54,7 +54,7 @@ export function EyebrowSplitSection({
|
|
|
54
54
|
{renderRichText(eyebrow)}
|
|
55
55
|
</p>
|
|
56
56
|
)}
|
|
57
|
-
<div className="max-w-[var(--pb-split-content-max,none)]">
|
|
57
|
+
<div className="min-w-0 max-w-[var(--pb-split-content-max,none)]">
|
|
58
58
|
{/* AccentText, not bare renderRichText: this is a display heading on
|
|
59
59
|
`--pb-display-weight`, where a plain <strong>'s relative `bolder`
|
|
60
60
|
can compute to no visible change. */}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
// A link href or image src: ONE level of balanced parentheses, so Wikipedia's
|
|
4
|
+
// `..._(disambiguation)` survives (see LINK_PATTERN in rich-text).
|
|
5
|
+
export const HREF_SOURCE = String.raw`(?:[^\s()]|\([^\s()]*\))+`;
|
|
6
|
+
/** `` — the alt may be empty, as a decorative logo's is. */
|
|
7
|
+
export const IMAGE_SOURCE = String.raw`!\[[^\]]*\]\(${HREF_SOURCE}\)`;
|
|
8
|
+
const IMAGE_EXACT = new RegExp(String.raw`^!\[([^\]]*)\]\((${HREF_SOURCE})\)$`);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Only http(s) and scheme-less sources (`/media/...`, `logo.png`) load. Editor
|
|
12
|
+
* copy is not fully trusted, so `data:`, `javascript:` and the rest fall
|
|
13
|
+
* through to literal text, the same way an unsafe link href does.
|
|
14
|
+
*/
|
|
15
|
+
function isSafeImageSrc(src: string): boolean {
|
|
16
|
+
const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(src);
|
|
17
|
+
return !scheme || ['http', 'https'].includes(scheme[1].toLowerCase());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* `` → `<img>`, or `null` when the text is not exactly one image or
|
|
22
|
+
* its src is unsafe (#66). Inline, so a line of logos sits in a row and a
|
|
23
|
+
* paragraph of its own stacks; `max-w-full` keeps a large one inside the column.
|
|
24
|
+
*/
|
|
25
|
+
export function renderInlineImage(markdown: string, key: string): ReactNode | null {
|
|
26
|
+
const match = IMAGE_EXACT.exec(markdown);
|
|
27
|
+
if (!match || !isSafeImageSrc(match[2])) return null;
|
|
28
|
+
return (
|
|
29
|
+
<img
|
|
30
|
+
key={key}
|
|
31
|
+
src={match[2]}
|
|
32
|
+
alt={match[1]}
|
|
33
|
+
loading="lazy"
|
|
34
|
+
className="inline-block h-auto max-w-full align-middle"
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { MarkdownListItem } from '../../../utils/markdown';
|
|
2
|
+
import { renderRichText } from './rich-text';
|
|
3
|
+
|
|
4
|
+
// Nested levels switch to hollow bullets, the way browsers mark a second level.
|
|
5
|
+
// The marker position is inherited explicitly: preflight's `list-style: none`
|
|
6
|
+
// resets it to `outside`, so under the Markdown widget's `list-inside` list
|
|
7
|
+
// the nested markers hung back in line with their parent's.
|
|
8
|
+
const NESTED_CLASS = 'list-[circle] [list-style-position:inherit] pl-5 mt-1 space-y-1';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A parsed `- ` list, nesting included (#66). The Markdown widget, FAQ answers
|
|
12
|
+
* and widget textareas all render bullets through this, so a nested item can't
|
|
13
|
+
* work in one of them and flatten in another.
|
|
14
|
+
*/
|
|
15
|
+
export function MarkdownList({
|
|
16
|
+
items,
|
|
17
|
+
className,
|
|
18
|
+
}: {
|
|
19
|
+
items: MarkdownListItem[];
|
|
20
|
+
className?: string;
|
|
21
|
+
}) {
|
|
22
|
+
return (
|
|
23
|
+
<ul className={className}>
|
|
24
|
+
{items.map((item, i) => (
|
|
25
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: list items are positional slices of the source text
|
|
26
|
+
<li key={i}>
|
|
27
|
+
{renderRichText(item.text)}
|
|
28
|
+
{item.children.length > 0 && (
|
|
29
|
+
<MarkdownList items={item.children} className={NESTED_CLASS} />
|
|
30
|
+
)}
|
|
31
|
+
</li>
|
|
32
|
+
))}
|
|
33
|
+
</ul>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
parseMarkdownBlocks,
|
|
6
6
|
} from '../../../utils/markdown';
|
|
7
7
|
import { cn } from '../../../utils/widgetUtils';
|
|
8
|
+
import { HREF_SOURCE, IMAGE_SOURCE, renderInlineImage } from './inline-image';
|
|
9
|
+
import { MarkdownList } from './markdown-list';
|
|
8
10
|
|
|
9
11
|
// `[label](href)`. Split first, so a link's label can still carry the emphasis
|
|
10
12
|
// markers the inline tokenizer understands ("[**Datenschutz**](/x)").
|
|
@@ -15,7 +17,15 @@ import { cn } from '../../../utils/widgetUtils';
|
|
|
15
17
|
// leaking the remainder onto the page as stray literal text. Anything the
|
|
16
18
|
// pattern can't parse falls through unchanged and renders as literal text, so
|
|
17
19
|
// malformed input is always visible rather than dropped.
|
|
18
|
-
|
|
20
|
+
//
|
|
21
|
+
// Images (#66) split out the same way, a linked image `[](href)`
|
|
22
|
+
// first: tried as a plain link, its label would end at the image's own `]`.
|
|
23
|
+
const LINK_PATTERN = new RegExp(
|
|
24
|
+
String.raw`(\[${IMAGE_SOURCE}\]\(${HREF_SOURCE}\)|${IMAGE_SOURCE}|\[[^\]]+\]\(${HREF_SOURCE}\))`,
|
|
25
|
+
'g',
|
|
26
|
+
);
|
|
27
|
+
const LINKED_IMAGE = new RegExp(String.raw`^\[(${IMAGE_SOURCE})\]\((${HREF_SOURCE})\)$`);
|
|
28
|
+
const LINK = new RegExp(String.raw`^\[([^\]]+)\]\((${HREF_SOURCE})\)$`);
|
|
19
29
|
|
|
20
30
|
// `<strong>`'s UA default `font-weight: bolder` is RELATIVE — inside
|
|
21
31
|
// `font-light` (300) copy it computes to 400 and the bold is invisible. An
|
|
@@ -135,7 +145,18 @@ function renderRichTextNodes(text: string, opts?: RichTextOptions): ReactNode[]
|
|
|
135
145
|
for (let i = 0; i < parts.length; i++) {
|
|
136
146
|
const part = parts[i];
|
|
137
147
|
if (!part) continue;
|
|
138
|
-
const
|
|
148
|
+
const image = renderInlineImage(part, `i-${i}`);
|
|
149
|
+
if (image) {
|
|
150
|
+
out.push(image);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const linked = LINKED_IMAGE.exec(part);
|
|
154
|
+
const linkedImage = linked && renderInlineImage(linked[1], `i-${i}`);
|
|
155
|
+
if (linked && linkedImage && isSafeHref(linked[2])) {
|
|
156
|
+
out.push(linksAllowed ? anchor(linked[2], linkedImage, `l-${i}`) : linkedImage);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const match = LINK.exec(part);
|
|
139
160
|
if (match && isSafeHref(match[2])) {
|
|
140
161
|
const [, label, href] = match;
|
|
141
162
|
// Inside an `<a>`/`<button>`/`<summary>` an anchor can't be nested, so
|
|
@@ -145,19 +166,7 @@ function renderRichTextNodes(text: string, opts?: RichTextOptions): ReactNode[]
|
|
|
145
166
|
out.push(...renderEmphasis(label, `u-${i}`, opts));
|
|
146
167
|
continue;
|
|
147
168
|
}
|
|
148
|
-
|
|
149
|
-
// same new-tab + noopener treatment as absolute http(s) links.
|
|
150
|
-
const external = /^(?:https?:)?\/\//.test(href);
|
|
151
|
-
out.push(
|
|
152
|
-
<a
|
|
153
|
-
key={`l-${i}`}
|
|
154
|
-
href={href}
|
|
155
|
-
className="underline underline-offset-2 text-[color:var(--pb-prose-link-color,inherit)]"
|
|
156
|
-
{...(external ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
|
|
157
|
-
>
|
|
158
|
-
{renderEmphasis(label, `l-${i}`, opts)}
|
|
159
|
-
</a>,
|
|
160
|
-
);
|
|
169
|
+
out.push(anchor(href, renderEmphasis(label, `l-${i}`, opts), `l-${i}`));
|
|
161
170
|
continue;
|
|
162
171
|
}
|
|
163
172
|
out.push(...renderEmphasis(part, `t-${i}`, opts));
|
|
@@ -165,6 +174,22 @@ function renderRichTextNodes(text: string, opts?: RichTextOptions): ReactNode[]
|
|
|
165
174
|
return out;
|
|
166
175
|
}
|
|
167
176
|
|
|
177
|
+
function anchor(href: string, children: ReactNode, key: string): ReactNode {
|
|
178
|
+
// Scheme-relative `//host/...` is off-site too — it must get the
|
|
179
|
+
// same new-tab + noopener treatment as absolute http(s) links.
|
|
180
|
+
const external = /^(?:https?:)?\/\//.test(href);
|
|
181
|
+
return (
|
|
182
|
+
<a
|
|
183
|
+
key={key}
|
|
184
|
+
href={href}
|
|
185
|
+
className="underline underline-offset-2 text-[color:var(--pb-prose-link-color,inherit)]"
|
|
186
|
+
{...(external ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
|
|
187
|
+
>
|
|
188
|
+
{children}
|
|
189
|
+
</a>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
168
193
|
export type RichTextBlockProps = {
|
|
169
194
|
text: string | undefined;
|
|
170
195
|
className?: string;
|
|
@@ -224,12 +249,11 @@ function renderWithSoftBreaks(text: string): ReactNode[] {
|
|
|
224
249
|
function renderBlock(block: MarkdownBlock, key: number): ReactNode {
|
|
225
250
|
if (block.type === 'ul') {
|
|
226
251
|
return (
|
|
227
|
-
<
|
|
228
|
-
{
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
</ul>
|
|
252
|
+
<MarkdownList
|
|
253
|
+
key={key}
|
|
254
|
+
items={block.items}
|
|
255
|
+
className="list-disc pl-5 [&:not(:first-child)]:mt-3"
|
|
256
|
+
/>
|
|
233
257
|
);
|
|
234
258
|
}
|
|
235
259
|
return (
|
|
@@ -7,6 +7,7 @@ import { parseMarkdownBlocks } from '../../utils/markdown';
|
|
|
7
7
|
import { cn } from '../../utils/widgetUtils';
|
|
8
8
|
import { AccentText } from './_internal/accent-text';
|
|
9
9
|
import { DisclosureChevron } from './_internal/disclosure-chevron';
|
|
10
|
+
import { MarkdownList } from './_internal/markdown-list';
|
|
10
11
|
import { RichTextBlock, renderRichText } from './_internal/rich-text';
|
|
11
12
|
import { eyebrowTextStyle } from './_shared';
|
|
12
13
|
|
|
@@ -59,13 +60,12 @@ function Answer({ text, inverse }: { text: string; inverse?: boolean }) {
|
|
|
59
60
|
>
|
|
60
61
|
{parseMarkdownBlocks(text || '').map((block, i) =>
|
|
61
62
|
block.type === 'ul' ? (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
</ul>
|
|
63
|
+
<MarkdownList
|
|
64
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: blocks are positional slices of one string, re-derived each render
|
|
65
|
+
key={i}
|
|
66
|
+
items={block.items}
|
|
67
|
+
className="list-disc pl-5 [&:not(:first-child)]:mt-3"
|
|
68
|
+
/>
|
|
69
69
|
) : (
|
|
70
70
|
// biome-ignore lint/suspicious/noArrayIndexKey: blocks are positional slices of one string, re-derived each render
|
|
71
71
|
<p key={i} className="[&:not(:first-child)]:mt-3">
|
|
@@ -160,7 +160,9 @@ function SplitFaq({
|
|
|
160
160
|
>
|
|
161
161
|
{renderRichText(eyebrow)}
|
|
162
162
|
</p>
|
|
163
|
-
|
|
163
|
+
{/* min-w-0: a grid item's `min-width: auto` let a wide Markdown image
|
|
164
|
+
in an answer push the 2fr track past the coloured band. */}
|
|
165
|
+
<div className="min-w-0 max-w-[var(--pb-split-content-max,none)]">
|
|
164
166
|
<div className="max-w-[var(--pb-faq-intro-max,none)]">
|
|
165
167
|
{/* AccentText, not bare renderRichText: these are display headings
|
|
166
168
|
on `--pb-display-weight`, where a plain <strong>'s relative
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { MarkdownWidget } from './markdown-widget';
|
|
6
|
+
|
|
7
|
+
const Markdown = MarkdownWidget.render as unknown as (
|
|
8
|
+
props: Record<string, unknown>,
|
|
9
|
+
) => ReactElement;
|
|
10
|
+
|
|
11
|
+
function html(content: string): string {
|
|
12
|
+
return renderToStaticMarkup(<Markdown {...MarkdownWidget.defaultProps} content={content} />);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// #66: content seeded from existing Markdown (a partners page of logos)
|
|
16
|
+
// rendered `` as literal text and flattened nested lists.
|
|
17
|
+
describe('MarkdownWidget images', () => {
|
|
18
|
+
it('renders an image', () => {
|
|
19
|
+
const out = html('');
|
|
20
|
+
expect(out).toContain('<img');
|
|
21
|
+
expect(out).toContain('src="/media/acme.png"');
|
|
22
|
+
expect(out).toContain('alt="Acme logo"');
|
|
23
|
+
expect(out).not.toContain('](https://acme.example)');
|
|
28
|
+
expect(out).toMatch(
|
|
29
|
+
/<a [^>]*href="https:\/\/acme\.example"[^>]*><img [^>]*src="\/media\/acme\.png"/,
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('keeps several images on one line in one paragraph', () => {
|
|
34
|
+
const out = html(' ');
|
|
35
|
+
expect(out.match(/<img /g)).toHaveLength(2);
|
|
36
|
+
expect(out.match(/<p /g)).toHaveLength(1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('accepts an empty alt', () => {
|
|
40
|
+
expect(html('')).toContain('alt=""');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('leaves an unsafe src as visible text, like an unsafe link', () => {
|
|
44
|
+
for (const src of ['javascript:alert(1)', 'data:image/svg+xml,x']) {
|
|
45
|
+
const out = html(``);
|
|
46
|
+
expect(out).not.toContain('<img');
|
|
47
|
+
expect(out).toContain(``);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('does not wrap an image in a link whose href is unsafe', () => {
|
|
52
|
+
const out = html('[](javascript:alert(1))');
|
|
53
|
+
expect(out).not.toContain('href="javascript');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('still renders plain links', () => {
|
|
57
|
+
expect(html('[Docs](/docs)')).toMatch(/<a [^>]*href="\/docs"[^>]*>Docs<\/a>/);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('MarkdownWidget nested lists', () => {
|
|
62
|
+
it('renders an indented bullet as a nested list', () => {
|
|
63
|
+
const out = html('- Partners\n - Gold\n - Silver\n- Press');
|
|
64
|
+
expect(out).toMatch(
|
|
65
|
+
/<li>Partners<ul [^>]*><li>Gold<\/li><li>Silver<\/li><\/ul><\/li><li>Press<\/li>/,
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -2,6 +2,7 @@ import type { ComponentConfig } from '@puckeditor/core';
|
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { keys } from '../../utils/i18n';
|
|
4
4
|
import { parseMarkdownBlocks as renderMarkdown } from '../../utils/markdown';
|
|
5
|
+
import { MarkdownList } from './_internal/markdown-list';
|
|
5
6
|
import { renderRichText } from './_internal/rich-text';
|
|
6
7
|
|
|
7
8
|
export type MarkdownWidgetProps = {
|
|
@@ -128,13 +129,12 @@ function MarkdownRender({ content, width = 'auto', indent = 'none' }: MarkdownWi
|
|
|
128
129
|
);
|
|
129
130
|
if (block.type === 'ul')
|
|
130
131
|
return (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
</ul>
|
|
132
|
+
<MarkdownList
|
|
133
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: author-ordered array with no stable id; content repeats, so a content key collides
|
|
134
|
+
key={idx}
|
|
135
|
+
items={block.items}
|
|
136
|
+
className="list-disc list-inside space-y-1 mb-4"
|
|
137
|
+
/>
|
|
138
138
|
);
|
|
139
139
|
return (
|
|
140
140
|
// biome-ignore lint/suspicious/noArrayIndexKey: author-ordered array with no stable id; content repeats, so a content key collides
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ComponentConfig } from '@puckeditor/core';
|
|
2
|
+
import type { CSSProperties } from 'react';
|
|
2
3
|
import { keys } from '../../utils/i18n';
|
|
3
4
|
import { cn } from '../../utils/widgetUtils';
|
|
4
5
|
import { renderRichText } from './_internal/rich-text';
|
|
@@ -10,6 +11,18 @@ export type QuoteWidgetProps = {
|
|
|
10
11
|
align: 'left' | 'center';
|
|
11
12
|
};
|
|
12
13
|
|
|
14
|
+
// Colours come from the renderer's `--pb-*` tokens rather than a fixed palette,
|
|
15
|
+
// so the quote follows the page's theme whether or not it toggles `.dark` —
|
|
16
|
+
// a dark branded page would otherwise get dark-grey text on its own navy.
|
|
17
|
+
// The tint is mixed from the accent, so it reads on either background.
|
|
18
|
+
const FIGURE_STYLE: CSSProperties = {
|
|
19
|
+
borderColor: 'var(--pb-accent, var(--primary))',
|
|
20
|
+
backgroundColor: 'color-mix(in srgb, var(--pb-accent, var(--primary)) 8%, transparent)',
|
|
21
|
+
};
|
|
22
|
+
const CAPTION_STYLE: CSSProperties = {
|
|
23
|
+
color: 'var(--pb-caption-color, var(--pb-body-color, var(--muted-foreground)))',
|
|
24
|
+
};
|
|
25
|
+
|
|
13
26
|
export const QuoteWidget: ComponentConfig<QuoteWidgetProps> = {
|
|
14
27
|
label: keys.pagebuilder.blocks.quote.label,
|
|
15
28
|
fields: {
|
|
@@ -34,15 +47,19 @@ export const QuoteWidget: ComponentConfig<QuoteWidgetProps> = {
|
|
|
34
47
|
render: ({ quote, author, source, align }) => (
|
|
35
48
|
<figure
|
|
36
49
|
className={cn(
|
|
37
|
-
'max-w-3xl mx-auto px-4 py-10 border-l-4
|
|
50
|
+
'max-w-3xl mx-auto px-4 py-10 border-l-4 rounded-r-lg',
|
|
38
51
|
align === 'center' ? 'text-center' : 'text-left',
|
|
39
52
|
)}
|
|
53
|
+
style={FIGURE_STYLE}
|
|
40
54
|
>
|
|
41
|
-
<blockquote
|
|
55
|
+
<blockquote
|
|
56
|
+
className="text-xl sm:text-2xl italic leading-relaxed"
|
|
57
|
+
style={{ color: 'var(--pb-heading-color, var(--foreground))' }}
|
|
58
|
+
>
|
|
42
59
|
“{renderRichText(quote)}”
|
|
43
60
|
</blockquote>
|
|
44
61
|
{(author || source) && (
|
|
45
|
-
<figcaption className="mt-4
|
|
62
|
+
<figcaption className="mt-4" style={CAPTION_STYLE}>
|
|
46
63
|
{author && <span className="font-semibold">— {renderRichText(author)}</span>}
|
|
47
64
|
{source && <span className="ml-2 text-sm">({renderRichText(source)})</span>}
|
|
48
65
|
</figcaption>
|
|
@@ -112,7 +112,7 @@ export const SectionIntroWidget: ComponentConfig<SectionIntroWidgetProps> = {
|
|
|
112
112
|
{renderRichText(eyebrow)}
|
|
113
113
|
</p>
|
|
114
114
|
)}
|
|
115
|
-
<div className={eyebrow
|
|
115
|
+
<div className={cn('min-w-0', !eyebrow && 'md:col-span-2')}>{content}</div>
|
|
116
116
|
</div>
|
|
117
117
|
</section>
|
|
118
118
|
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Locale switcher and auth-aware CTA for the SiteHeader widget. */
|
|
2
|
+
|
|
3
|
+
import { usePage } from '@inertiajs/react';
|
|
4
|
+
import {
|
|
5
|
+
LocaleSwitcher,
|
|
6
|
+
useHasMultipleLocales,
|
|
7
|
+
} from '@simple-module-py/ui/components/LocaleSwitcher';
|
|
8
|
+
|
|
9
|
+
type AuthSharedProps = {
|
|
10
|
+
auth?: { isAuthenticated?: boolean } | null;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Whether the visitor has a session, from the `auth` shared prop the framework
|
|
15
|
+
* layouts read. The header only mounts inside an Inertia page; the guard keeps
|
|
16
|
+
* a bare render (a unit test, a static preview) on the anonymous branch rather
|
|
17
|
+
* than throwing, so a header that never set the new props renders as before.
|
|
18
|
+
*/
|
|
19
|
+
export function useIsSignedIn(): boolean {
|
|
20
|
+
try {
|
|
21
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: usePage throws outside Inertia, after reading its context, so the hook order is unchanged
|
|
22
|
+
return Boolean(usePage<AuthSharedProps>().props.auth?.isAuthenticated);
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The CTA the visitor should see: the signed-in variant only when it is filled in. */
|
|
29
|
+
export function resolveCta(
|
|
30
|
+
signedIn: boolean,
|
|
31
|
+
cta: { label: string; href: string },
|
|
32
|
+
signedInCta: { label?: string; href?: string },
|
|
33
|
+
): { label: string; href: string } {
|
|
34
|
+
if (signedIn && signedInCta.label) {
|
|
35
|
+
return { label: signedInCta.label, href: signedInCta.href || cta.href };
|
|
36
|
+
}
|
|
37
|
+
return cta;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The shared switcher, hidden on a single-locale install where it would be an
|
|
42
|
+
* inert pill. It switches the UI locale; it does not jump to a translated
|
|
43
|
+
* page, because the shared control has no hook for a per-page target.
|
|
44
|
+
*/
|
|
45
|
+
export function HeaderLocaleSwitcher({ show }: { show: boolean }) {
|
|
46
|
+
const multiple = useHasMultipleLocales();
|
|
47
|
+
if (!show || !multiple) return null;
|
|
48
|
+
return (
|
|
49
|
+
<div className="ml-auto mr-2 flex items-center lg:ml-0 lg:mr-0">
|
|
50
|
+
<LocaleSwitcher />
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
4
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
|
|
6
|
+
let shared: Record<string, unknown> = {};
|
|
7
|
+
vi.mock('@inertiajs/react', () => ({
|
|
8
|
+
usePage: () => ({ props: shared }),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
// The framework ui package ships JSX sources compiled with the classic runtime
|
|
12
|
+
// under vitest, so its components expect a global React.
|
|
13
|
+
(globalThis as { React?: unknown }).React = React;
|
|
14
|
+
|
|
15
|
+
import type { SiteHeaderWidgetProps } from './site-header-widget';
|
|
16
|
+
|
|
17
|
+
const { SiteHeaderRender, SiteHeaderWidget } = await import('./site-header-widget');
|
|
18
|
+
const { resolveCta } = await import('./site-header-account');
|
|
19
|
+
|
|
20
|
+
const base: Record<string, unknown> = {
|
|
21
|
+
...(SiteHeaderWidget.defaultProps as object),
|
|
22
|
+
ctaLabel: 'Sign in',
|
|
23
|
+
ctaHref: '/users/login',
|
|
24
|
+
};
|
|
25
|
+
const i18n = (supportedLocales: string[]) => ({
|
|
26
|
+
locale: 'en',
|
|
27
|
+
supportedLocales,
|
|
28
|
+
messages: {},
|
|
29
|
+
});
|
|
30
|
+
const render = (props: Record<string, unknown> = {}) =>
|
|
31
|
+
renderToStaticMarkup(
|
|
32
|
+
<SiteHeaderRender {...({ ...base, ...props } as unknown as SiteHeaderWidgetProps)} />,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
shared = { auth: { isAuthenticated: false }, i18n: i18n(['en', 'fr']) };
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('SiteHeader locale switcher', () => {
|
|
40
|
+
it('is hidden unless showLocaleSwitcher is set', () => {
|
|
41
|
+
expect(render()).not.toContain('/i18n/set-locale');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('renders the shared switcher when enabled on a multi-locale install', () => {
|
|
45
|
+
const out = render({ showLocaleSwitcher: true });
|
|
46
|
+
expect(out).toContain('/i18n/set-locale');
|
|
47
|
+
expect(out).toContain('>EN<');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('stays hidden on a single-locale install', () => {
|
|
51
|
+
shared = { auth: {}, i18n: i18n(['en']) };
|
|
52
|
+
expect(render({ showLocaleSwitcher: true })).not.toContain('>EN<');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('exposes the toggle as an editor field defaulting to off', () => {
|
|
56
|
+
expect(SiteHeaderWidget.fields).toHaveProperty('showLocaleSwitcher');
|
|
57
|
+
expect(SiteHeaderWidget.defaultProps?.showLocaleSwitcher).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('SiteHeader auth-aware CTA', () => {
|
|
62
|
+
const props = { signedInLabel: 'Dashboard', signedInHref: '/dashboard/' };
|
|
63
|
+
|
|
64
|
+
it('shows the anonymous CTA to a visitor', () => {
|
|
65
|
+
const out = render(props);
|
|
66
|
+
expect(out).toContain('Sign in');
|
|
67
|
+
expect(out).not.toContain('Dashboard');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('switches to the signed-in label and link with a session', () => {
|
|
71
|
+
shared = { auth: { isAuthenticated: true } };
|
|
72
|
+
const out = render(props);
|
|
73
|
+
expect(out).toContain('Dashboard');
|
|
74
|
+
expect(out).toContain('href="/dashboard/"');
|
|
75
|
+
expect(out).not.toContain('>Sign in<');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('keeps the CTA for a signed-in visitor when no signed-in label is set', () => {
|
|
79
|
+
shared = { auth: { isAuthenticated: true } };
|
|
80
|
+
expect(render()).toContain('>Sign in<');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('falls back to the CTA link when only the label is set', () => {
|
|
84
|
+
expect(resolveCta(true, { label: 'Sign in', href: '/x' }, { label: 'Hi', href: '' })).toEqual({
|
|
85
|
+
label: 'Hi',
|
|
86
|
+
href: '/x',
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|