├── .nvmrc
├── .prettierrc.json
├── .env.example
├── public
├── robots.txt
├── js_snippets_before_body_end.js
├── _redirects
├── js_snippets_head.js
├── _headers
└── _headersCsp.json
├── .gitignore
├── src
├── assets
│ ├── stylesheets
│ │ ├── bootstrap5
│ │ │ ├── helpers
│ │ │ │ ├── _clearfix.scss
│ │ │ │ ├── _text-truncation.scss
│ │ │ │ ├── _visually-hidden.scss
│ │ │ │ ├── _vr.scss
│ │ │ │ ├── _stretched-link.scss
│ │ │ │ ├── _stacks.scss
│ │ │ │ ├── _colored-links.scss
│ │ │ │ ├── _ratio.scss
│ │ │ │ └── _position.scss
│ │ │ ├── mixins
│ │ │ │ ├── _clearfix.scss
│ │ │ │ ├── _lists.scss
│ │ │ │ ├── _color-scheme.scss
│ │ │ │ ├── _text-truncate.scss
│ │ │ │ ├── _resize.scss
│ │ │ │ ├── _container.scss
│ │ │ │ ├── _alert.scss
│ │ │ │ ├── _backdrop.scss
│ │ │ │ ├── _image.scss
│ │ │ │ ├── _box-shadow.scss
│ │ │ │ ├── _reset-text.scss
│ │ │ │ ├── _list-group.scss
│ │ │ │ ├── _deprecate.scss
│ │ │ │ ├── _transition.scss
│ │ │ │ ├── _pagination.scss
│ │ │ │ ├── _table-variants.scss
│ │ │ │ └── _visually-hidden.scss
│ │ │ ├── forms
│ │ │ │ ├── _form-text.scss
│ │ │ │ ├── _validation.scss
│ │ │ │ └── _labels.scss
│ │ │ ├── _forms.scss
│ │ │ ├── _helpers.scss
│ │ │ ├── bootstrap-utilities.scss
│ │ │ ├── bootstrap-reboot.scss
│ │ │ ├── _transitions.scss
│ │ │ ├── _badge.scss
│ │ │ ├── _grid.scss
│ │ │ ├── _mixins.scss
│ │ │ ├── _breadcrumb.scss
│ │ │ ├── _placeholders.scss
│ │ │ ├── _close.scss
│ │ │ ├── _images.scss
│ │ │ ├── bootstrap.scss
│ │ │ └── _containers.scss
│ │ ├── _variables.scss
│ │ ├── fontawesome
│ │ │ ├── _fixed-width.scss
│ │ │ ├── _screen-reader.scss
│ │ │ ├── _larger.scss
│ │ │ ├── _list.scss
│ │ │ ├── _core.scss
│ │ │ ├── _stacked.scss
│ │ │ ├── _animated.scss
│ │ │ ├── _rotated-flipped.scss
│ │ │ ├── _bordered-pulled.scss
│ │ │ └── _path.scss
│ │ ├── variables
│ │ │ └── _responsive.scss
│ │ ├── _mixins.scss
│ │ └── _fontawesome.scss
│ ├── images
│ │ ├── favicon.png
│ │ ├── arrow_next.svg
│ │ ├── arrow_prev.svg
│ │ ├── button_widget.svg
│ │ ├── video_widget.svg
│ │ ├── divider_widget.svg
│ │ ├── redirect_obj.svg
│ │ ├── testimonial_widget.svg
│ │ ├── icon_widget.svg
│ │ ├── feature_panel_widget.svg
│ │ ├── section_widget.svg
│ │ ├── tick_list_widget.svg
│ │ ├── space_widget.svg
│ │ ├── cookie_consent_icon.svg
│ │ └── tick_list_item_widget.svg
│ └── fonts
│ │ ├── Manrope-Bold-700.woff2
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.ttf
│ │ ├── Manrope-Medium-500.woff2
│ │ ├── fontawesome-webfont.woff
│ │ └── fontawesome-webfont.woff2
├── tracking.js
├── Widgets
│ ├── FormContainerWidget
│ │ ├── utils
│ │ │ ├── isCustomType.js
│ │ │ ├── getFieldName.js
│ │ │ ├── validations
│ │ │ │ ├── insideFormContainerValidation.js
│ │ │ │ ├── typeValidation.js
│ │ │ │ └── customFieldNameValidation.js
│ │ │ ├── pseudoRandom32CharHex.js
│ │ │ ├── scrollIntoView.js
│ │ │ ├── getFormContainer.js
│ │ │ └── isFieldNameUnique.js
│ │ ├── FormContainerWidgetClass.js
│ │ ├── FormContainerWidget.scss
│ │ └── FormIdComponent.js
│ ├── VimeoVideoWidget
│ │ ├── VimeoVideoWidget.scss
│ │ └── VimeoVideoWidgetClass.js
│ ├── YoutubeVideoWidget
│ │ ├── YoutubeVideoWidget.scss
│ │ └── YoutubeVideoWidgetClass.js
│ ├── SpaceWidget
│ │ ├── SpaceWidgetClass.js
│ │ ├── SpaceWidgetComponent.js
│ │ └── SpaceWidgetEditingConfig.js
│ ├── editingConfigs.js
│ ├── DividerWidget
│ │ ├── DividerWidgetClass.js
│ │ ├── DividerWidgetComponent.js
│ │ ├── DividerWidgetEditingConfig.js
│ │ └── DividerWidget.scss
│ ├── index.js
│ ├── LinkWidget
│ │ ├── LinkWidgetClass.js
│ │ ├── LinkWidgetEditingConfig.js
│ │ └── LinkWidgetComponent.js
│ ├── GalleryWidget
│ │ ├── GalleryWidgetClass.js
│ │ └── GalleryWidgetEditingConfig.js
│ ├── GroupWidget
│ │ ├── GroupWidgetComponent.js
│ │ ├── GroupWidgetClass.js
│ │ └── GroupWidgetEditingConfig.js
│ ├── JobOverviewWidget
│ │ ├── JobOverviewWidgetClass.js
│ │ └── JobOverviewWidgetEditingConfig.js
│ ├── FactWidget
│ │ ├── FactWidgetClass.js
│ │ ├── FactWidgetComponent.js
│ │ ├── FactWidgetEditingConfig.js
│ │ └── FactWidget.scss
│ ├── VideoWidget
│ │ ├── VideoWidgetClass.js
│ │ ├── videoPlaceholder.js
│ │ ├── VideoWidgetEditingConfig.js
│ │ └── VideoWidgetComponent.js
│ ├── TickListWidget
│ │ ├── TickListWidgetClass.js
│ │ ├── TickListWidgetComponent.js
│ │ ├── TickListWidget.scss
│ │ └── TickListWidgetEditingConfig.js
│ ├── ColumnWidget
│ │ ├── ColumnWidgetEditingConfig.js
│ │ └── ColumnWidgetClass.js
│ ├── IconContainerWidget
│ │ ├── IconContainerWidgetClass.js
│ │ ├── IconContainerWidgetEditingConfig.js
│ │ └── IconContainerWidgetComponent.js
│ ├── PricingSpecWidget
│ │ ├── PricingSpecWidgetEditingConfig.js
│ │ ├── PricingSpecWidgetClass.js
│ │ └── PricingSpecWidgetComponent.js
│ ├── TextWidget
│ │ ├── TextWidgetClass.js
│ │ ├── TextWidgetComponent.js
│ │ └── TextWidgetEditingConfig.js
│ ├── LinkContainerWidget
│ │ ├── LinkContainerWidgetClass.js
│ │ ├── LinkContainerWidgetComponent.js
│ │ ├── LinkContainerWidget.scss
│ │ └── LinkContainerWidgetEditingConfig.js
│ ├── TestimonialSliderWidget
│ │ ├── TestimonialSliderWidgetClass.js
│ │ └── TestimonialSliderWidgetEditingConfig.js
│ ├── TickListItemWidget
│ │ ├── TickListItemWidgetComponent.js
│ │ ├── TickListItemWidgetClass.js
│ │ └── TickListItemWidgetEditingConfig.js
│ ├── EventOverviewWidget
│ │ ├── EventOverviewWidgetClass.js
│ │ └── EventOverviewWidgetEditingConfig.js
│ ├── TableRowWidget
│ │ ├── TableRowWidgetEditingConfig.js
│ │ ├── TableRowWidgetClass.js
│ │ └── TableRowWidgetComponent.js
│ ├── BoxWidget
│ │ ├── BoxWidgetClass.js
│ │ ├── BoxWidgetComponent.js
│ │ └── BoxWidgetEditingConfig.js
│ ├── BlogOverviewWidget
│ │ ├── BlogOverviewWidgetClass.js
│ │ ├── BlogOverviewWidgetComponent.js
│ │ └── BlogOverviewWidgetEditingConfig.js
│ ├── ButtonWidget
│ │ ├── ButtonWidgetClass.js
│ │ └── ButtonWidgetComponent.js
│ ├── FormHiddenFieldWidget
│ │ ├── FormHiddenFieldWidgetClass.js
│ │ └── FormHiddenFieldWidgetComponent.js
│ ├── PriceWidget
│ │ ├── PriceWidgetClass.js
│ │ ├── PriceWidgetEditingConfig.js
│ │ ├── PriceWidget.scss
│ │ └── PriceWidgetComponent.js
│ ├── ThumbnailGalleryWidget
│ │ ├── ThumbnailGalleryWidgetClass.js
│ │ └── ThumbnailGalleryWidgetEditingConfig.js
│ ├── FeaturePanelWidget
│ │ ├── FeaturePanelWidgetClass.js
│ │ ├── FeaturePanelWidgetComponent.js
│ │ └── FeaturePanelWidgetEditingConfig.js
│ ├── FormButtonWidget
│ │ ├── FormButtonWidgetClass.js
│ │ ├── FormButtonWidgetComponent.js
│ │ └── FormButtonWidgetEditingConfig.js
│ ├── TableWidget
│ │ └── TableWidgetClass.js
│ ├── IconWidget
│ │ ├── IconWidgetClass.js
│ │ └── IconWidgetComponent.js
│ ├── CarouselWidget
│ │ ├── CarouselWidgetClass.js
│ │ └── CarouselWidgetEditingConfig.js
│ ├── ColumnContainerWidget
│ │ ├── ColumnContainerWidgetClass.js
│ │ ├── ColumnContainerWidgetEditingConfig.js
│ │ └── ColumnContainerWidgetComponent.js
│ ├── TestimonialWidget
│ │ └── TestimonialWidgetClass.js
│ ├── ThumbnailGalleryImageWidget
│ │ ├── ThumbnailGalleryImageWidgetClass.js
│ │ └── ThumbnailGalleryImageWidgetEditingConfig.js
│ ├── HeadlineWidget
│ │ ├── HeadlineWidgetClass.js
│ │ └── HeadlineWidgetComponent.js
│ ├── ImageWidget
│ │ ├── ImageWidgetClass.js
│ │ └── ImageWidgetComponent.js
│ ├── FormCheckboxWidget
│ │ └── FormCheckboxWidgetClass.js
│ ├── SectionWidget
│ │ ├── SectionWidgetClass.js
│ │ └── SectionWidgetComponent.js
│ ├── FormInputFieldWidget
│ │ └── FormInputFieldWidgetClass.js
│ ├── AddressWidget
│ │ └── AddressWidgetClass.js
│ ├── GoogleMapsWidget
│ │ ├── GoogleMapsWidgetClass.js
│ │ └── GoogleMapsWidget.scss
│ └── PricingWidget
│ │ └── PricingWidgetClass.js
├── Objs
│ ├── RedirectToUi
│ │ ├── RedirectToUiObjClass.js
│ │ ├── RedirectToUiEditingConfig.js
│ │ └── RedirectToUiComponent.js
│ ├── editingConfigs.js
│ ├── Video
│ │ ├── VideoObjClass.js
│ │ └── VideoEditingConfig.js
│ ├── index.js
│ ├── Redirect
│ │ ├── RedirectObjClass.js
│ │ ├── RedirectEditingConfig.js
│ │ └── RedirectComponent.js
│ ├── Page
│ │ ├── PageComponent.js
│ │ ├── PageObjClass.js
│ │ └── PageEditingConfig.js
│ ├── Homepage
│ │ ├── HomepageComponent.js
│ │ └── HomepageObjClass.js
│ ├── LandingPage
│ │ ├── LandingPageComponent.js
│ │ ├── LandingPageObjClass.js
│ │ └── LandingPageEditingConfig.js
│ ├── Image
│ │ ├── ImageObjClass.js
│ │ └── ImageEditingConfig.js
│ ├── Download
│ │ ├── DownloadObjClass.js
│ │ └── DownloadEditingConfig.js
│ ├── SearchResults
│ │ ├── SearchResultsObjClass.js
│ │ ├── SearchResultsTagList.js
│ │ ├── ShowMoreButton.js
│ │ ├── SearchResultsEditingConfig.js
│ │ └── SearchResultItem.scss
│ ├── Author
│ │ ├── AuthorObjClass.js
│ │ ├── AuthorEditingConfig.js
│ │ └── AuthorComponent.js
│ ├── Blog
│ │ ├── BlogObjClass.js
│ │ ├── BlogComponent.js
│ │ └── BlogEditingConfig.js
│ ├── _defaultPageAttributes.js
│ ├── _metadataAttributes.js
│ ├── BlogPost
│ │ └── BlogPostObjClass.js
│ ├── Event
│ │ └── EventObjClass.js
│ └── Job
│ │ └── JobObjClass.js
├── prerenderContent
│ ├── filenameFromUrl.js
│ ├── reportError.js
│ ├── contentHash.js
│ ├── generatePreloadDump.js
│ ├── storeResult.js
│ ├── generateHtml.js
│ └── extendRedirects.js
├── utils
│ ├── isImageObj.js
│ ├── alignmentClassName.js
│ ├── googleMapsApiKey.js
│ ├── formatDate.js
│ ├── navigateToBlogWithTag.js
│ ├── placeholderCss.js
│ ├── urlFromBinaryObj.js
│ └── isVideoObj.js
├── Components
│ ├── WrapIfClassName.js
│ ├── ScrivitoExtensions
│ │ ├── index.js
│ │ └── IconEditorTab
│ │ │ ├── SingleIcon.js
│ │ │ └── IconSearchResults.js
│ ├── Navigation
│ │ ├── LandingPageNavigation.js
│ │ ├── ScrollToNextSectionLink.js
│ │ ├── NavigationSection.js
│ │ ├── CollapseToggle.js
│ │ └── Logo.js
│ ├── SchemaDotOrg
│ │ ├── dataFromAuthor.js
│ │ ├── dataFromBlog.js
│ │ ├── dataFromAddressWidget.js
│ │ ├── dataFromBlogPost.js
│ │ ├── dataFromEvent.js
│ │ └── dataFromJob.js
│ ├── InPlaceEditingPlaceholder.js
│ ├── BlogPost
│ │ ├── BlogPostDate.js
│ │ ├── BlogPostMorePosts.js
│ │ └── BlogPostTagList.js
│ ├── Tracking.js
│ ├── AnimateOnReveal.js
│ ├── Icon.js
│ ├── Footer.js
│ ├── AuthorImage.js
│ ├── CurrentPageMetadata.js
│ └── CookieConsentContext.js
├── config
│ ├── objClassForContentType.js
│ ├── windowScrivito.js
│ ├── index.js
│ ├── history.js
│ └── scrivito.js
├── scrivito_extensions.js
├── _scrivito_extensions.html
├── catch_all_index.html
└── index.js
├── generator-scrivito
├── generators
│ ├── obj
│ │ └── templates
│ │ │ ├── X.scss.ejs
│ │ │ ├── XComponent.js.ejs
│ │ │ ├── XObjClass.js.ejs
│ │ │ └── XEditingConfig.js.ejs
│ └── widget
│ │ └── templates
│ │ ├── X.scss.ejs
│ │ ├── XWidgetEditingConfig.js.ejs
│ │ ├── XWidgetClass.js.ejs
│ │ └── XWidgetComponent.js.ejs
├── package.json
└── app
│ └── index.js
├── netlify.toml
├── .circleci
└── config.yml
└── LICENSE
/.nvmrc:
--------------------------------------------------------------------------------
1 | 18
2 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | SCRIVITO_TENANT=your_scrivito_tenant_id
2 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /scrivito/
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | build.zip
3 | buildNode
4 | buildPrerendered
5 | node_modules
6 | tmp
7 | .env
8 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_clearfix.scss:
--------------------------------------------------------------------------------
1 | .clearfix {
2 | @include clearfix();
3 | }
4 |
--------------------------------------------------------------------------------
/src/tracking.js:
--------------------------------------------------------------------------------
1 | // This file is for executing JavaScript code after the user has given cookie consent.
2 |
--------------------------------------------------------------------------------
/src/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Scrivito/scrivito_example_app_js/HEAD/src/assets/images/favicon.png
--------------------------------------------------------------------------------
/generator-scrivito/generators/obj/templates/X.scss.ejs:
--------------------------------------------------------------------------------
1 | // Styles for <%= objClassName %>
2 |
3 | .<%= cssClassName %> {
4 | }
5 |
--------------------------------------------------------------------------------
/generator-scrivito/generators/widget/templates/X.scss.ejs:
--------------------------------------------------------------------------------
1 | // Styles for <%= widgetClassName %>
2 |
3 | .<%= cssClassName %> {
4 | }
5 |
--------------------------------------------------------------------------------
/src/assets/fonts/Manrope-Bold-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Scrivito/scrivito_example_app_js/HEAD/src/assets/fonts/Manrope-Bold-700.woff2
--------------------------------------------------------------------------------
/src/assets/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Scrivito/scrivito_example_app_js/HEAD/src/assets/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/src/assets/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Scrivito/scrivito_example_app_js/HEAD/src/assets/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Manrope-Medium-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Scrivito/scrivito_example_app_js/HEAD/src/assets/fonts/Manrope-Medium-500.woff2
--------------------------------------------------------------------------------
/src/assets/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Scrivito/scrivito_example_app_js/HEAD/src/assets/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/src/assets/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Scrivito/scrivito_example_app_js/HEAD/src/assets/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_text-truncation.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Text truncation
3 | //
4 |
5 | .text-truncate {
6 | @include text-truncate();
7 | }
8 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/isCustomType.js:
--------------------------------------------------------------------------------
1 | export function isCustomType(widget) {
2 | return !widget.attributeDefinitions().type || widget.get("type") === "custom";
3 | }
4 |
--------------------------------------------------------------------------------
/src/Widgets/VimeoVideoWidget/VimeoVideoWidget.scss:
--------------------------------------------------------------------------------
1 | .vimeo-video-widget--fullsize-iframe {
2 | position: absolute;
3 | top: 0;
4 | left: 0;
5 | width: 100%;
6 | height: 100%;
7 | }
8 |
--------------------------------------------------------------------------------
/src/Objs/RedirectToUi/RedirectToUiObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const RedirectToUi = Scrivito.provideObjClass("RedirectToUi", {
4 | attributes: {},
5 | });
6 |
--------------------------------------------------------------------------------
/src/Widgets/YoutubeVideoWidget/YoutubeVideoWidget.scss:
--------------------------------------------------------------------------------
1 | .youtube-video-widget--fullsize-iframe {
2 | position: absolute;
3 | top: 0;
4 | left: 0;
5 | width: 100%;
6 | height: 100%;
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/_variables.scss:
--------------------------------------------------------------------------------
1 | @import "variables/colors";
2 | @import "variables/responsive";
3 |
4 | $border-radius: 0 !default;
5 | $border-radius-lg: 0 !default;
6 | $border-radius-sm: 0 !default;
7 |
--------------------------------------------------------------------------------
/public/js_snippets_before_body_end.js:
--------------------------------------------------------------------------------
1 | // This file is for executing JavaScript code immediately before the body element is closed.
2 | // Here you can, for example, let third-party code render additional markup.
3 |
--------------------------------------------------------------------------------
/src/Objs/editingConfigs.js:
--------------------------------------------------------------------------------
1 | function importAll(r) {
2 | r.keys().forEach(r);
3 | }
4 |
5 | // import all *EditingConfig.js files under src/Objs/
6 | importAll(require.context("./", true, /EditingConfig\.js$/));
7 |
--------------------------------------------------------------------------------
/src/prerenderContent/filenameFromUrl.js:
--------------------------------------------------------------------------------
1 | export function filenameFromUrl(url) {
2 | const { pathname } = new URL(url);
3 | if (pathname === "/") return "/index.html";
4 |
5 | return `${pathname}.html`;
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/isImageObj.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export function isImageObj(obj) {
4 | return (
5 | obj instanceof Scrivito.Obj && obj.objClass() === "Image" && obj.get("blob")
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/src/Components/WrapIfClassName.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export function WrapIfClassName({ className, children }) {
4 | return className ?
{children}
: children;
5 | }
6 |
--------------------------------------------------------------------------------
/src/Objs/Video/VideoObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const Video = Scrivito.provideObjClass("Video", {
4 | attributes: {
5 | blob: "binary",
6 | tags: "stringlist",
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/src/Objs/index.js:
--------------------------------------------------------------------------------
1 | function importAll(r) {
2 | r.keys().forEach(r);
3 | }
4 |
5 | // import all *ObjClass.js and *Component.js files under src/Objs/
6 | importAll(require.context("./", true, /(ObjClass|Component)\.js$/));
7 |
--------------------------------------------------------------------------------
/src/Widgets/SpaceWidget/SpaceWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const SpaceWidget = Scrivito.provideWidgetClass("SpaceWidget", {
4 | attributes: {
5 | size: "float",
6 | },
7 | });
8 |
--------------------------------------------------------------------------------
/src/Components/ScrivitoExtensions/index.js:
--------------------------------------------------------------------------------
1 | function importAll(r) {
2 | r.keys().forEach(r);
3 | }
4 |
5 | // import all js files under src/Components/ScrivitoExtensions/
6 | importAll(require.context("./", true, /\.js$/));
7 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_visually-hidden.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Visually hidden
3 | //
4 |
5 | .visually-hidden,
6 | .visually-hidden-focusable:not(:focus):not(:focus-within) {
7 | @include visually-hidden();
8 | }
9 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_vr.scss:
--------------------------------------------------------------------------------
1 | .vr {
2 | display: inline-block;
3 | align-self: stretch;
4 | width: 1px;
5 | min-height: 1em;
6 | background-color: currentColor;
7 | opacity: $hr-opacity;
8 | }
9 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_fixed-width.scss:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | @use "sass:math";
4 |
5 | .#{$fa-css-prefix}-fw {
6 | width: math.div(18em, 14);
7 | text-align: center;
8 | }
9 |
--------------------------------------------------------------------------------
/src/Objs/Redirect/RedirectObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const Redirect = Scrivito.provideObjClass("Redirect", {
4 | attributes: {
5 | title: "string",
6 | link: "link",
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/src/Widgets/editingConfigs.js:
--------------------------------------------------------------------------------
1 | function importAll(r) {
2 | r.keys().forEach(r);
3 | }
4 |
5 | // import all *WidgetEditingConfig.js files under src/Widgets/
6 | importAll(require.context("./", true, /WidgetEditingConfig\.js$/));
7 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_screen-reader.scss:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only {
5 | @include sr-only();
6 | }
7 | .sr-only-focusable {
8 | @include sr-only-focusable();
9 | }
10 |
--------------------------------------------------------------------------------
/src/prerenderContent/reportError.js:
--------------------------------------------------------------------------------
1 | export function reportError(message, ...args) {
2 | // Report to your external error tracker here, like Honeybadger or Rollbar.
3 | console.log(` ❌ [reportError] ${message}`, ...args);
4 | }
5 |
--------------------------------------------------------------------------------
/src/Widgets/DividerWidget/DividerWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const DividerWidget = Scrivito.provideWidgetClass("DividerWidget", {
4 | attributes: {
5 | showLogo: "boolean",
6 | },
7 | });
8 |
--------------------------------------------------------------------------------
/src/utils/alignmentClassName.js:
--------------------------------------------------------------------------------
1 | export function alignmentClassName(widgetAlignment) {
2 | if (widgetAlignment === "center") return "text-center";
3 | if (widgetAlignment === "right") return "text-end";
4 |
5 | return null;
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/googleMapsApiKey.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export function googleMapsApiKey() {
4 | const root = Scrivito.Obj.root();
5 | if (!root) return "";
6 |
7 | return root.get("googleMapsApiKey");
8 | }
9 |
--------------------------------------------------------------------------------
/src/Objs/Page/PageComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("Page", ({ page }) => (
5 |
6 | ));
7 |
--------------------------------------------------------------------------------
/src/Widgets/index.js:
--------------------------------------------------------------------------------
1 | function importAll(r) {
2 | r.keys().forEach(r);
3 | }
4 |
5 | // import all *WidgetClass.js and *WidgetComponent.js files under src/Widgets/
6 | importAll(require.context("./", true, /Widget(Class|Component)\.js$/));
7 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_clearfix.scss:
--------------------------------------------------------------------------------
1 | // scss-docs-start clearfix
2 | @mixin clearfix() {
3 | &::after {
4 | display: block;
5 | clear: both;
6 | content: "";
7 | }
8 | }
9 | // scss-docs-end clearfix
10 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_lists.scss:
--------------------------------------------------------------------------------
1 | // Lists
2 |
3 | // Unstyled keeps list items block level, just removes default browser padding and list-style
4 | @mixin list-unstyled {
5 | padding-left: 0;
6 | list-style: none;
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/variables/_responsive.scss:
--------------------------------------------------------------------------------
1 | /* - BS3 variables - */
2 |
3 | $screen-xs-max: 767px;
4 | $screen-sm-min: 768px;
5 | $screen-sm-max: 991px;
6 | $screen-md-min: 992px;
7 | $screen-md-max: 1199px;
8 | $screen-lg-min: 1200px;
9 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | # Global settings applied to the whole site.
2 | # “command” is your build command.
3 | # “publish” is the directory to publish (relative to root of your repo).
4 |
5 | [build]
6 | command = "npm run build"
7 | publish = "build"
8 |
--------------------------------------------------------------------------------
/src/utils/formatDate.js:
--------------------------------------------------------------------------------
1 | import dateFormat from "dateformat";
2 |
3 | export function formatDate(date, format) {
4 | // dateFormat uses Date.now if no date is given.
5 | if (!date) return null;
6 |
7 | return dateFormat(date, format);
8 | }
9 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_color-scheme.scss:
--------------------------------------------------------------------------------
1 | // scss-docs-start mixin-color-scheme
2 | @mixin color-scheme($name) {
3 | @media (prefers-color-scheme: #{$name}) {
4 | @content;
5 | }
6 | }
7 | // scss-docs-end mixin-color-scheme
8 |
--------------------------------------------------------------------------------
/src/Objs/Homepage/HomepageComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("Homepage", ({ page }) => (
5 |
6 | ));
7 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/getFieldName.js:
--------------------------------------------------------------------------------
1 | import { isCustomType } from "./isCustomType";
2 |
3 | export function getFieldName(widget) {
4 | return isCustomType(widget)
5 | ? widget.get("customFieldName")
6 | : widget.get("type");
7 | }
8 |
--------------------------------------------------------------------------------
/src/Widgets/LinkWidget/LinkWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const LinkWidget = Scrivito.provideWidgetClass("LinkWidget", {
4 | onlyInside: "LinkContainerWidget",
5 | attributes: {
6 | link: "link",
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_text-truncate.scss:
--------------------------------------------------------------------------------
1 | // Text truncate
2 | // Requires inline-block or block for proper styling
3 |
4 | @mixin text-truncate() {
5 | overflow: hidden;
6 | text-overflow: ellipsis;
7 | white-space: nowrap;
8 | }
9 |
--------------------------------------------------------------------------------
/src/Objs/LandingPage/LandingPageComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("LandingPage", ({ page }) => (
5 |
6 | ));
7 |
--------------------------------------------------------------------------------
/src/Widgets/GalleryWidget/GalleryWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const GalleryWidget = Scrivito.provideWidgetClass("GalleryWidget", {
4 | attributes: {
5 | images: ["referencelist", { only: ["Image"] }],
6 | },
7 | });
8 |
--------------------------------------------------------------------------------
/src/Widgets/GroupWidget/GroupWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("GroupWidget", ({ widget }) => (
5 |
6 | ));
7 |
--------------------------------------------------------------------------------
/src/Objs/Image/ImageObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const Image = Scrivito.provideObjClass("Image", {
4 | attributes: {
5 | blob: "binary",
6 | tags: "stringlist",
7 | alternativeText: "string",
8 | },
9 | });
10 |
--------------------------------------------------------------------------------
/src/Widgets/GroupWidget/GroupWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const GroupWidget = Scrivito.provideWidgetClass("GroupWidget", {
4 | attributes: {
5 | content: "widgetlist",
6 | },
7 | extractTextAttributes: ["content"],
8 | });
9 |
--------------------------------------------------------------------------------
/src/utils/navigateToBlogWithTag.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export function navigateToBlogWithTag(tag) {
4 | const params = {};
5 | if (tag) params.tag = tag;
6 |
7 | Scrivito.navigateTo(() => Scrivito.Obj.getByPermalink("blog"), params);
8 | }
9 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_resize.scss:
--------------------------------------------------------------------------------
1 | // Resize anything
2 |
3 | @mixin resizable($direction) {
4 | overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible`
5 | resize: $direction; // Options: horizontal, vertical, both
6 | }
7 |
--------------------------------------------------------------------------------
/src/Widgets/GroupWidget/GroupWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import groupWidgetIcon from "../../assets/images/group_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("GroupWidget", {
5 | title: "Group",
6 | thumbnail: groupWidgetIcon,
7 | });
8 |
--------------------------------------------------------------------------------
/src/utils/placeholderCss.js:
--------------------------------------------------------------------------------
1 | export const placeholderCss = {
2 | color: "rgba(64, 64, 64, 0.53)",
3 | display: "inline-block",
4 | fontSize: "13px",
5 | fontStyle: "normal",
6 | fontWeight: "normal",
7 | lineHeight: "28px",
8 | verticalAlign: "middle",
9 | };
10 |
--------------------------------------------------------------------------------
/src/prerenderContent/contentHash.js:
--------------------------------------------------------------------------------
1 | import { md4 } from "hash-wasm";
2 |
3 | /** Generates a 20 long hex value, based the md4 of the given string */
4 | export async function contentHash(input) {
5 | const md4OfInput = await md4(input);
6 | return md4OfInput.substring(0, 20);
7 | }
8 |
--------------------------------------------------------------------------------
/generator-scrivito/generators/widget/templates/XWidgetEditingConfig.js.ejs:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | Scrivito.provideEditingConfig("<%= widgetClassName %>", {
4 | title: "<%= humanFriendlyName %>",
5 | initialContent: {
6 | headline: "Lorem Ipsum",
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/src/config/objClassForContentType.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export function configureObjClassForContentType() {
4 | Scrivito.configureObjClassForContentType({
5 | "image/*": "Image",
6 | "video/*": "Video",
7 | "*/*": "Download",
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | ##
2 | # Netlify redirect rules. See https://www.netlify.com/docs/redirects/ for details.
3 | ##
4 |
5 | # Single Page Application routes
6 | /* status-code=404-not-found /catch_all_index.html 404
7 | # PRERENDERED-UPPERCASE-ROUTES-PLACEHOLDER
8 | /* /catch_all_index.html 200
9 |
--------------------------------------------------------------------------------
/src/Widgets/JobOverviewWidget/JobOverviewWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const JobOverviewWidget = Scrivito.provideWidgetClass(
4 | "JobOverviewWidget",
5 | {
6 | attributes: {
7 | locationLocality: "string",
8 | },
9 | }
10 | );
11 |
--------------------------------------------------------------------------------
/src/Widgets/SpaceWidget/SpaceWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("SpaceWidget", ({ widget }) => {
5 | const size = widget.get("size") || 5;
6 | return ;
7 | });
8 |
--------------------------------------------------------------------------------
/src/Widgets/FactWidget/FactWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const FactWidget = Scrivito.provideWidgetClass("FactWidget", {
4 | attributes: {
5 | key: "string",
6 | value: "string",
7 | },
8 | extractTextAttributes: ["key", "value"],
9 | });
10 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/validations/insideFormContainerValidation.js:
--------------------------------------------------------------------------------
1 | import { getFormContainer } from "../getFormContainer";
2 |
3 | export function insideFormContainerValidation(widget) {
4 | if (!getFormContainer(widget)) {
5 | return "Needs to be inside a form.";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/Widgets/VideoWidget/VideoWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const VideoWidget = Scrivito.provideWidgetClass("VideoWidget", {
4 | attributes: {
5 | source: ["reference", { only: ["Video"] }],
6 | poster: ["reference", { only: ["Image"] }],
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/src/config/windowScrivito.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export function configureWindowScrivito() {
4 | if (typeof window === "undefined") return;
5 |
6 | // set Scrivito as a global to allow easier debugging in the javascript console.
7 | window.Scrivito = Scrivito;
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/urlFromBinaryObj.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export function urlFromBinaryObj(binary) {
4 | if (!(binary instanceof Scrivito.Obj)) return null;
5 |
6 | const blob = binary.get("blob");
7 | if (!blob) return null;
8 |
9 | return blob.url() || null;
10 | }
11 |
--------------------------------------------------------------------------------
/src/Widgets/TickListWidget/TickListWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const TickListWidget = Scrivito.provideWidgetClass("TickListWidget", {
4 | attributes: {
5 | items: ["widgetlist", { only: "TickListItemWidget" }],
6 | },
7 | extractTextAttributes: ["items"],
8 | });
9 |
--------------------------------------------------------------------------------
/generator-scrivito/generators/widget/templates/XWidgetClass.js.ejs:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const <%= widgetClassName %> = Scrivito.provideWidgetClass("<%= widgetClassName %>", {
4 | attributes: {
5 | headline: "string",
6 | },
7 | extractTextAttributes: ["headline"],
8 | });
9 |
--------------------------------------------------------------------------------
/src/Objs/Download/DownloadObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const Download = Scrivito.provideObjClass("Download", {
4 | attributes: {
5 | blob: "binary",
6 | tags: "stringlist",
7 | title: "string",
8 | },
9 | extractTextAttributes: ["blob:text"],
10 | });
11 |
--------------------------------------------------------------------------------
/src/utils/isVideoObj.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export function isVideoObj(obj) {
4 | if (!(obj instanceof Scrivito.Obj)) return false;
5 |
6 | const contentType = obj.contentType();
7 | if (!contentType) return false;
8 |
9 | return contentType.startsWith("video/");
10 | }
11 |
--------------------------------------------------------------------------------
/src/Widgets/ColumnWidget/ColumnWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import columnWidgetIcon from "../../assets/images/column_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("ColumnWidget", {
5 | title: "Column",
6 | thumbnail: columnWidgetIcon,
7 | hideInSelectionDialogs: true,
8 | });
9 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/pseudoRandom32CharHex.js:
--------------------------------------------------------------------------------
1 | import { times } from "lodash-es";
2 |
3 | export function pseudoRandom32CharHex() {
4 | return times(32).map(pseudoRandomHex).join("");
5 | }
6 |
7 | function pseudoRandomHex() {
8 | return Math.floor(Math.random() * 16).toString(16);
9 | }
10 |
--------------------------------------------------------------------------------
/src/Objs/RedirectToUi/RedirectToUiEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import redirectObjIcon from "../../assets/images/redirect_obj.svg";
3 |
4 | Scrivito.provideEditingConfig("RedirectToUi", {
5 | title: "Redirect To UI",
6 | thumbnail: redirectObjIcon,
7 | hideInSelectionDialogs: true,
8 | });
9 |
--------------------------------------------------------------------------------
/src/Widgets/IconContainerWidget/IconContainerWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const IconContainerWidget = Scrivito.provideWidgetClass(
4 | "IconContainerWidget",
5 | {
6 | attributes: {
7 | iconList: ["widgetlist", { only: "IconWidget" }],
8 | },
9 | }
10 | );
11 |
--------------------------------------------------------------------------------
/src/Widgets/PricingSpecWidget/PricingSpecWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import pricingSpecWidgetIcon from "../../assets/images/pricing_spec_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("PricingSpecWidget", {
5 | title: "Pricing Spec",
6 | thumbnail: pricingSpecWidgetIcon,
7 | });
8 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/forms/_form-text.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Form text
3 | //
4 |
5 | .form-text {
6 | margin-top: $form-text-margin-top;
7 | @include font-size($form-text-font-size);
8 | font-style: $form-text-font-style;
9 | font-weight: $form-text-font-weight;
10 | color: $form-text-color;
11 | }
12 |
--------------------------------------------------------------------------------
/src/Objs/Video/VideoEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | Scrivito.provideEditingConfig("Video", {
4 | attributes: {
5 | tags: {
6 | title: "Tags",
7 | description: "Make it easier to find this video by adding some tags.",
8 | },
9 | },
10 | properties: ["tags"],
11 | });
12 |
--------------------------------------------------------------------------------
/src/Widgets/TextWidget/TextWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const TextWidget = Scrivito.provideWidgetClass("TextWidget", {
4 | attributes: {
5 | text: "html",
6 | alignment: ["enum", { values: ["left", "center", "right"] }],
7 | },
8 | extractTextAttributes: ["text"],
9 | });
10 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/_forms.scss:
--------------------------------------------------------------------------------
1 | @import "forms/labels";
2 | @import "forms/form-text";
3 | @import "forms/form-control";
4 | @import "forms/form-select";
5 | @import "forms/form-check";
6 | @import "forms/form-range";
7 | @import "forms/floating-labels";
8 | @import "forms/input-group";
9 | @import "forms/validation";
10 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/scrollIntoView.js:
--------------------------------------------------------------------------------
1 | export function scrollIntoView(element) {
2 | window.scrollTo({
3 | top: getTop(element) - 95,
4 | behavior: "smooth",
5 | });
6 | }
7 |
8 | function getTop(element) {
9 | const rect = element.getBoundingClientRect();
10 | return rect.top + window.pageYOffset;
11 | }
12 |
--------------------------------------------------------------------------------
/src/Widgets/LinkContainerWidget/LinkContainerWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const LinkContainerWidget = Scrivito.provideWidgetClass(
4 | "LinkContainerWidget",
5 | {
6 | attributes: {
7 | headline: "string",
8 | links: ["widgetlist", { only: "LinkWidget" }],
9 | },
10 | }
11 | );
12 |
--------------------------------------------------------------------------------
/src/Widgets/TestimonialSliderWidget/TestimonialSliderWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const TestimonialSliderWidget = Scrivito.provideWidgetClass(
4 | "TestimonialSliderWidget",
5 | {
6 | attributes: {
7 | testimonials: ["widgetlist", { only: "TestimonialWidget" }],
8 | },
9 | }
10 | );
11 |
--------------------------------------------------------------------------------
/src/Widgets/TickListItemWidget/TickListItemWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("TickListItemWidget", ({ widget }) => (
5 |
6 |
7 |
8 | ));
9 |
--------------------------------------------------------------------------------
/src/Components/Navigation/LandingPageNavigation.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Logo } from "./Logo";
3 |
4 | export function LandingPageNavigation({ navigationStyle }) {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/src/Widgets/ColumnWidget/ColumnWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const ColumnWidget = Scrivito.provideWidgetClass("ColumnWidget", {
4 | onlyInside: "ColumnContainerWidget",
5 | attributes: {
6 | colSize: "integer",
7 | content: "widgetlist",
8 | },
9 | extractTextAttributes: ["content"],
10 | });
11 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/_helpers.scss:
--------------------------------------------------------------------------------
1 | @import "helpers/clearfix";
2 | @import "helpers/colored-links";
3 | @import "helpers/ratio";
4 | @import "helpers/position";
5 | @import "helpers/stacks";
6 | @import "helpers/visually-hidden";
7 | @import "helpers/stretched-link";
8 | @import "helpers/text-truncation";
9 | @import "helpers/vr";
10 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_stretched-link.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Stretched link
3 | //
4 |
5 | .stretched-link {
6 | &::#{$stretched-link-pseudo-element} {
7 | position: absolute;
8 | top: 0;
9 | right: 0;
10 | bottom: 0;
11 | left: 0;
12 | z-index: $stretched-link-z-index;
13 | content: "";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Widgets/EventOverviewWidget/EventOverviewWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const EventOverviewWidget = Scrivito.provideWidgetClass(
4 | "EventOverviewWidget",
5 | {
6 | attributes: {
7 | maxItems: "integer",
8 | showTags: "boolean",
9 | tags: "stringlist",
10 | },
11 | }
12 | );
13 |
--------------------------------------------------------------------------------
/src/Widgets/TableRowWidget/TableRowWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import tableRowWidgetIcon from "../../assets/images/table_row_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("TableRowWidget", {
5 | title: "Table Row",
6 | thumbnail: tableRowWidgetIcon,
7 | titleForContent: (widget) => widget.get("cell1"),
8 | });
9 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_container.scss:
--------------------------------------------------------------------------------
1 | // Container mixins
2 |
3 | @mixin make-container($gutter: $container-padding-x) {
4 | width: 100%;
5 | padding-right: var(--#{$variable-prefix}gutter-x, #{$gutter});
6 | padding-left: var(--#{$variable-prefix}gutter-x, #{$gutter});
7 | margin-right: auto;
8 | margin-left: auto;
9 | }
10 |
--------------------------------------------------------------------------------
/src/Widgets/BoxWidget/BoxWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const BoxWidget = Scrivito.provideWidgetClass("BoxWidget", {
4 | attributes: {
5 | body: "widgetlist",
6 | boxStyle: ["enum", { values: ["transparent", "white"] }],
7 | useOffset: "boolean",
8 | },
9 | extractTextAttributes: ["body"],
10 | });
11 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_stacks.scss:
--------------------------------------------------------------------------------
1 | // scss-docs-start stacks
2 | .hstack {
3 | display: flex;
4 | flex-direction: row;
5 | align-items: center;
6 | align-self: stretch;
7 | }
8 |
9 | .vstack {
10 | display: flex;
11 | flex: 1 1 auto;
12 | flex-direction: column;
13 | align-self: stretch;
14 | }
15 | // scss-docs-end stacks
16 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_alert.scss:
--------------------------------------------------------------------------------
1 | // scss-docs-start alert-variant-mixin
2 | @mixin alert-variant($background, $border, $color) {
3 | color: $color;
4 | @include gradient-bg($background);
5 | border-color: $border;
6 |
7 | .alert-link {
8 | color: shade-color($color, 20%);
9 | }
10 | }
11 | // scss-docs-end alert-variant-mixin
12 |
--------------------------------------------------------------------------------
/src/Widgets/BlogOverviewWidget/BlogOverviewWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const BlogOverviewWidget = Scrivito.provideWidgetClass(
4 | "BlogOverviewWidget",
5 | {
6 | attributes: {
7 | maxItems: "integer",
8 | author: ["reference", { only: "Author" }],
9 | tags: "stringlist",
10 | },
11 | }
12 | );
13 |
--------------------------------------------------------------------------------
/src/Widgets/TickListItemWidget/TickListItemWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const TickListItemWidget = Scrivito.provideWidgetClass(
4 | "TickListItemWidget",
5 | {
6 | onlyInside: "TickListWidget",
7 | attributes: {
8 | statement: "string",
9 | },
10 | extractTextAttributes: ["statement"],
11 | }
12 | );
13 |
--------------------------------------------------------------------------------
/src/Widgets/ButtonWidget/ButtonWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const ButtonWidget = Scrivito.provideWidgetClass("ButtonWidget", {
4 | attributes: {
5 | target: "link",
6 | alignment: ["enum", { values: ["left", "center", "right", "block"] }],
7 | style: ["enum", { values: ["btn-primary", "btn-clear"] }],
8 | },
9 | });
10 |
--------------------------------------------------------------------------------
/src/Widgets/FormHiddenFieldWidget/FormHiddenFieldWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const FormHiddenFieldWidget = Scrivito.provideWidgetClass(
4 | "FormHiddenFieldWidget",
5 | {
6 | onlyInside: "FormContainerWidget",
7 | attributes: {
8 | customFieldName: "string",
9 | hiddenValue: "string",
10 | },
11 | }
12 | );
13 |
--------------------------------------------------------------------------------
/src/Widgets/PriceWidget/PriceWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const PriceWidget = Scrivito.provideWidgetClass("PriceWidget", {
4 | onlyInside: "TableRowWidget",
5 | attributes: {
6 | currency: "string",
7 | period: "string",
8 | price: "string",
9 | },
10 | extractTextAttributes: ["price", "currency", "period"],
11 | });
12 |
--------------------------------------------------------------------------------
/src/Widgets/ThumbnailGalleryWidget/ThumbnailGalleryWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const ThumbnailGalleryWidget = Scrivito.provideWidgetClass(
4 | "ThumbnailGalleryWidget",
5 | {
6 | attributes: {
7 | images: ["widgetlist", { only: "ThumbnailGalleryImageWidget" }],
8 | showTags: "boolean",
9 | },
10 | }
11 | );
12 |
--------------------------------------------------------------------------------
/src/Widgets/PriceWidget/PriceWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import priceWidgetIcon from "../../assets/images/price_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("PriceWidget", {
5 | title: "Price",
6 | thumbnail: priceWidgetIcon,
7 | initialContent: {
8 | currency: "$",
9 | price: "20",
10 | period: "/mo",
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/public/js_snippets_head.js:
--------------------------------------------------------------------------------
1 | // This file is for executing JavaScript code immediately before the head element is closed.
2 | // Here you can, for example, connect your site to remote services such as booking.com, segment.io, etc.
3 | // Don't forget to whitelist the URLs in the CSP at public/_headersCsp.json.
4 |
5 | // Intercom is already taken care of by the app, so there's no need to add it here.
6 |
--------------------------------------------------------------------------------
/src/Widgets/TickListWidget/TickListWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | import "./TickListWidget.scss";
5 |
6 | Scrivito.provideComponent("TickListWidget", ({ widget }) => (
7 |
13 | ));
14 |
--------------------------------------------------------------------------------
/src/Components/SchemaDotOrg/dataFromAuthor.js:
--------------------------------------------------------------------------------
1 | import { urlFromBinaryObj } from "../../utils/urlFromBinaryObj";
2 |
3 | export function dataFromAuthor(author) {
4 | return {
5 | "@context": "http://schema.org",
6 | "@type": "Person",
7 | name: author.get("title"),
8 | description: author.get("description"),
9 | image: urlFromBinaryObj(author.get("image")),
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/src/Objs/SearchResults/SearchResultsObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { metadataAttributes } from "../_metadataAttributes";
3 |
4 | export const SearchResults = Scrivito.provideObjClass("SearchResults", {
5 | attributes: {
6 | title: "string",
7 | navigationBackgroundImage: ["reference", { only: ["Image"] }],
8 | ...metadataAttributes,
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/src/Widgets/PricingSpecWidget/PricingSpecWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const PricingSpecWidget = Scrivito.provideWidgetClass(
4 | "PricingSpecWidget",
5 | {
6 | onlyInside: "PricingWidget",
7 | attributes: {
8 | variable: "string",
9 | unit: "string",
10 | },
11 | extractTextAttributes: ["variable", "unit"],
12 | }
13 | );
14 |
--------------------------------------------------------------------------------
/src/Widgets/FeaturePanelWidget/FeaturePanelWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const FeaturePanelWidget = Scrivito.provideWidgetClass(
4 | "FeaturePanelWidget",
5 | {
6 | attributes: {
7 | icon: "string",
8 | headline: "string",
9 | description: "string",
10 | },
11 | extractTextAttributes: ["headline", "description"],
12 | }
13 | );
14 |
--------------------------------------------------------------------------------
/generator-scrivito/generators/obj/templates/XComponent.js.ejs:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | import "./<%= objClassName %>.scss";
5 |
6 | Scrivito.provideComponent("<%= objClassName %>", ({ page }) => (
7 |
13 | ));
14 |
--------------------------------------------------------------------------------
/src/Widgets/FormButtonWidget/FormButtonWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const FormButtonWidget = Scrivito.provideWidgetClass(
4 | "FormButtonWidget",
5 | {
6 | attributes: {
7 | buttonText: "string",
8 | alignment: ["enum", { values: ["left", "center", "right", "block"] }],
9 | },
10 | extractTextAttributes: ["buttonText"],
11 | }
12 | );
13 |
--------------------------------------------------------------------------------
/src/Widgets/PriceWidget/PriceWidget.scss:
--------------------------------------------------------------------------------
1 | .price-widget {
2 | margin-top: 10px;
3 |
4 | &--dollar {
5 | font-size: 24px;
6 | position: relative;
7 | top: -20px;
8 | }
9 |
10 | &--price {
11 | font-size: 50px;
12 | padding: 0 3px;
13 | }
14 |
15 | &--period {
16 | font-size: 14px;
17 | margin-left: 0;
18 | position: relative;
19 | top: -3px;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/generator-scrivito/generators/widget/templates/XWidgetComponent.js.ejs:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | import "./<%= widgetClassName %>.scss";
5 |
6 | Scrivito.provideComponent("<%= widgetClassName %>", ({ widget }) => (
7 |
12 | ));
13 |
--------------------------------------------------------------------------------
/src/Widgets/VimeoVideoWidget/VimeoVideoWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const VimeoVideoWidget = Scrivito.provideWidgetClass(
4 | "VimeoVideoWidget",
5 | {
6 | attributes: {
7 | vimeoVideoId: "string",
8 | aspectRatio: [
9 | "enum",
10 | { values: ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"] },
11 | ],
12 | },
13 | }
14 | );
15 |
--------------------------------------------------------------------------------
/src/Widgets/YoutubeVideoWidget/YoutubeVideoWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const YoutubeVideoWidget = Scrivito.provideWidgetClass(
4 | "YoutubeVideoWidget",
5 | {
6 | attributes: {
7 | youtubeVideoId: "string",
8 | aspectRatio: [
9 | "enum",
10 | { values: ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"] },
11 | ],
12 | },
13 | }
14 | );
15 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/_mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin transition-performance() {
2 | -webkit-backface-visibility: hidden;
3 | backface-visibility: hidden;
4 | -moz-osx-font-smoothing: grayscale;
5 | -webkit-backface-visibility: hidden;
6 | -webkit-transform: translateZ(0);
7 | -moz-transform: translateZ(0);
8 | -ms-transform: translateZ(0);
9 | -o-transform: translateZ(0);
10 | transform: translateZ(0);
11 | }
12 |
--------------------------------------------------------------------------------
/src/Objs/Author/AuthorObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { metadataAttributes } from "../_metadataAttributes";
3 |
4 | export const Author = Scrivito.provideObjClass("Author", {
5 | attributes: {
6 | title: "string",
7 | description: "string",
8 | image: ["reference", { only: ["Image"] }],
9 | ...metadataAttributes,
10 | },
11 | extractTextAttributes: ["description"],
12 | });
13 |
--------------------------------------------------------------------------------
/src/Objs/Page/PageObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { metadataAttributes } from "../_metadataAttributes";
3 | import { defaultPageAttributes } from "../_defaultPageAttributes";
4 |
5 | export const Page = Scrivito.provideObjClass("Page", {
6 | attributes: {
7 | ...defaultPageAttributes,
8 | ...metadataAttributes,
9 | },
10 | extractTextAttributes: ["navigationSection", "body"],
11 | });
12 |
--------------------------------------------------------------------------------
/src/Widgets/TableWidget/TableWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const TableWidget = Scrivito.provideWidgetClass("TableWidget", {
4 | attributes: {
5 | rows: ["widgetlist", { only: "TableRowWidget" }],
6 | summaryRows: ["widgetlist", { only: "TableRowWidget" }],
7 | header1: "string",
8 | header2: "string",
9 | header3: "string",
10 | header4: "string",
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/src/Widgets/IconWidget/IconWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const IconWidget = Scrivito.provideWidgetClass("IconWidget", {
4 | attributes: {
5 | icon: "string",
6 | size: [
7 | "enum",
8 | { values: ["fa-1x", "fa-lg", "fa-2x", "fa-3x", "fa-4x", "fa-5x"] },
9 | ],
10 | alignment: ["enum", { values: ["left", "center", "right"] }],
11 | link: "link",
12 | },
13 | });
14 |
--------------------------------------------------------------------------------
/src/Widgets/TextWidget/TextWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { alignmentClassName } from "../../utils/alignmentClassName";
4 |
5 | Scrivito.provideComponent("TextWidget", ({ widget }) => (
6 |
12 | ));
13 |
--------------------------------------------------------------------------------
/generator-scrivito/generators/obj/templates/XObjClass.js.ejs:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import metadataAttributes from "../_metadataAttributes";
3 |
4 | export const <%= objClassName %> = Scrivito.provideObjClass("<%= objClassName %>", {
5 | attributes: {
6 | title: "string",
7 | body: ["widgetlist", { only: "SectionWidget" }],
8 | ...metadataAttributes,
9 | },
10 | extractTextAttributes: ["body"],
11 | });
12 |
--------------------------------------------------------------------------------
/src/Widgets/CarouselWidget/CarouselWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const CarouselWidget = Scrivito.provideWidgetClass("CarouselWidget", {
4 | attributes: {
5 | images: ["referencelist", { only: ["Image"] }],
6 | showDescription: "boolean",
7 | descriptionLogo: ["reference", { only: ["Image"] }],
8 | description: "widgetlist",
9 | },
10 | extractTextAttributes: ["description"],
11 | });
12 |
--------------------------------------------------------------------------------
/src/Objs/Download/DownloadEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | Scrivito.provideEditingConfig("Download", {
4 | attributes: {
5 | tags: {
6 | title: "Tags",
7 | description: "Make it easier to find this download by adding some tags.",
8 | },
9 | title: {
10 | title: "Title",
11 | description: "Limit to 55 characters.",
12 | },
13 | },
14 | properties: ["title", "tags"],
15 | });
16 |
--------------------------------------------------------------------------------
/src/Widgets/ColumnContainerWidget/ColumnContainerWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const ColumnContainerWidget = Scrivito.provideWidgetClass(
4 | "ColumnContainerWidget",
5 | {
6 | attributes: {
7 | columns: ["widgetlist", { only: "ColumnWidget" }],
8 | alignment: ["enum", { values: ["start", "center", "end", "stretch"] }],
9 | },
10 | extractTextAttributes: ["columns"],
11 | }
12 | );
13 |
--------------------------------------------------------------------------------
/src/Objs/Blog/BlogObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { metadataAttributes } from "../_metadataAttributes";
3 |
4 | export const Blog = Scrivito.provideObjClass("Blog", {
5 | attributes: {
6 | title: "string",
7 | navigationBackgroundImage: ["reference", { only: ["Image"] }],
8 | body: ["widgetlist", { only: "SectionWidget" }],
9 | ...metadataAttributes,
10 | },
11 | extractTextAttributes: ["body"],
12 | });
13 |
--------------------------------------------------------------------------------
/src/Objs/LandingPage/LandingPageObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { metadataAttributes } from "../_metadataAttributes";
3 | import { defaultPageAttributes } from "../_defaultPageAttributes";
4 |
5 | export const LandingPage = Scrivito.provideObjClass("LandingPage", {
6 | attributes: {
7 | ...defaultPageAttributes,
8 | ...metadataAttributes,
9 | },
10 | extractTextAttributes: ["navigationSection", "body"],
11 | });
12 |
--------------------------------------------------------------------------------
/public/_headers:
--------------------------------------------------------------------------------
1 | ##
2 | # Netlify headers. See https://www.netlify.com/docs/headers-and-basic-auth/ for details.
3 | #
4 | # CSP-DIRECTIVES-PLACEHOLDER will be replaced by webpack, which uses _headersCsp.json as input.
5 | ##
6 |
7 | /*
8 | Content-Security-Policy: CSP-DIRECTIVES-PLACEHOLDER
9 | X-Frame-Options: sameorigin
10 | X-XSS-Protection: 1; mode=block
11 | X-Content-Type-Options: nosniff
12 | Referrer-Policy: strict-origin-when-cross-origin
13 |
--------------------------------------------------------------------------------
/src/Objs/_defaultPageAttributes.js:
--------------------------------------------------------------------------------
1 | export const defaultPageAttributes = {
2 | body: ["widgetlist", { only: "SectionWidget" }],
3 | navigationBackgroundImage: ["reference", { only: ["Image", "Video"] }],
4 | navigationBackgroundImageGradient: "boolean",
5 | navigationHeight: [
6 | "enum",
7 | {
8 | values: ["small", "medium-height", "full-height"],
9 | },
10 | ],
11 | navigationSection: "widgetlist",
12 | title: "string",
13 | };
14 |
--------------------------------------------------------------------------------
/src/Widgets/FormHiddenFieldWidget/FormHiddenFieldWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { getFieldName } from "../FormContainerWidget/utils/getFieldName";
4 |
5 | Scrivito.provideComponent("FormHiddenFieldWidget", ({ widget }) => {
6 | const name = getFieldName(widget);
7 | if (!name) return null;
8 |
9 | return ;
10 | });
11 |
--------------------------------------------------------------------------------
/src/Widgets/TestimonialWidget/TestimonialWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const TestimonialWidget = Scrivito.provideWidgetClass(
4 | "TestimonialWidget",
5 | {
6 | onlyInside: "TestimonialSliderWidget",
7 | attributes: {
8 | testimonial: "string",
9 | author: "string",
10 | authorImage: ["reference", { only: ["Image"] }],
11 | },
12 | extractTextAttributes: ["testimonial"],
13 | }
14 | );
15 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_backdrop.scss:
--------------------------------------------------------------------------------
1 | // Shared between modals and offcanvases
2 | @mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) {
3 | position: fixed;
4 | top: 0;
5 | left: 0;
6 | z-index: $zindex;
7 | width: 100vw;
8 | height: 100vh;
9 | background-color: $backdrop-bg;
10 |
11 | // Fade for backdrop
12 | &.fade {
13 | opacity: 0;
14 | }
15 | &.show {
16 | opacity: $backdrop-opacity;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Widgets/ThumbnailGalleryImageWidget/ThumbnailGalleryImageWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const ThumbnailGalleryImageWidget = Scrivito.provideWidgetClass(
4 | "ThumbnailGalleryImageWidget",
5 | {
6 | onlyInside: "ThumbnailGalleryWidget",
7 | attributes: {
8 | image: ["reference", { only: ["Image"] }],
9 | title: "string",
10 | subtitle: "string",
11 | tags: "stringlist",
12 | },
13 | }
14 | );
15 |
--------------------------------------------------------------------------------
/src/Widgets/PricingSpecWidget/PricingSpecWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("PricingSpecWidget", ({ widget }) => (
5 |
6 |
12 |
13 |
14 | ));
15 |
--------------------------------------------------------------------------------
/src/Components/Navigation/ScrollToNextSectionLink.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export function ScrollToNextSectionLink({ heightClassName }) {
4 | if (heightClassName !== "full-height") return null;
5 |
6 | return (
7 |
12 |
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/src/Objs/Image/ImageEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | Scrivito.provideEditingConfig("Image", {
4 | attributes: {
5 | tags: {
6 | title: "Tags",
7 | description: "Make it easier to find this Image by adding some tags.",
8 | },
9 | alternativeText: {
10 | title: "Alternative text",
11 | description: "Brief description of what the image is about.",
12 | },
13 | },
14 | properties: ["alternativeText", "tags"],
15 | });
16 |
--------------------------------------------------------------------------------
/src/Objs/RedirectToUi/RedirectToUiComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | class RedirectToUiComponent extends React.Component {
5 | componentDidMount() {
6 | const scrivitoUiUrl = `https://edit.scrivito.com/${window.location.origin}`;
7 | window.top.location.replace(scrivitoUiUrl);
8 | }
9 |
10 | render() {
11 | return null;
12 | }
13 | }
14 |
15 | Scrivito.provideComponent("RedirectToUi", RedirectToUiComponent);
16 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_colored-links.scss:
--------------------------------------------------------------------------------
1 | @each $color, $value in $theme-colors {
2 | .link-#{$color} {
3 | color: $value;
4 |
5 | @if $link-shade-percentage != 0 {
6 | &:hover,
7 | &:focus {
8 | color: if(
9 | color-contrast($value) == $color-contrast-light,
10 | shade-color($value, $link-shade-percentage),
11 | tint-color($value, $link-shade-percentage)
12 | );
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/assets/images/arrow_next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/arrow_prev.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_image.scss:
--------------------------------------------------------------------------------
1 | // Image Mixins
2 | // - Responsive image
3 | // - Retina image
4 |
5 | // Responsive image
6 | //
7 | // Keep images from scaling beyond the width of their parents.
8 |
9 | @mixin img-fluid {
10 | // Part 1: Set a maximum relative to the parent
11 | max-width: 100%;
12 | // Part 2: Override the height to auto, otherwise images will be stretched
13 | // when setting a width and height attribute on the img element.
14 | height: auto;
15 | }
16 |
--------------------------------------------------------------------------------
/src/Widgets/SpaceWidget/SpaceWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import spaceWidgetIcon from "../../assets/images/space_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("SpaceWidget", {
5 | title: "Space",
6 | thumbnail: spaceWidgetIcon,
7 | attributes: {
8 | size: {
9 | title: "Choose size",
10 | description: "Height of the space in em. Default: 5",
11 | },
12 | },
13 | properties: ["size"],
14 | initialContent: {
15 | size: 5,
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/bootstrap-utilities.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Utilities v5.1.3 (https://getbootstrap.com/)
3 | * Copyright 2011-2021 The Bootstrap Authors
4 | * Copyright 2011-2021 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 | */
7 |
8 | // Configuration
9 | @import "functions";
10 | @import "variables";
11 | @import "mixins";
12 | @import "utilities";
13 |
14 | // Helpers
15 | @import "helpers";
16 |
17 | // Utilities
18 | @import "utilities/api";
19 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/getFormContainer.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | /** Returns the first `FormContainerWidget` container it can find. `null` otherwise. */
4 | export function getFormContainer(childWidget) {
5 | let candidate = childWidget.container();
6 | while (candidate instanceof Scrivito.Widget) {
7 | if (candidate.objClass() === "FormContainerWidget") {
8 | return candidate;
9 | }
10 | candidate = candidate.container();
11 | }
12 |
13 | return null;
14 | }
15 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/bootstrap-reboot.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v5.1.3 (https://getbootstrap.com/)
3 | * Copyright 2011-2021 The Bootstrap Authors
4 | * Copyright 2011-2021 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 |
9 | @import "functions";
10 | @import "variables";
11 | @import "mixins";
12 | @import "root";
13 | @import "reboot";
14 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_box-shadow.scss:
--------------------------------------------------------------------------------
1 | @mixin box-shadow($shadow...) {
2 | @if $enable-shadows {
3 | $result: ();
4 |
5 | @each $value in $shadow {
6 | @if $value != null {
7 | $result: append($result, $value, "comma");
8 | }
9 | @if $value == none and length($shadow) > 1 {
10 | @warn "The keyword 'none' must be used as a single argument.";
11 | }
12 | }
13 |
14 | @if (length($result) > 0) {
15 | box-shadow: $result;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/scrivito_extensions.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import * as ReactDOM from "react-dom/client";
4 |
5 | import "./Objs";
6 | import "./Objs/editingConfigs";
7 | import "./Widgets";
8 | import "./Widgets/editingConfigs";
9 | import { configure } from "./config";
10 | import "./Components/ScrivitoExtensions";
11 | import "./assets/stylesheets/index.scss";
12 |
13 | ReactDOM.createRoot(document.createElement("div")).render(
14 |
15 | );
16 | configure();
17 |
--------------------------------------------------------------------------------
/src/Components/SchemaDotOrg/dataFromBlog.js:
--------------------------------------------------------------------------------
1 | import { urlFromBinaryObj } from "../../utils/urlFromBinaryObj";
2 | import { isImageObj } from "../../utils/isImageObj";
3 |
4 | export function dataFromBlog(blog) {
5 | const schema = {
6 | "@context": "http://schema.org",
7 | "@type": "Blog",
8 | headline: blog.get("title"),
9 | };
10 |
11 | const backgroundObj = blog.get("navigationBackgroundImage");
12 | if (isImageObj(backgroundObj)) schema.image = urlFromBinaryObj(backgroundObj);
13 |
14 | return schema;
15 | }
16 |
--------------------------------------------------------------------------------
/src/Widgets/JobOverviewWidget/JobOverviewWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import jobOverviewWidgetIcon from "../../assets/images/job_overview_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("JobOverviewWidget", {
5 | title: "Job Overview",
6 | thumbnail: jobOverviewWidgetIcon,
7 | attributes: {
8 | locationLocality: {
9 | title: "Filter by locality",
10 | description: "Leave empty to see all jobs. E.g. New York",
11 | },
12 | },
13 | properties: ["locationLocality"],
14 | });
15 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/FormContainerWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const FormContainerWidget = Scrivito.provideWidgetClass(
4 | "FormContainerWidget",
5 | {
6 | attributes: {
7 | content: "widgetlist",
8 | formId: "string",
9 | failedMessage: "string",
10 | submittedMessage: "string",
11 | submittingMessage: "string",
12 | hiddenFields: ["widgetlist", { only: "FormHiddenFieldWidget" }],
13 | },
14 | extractTextAttributes: ["content"],
15 | }
16 | );
17 |
--------------------------------------------------------------------------------
/generator-scrivito/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generator-scrivito",
3 | "version": "0.0.1",
4 | "description": "generator for scrivito_example_app_js",
5 | "main": "index.js",
6 | "license": "MIT",
7 | "engines": {
8 | "node": ">=18.0.0"
9 | },
10 | "private": true,
11 | "repository": {
12 | "private": true
13 | },
14 | "dependencies": {
15 | "gulp-prettier": "^3.0.0",
16 | "lodash": "^4.17.21",
17 | "yeoman-generator": "^5.3.0"
18 | },
19 | "devDependencies": {
20 | "prettier": "^2.2.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Objs/_metadataAttributes.js:
--------------------------------------------------------------------------------
1 | export const metadataAttributes = {
2 | // Meta tags
3 | metaDataDescription: "string",
4 | robotsIndex: "boolean",
5 | // Twitter attributes
6 | tcCreator: "string",
7 | tcDescription: "string",
8 | tcImage: ["reference", { only: ["Image"] }],
9 | tcTitle: "string",
10 | // Open Graph attributes (used by Facebook)
11 | ogDescription: "string",
12 | ogImage: ["reference", { only: ["Image"] }],
13 | ogTitle: "string",
14 | // The order of the child pages
15 | childOrder: "referencelist",
16 | };
17 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_larger.scss:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | @use "sass:math";
6 |
7 | .#{$fa-css-prefix}-lg {
8 | font-size: math.div(4em, 3);
9 | line-height: (3em * 0.25);
10 | vertical-align: -15%;
11 | }
12 | .#{$fa-css-prefix}-2x {
13 | font-size: 2em;
14 | }
15 | .#{$fa-css-prefix}-3x {
16 | font-size: 3em;
17 | }
18 | .#{$fa-css-prefix}-4x {
19 | font-size: 4em;
20 | }
21 | .#{$fa-css-prefix}-5x {
22 | font-size: 5em;
23 | }
24 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_list.scss:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | @use "sass:math";
5 |
6 | .#{$fa-css-prefix}-ul {
7 | padding-left: 0;
8 | margin-left: $fa-li-width;
9 | list-style-type: none;
10 | > li {
11 | position: relative;
12 | }
13 | }
14 | .#{$fa-css-prefix}-li {
15 | position: absolute;
16 | left: -$fa-li-width;
17 | width: $fa-li-width;
18 | top: math.div(2em, 14);
19 | text-align: center;
20 | &.#{$fa-css-prefix}-lg {
21 | left: -$fa-li-width + math.div(4em, 14);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/public/_headersCsp.json:
--------------------------------------------------------------------------------
1 | {
2 | "base-uri": "'none'",
3 | "default-src": ["'self'", "data:", "https:", "wss:"],
4 | "style-src": ["'self'", "data:", "https:", "wss:", "'unsafe-inline'"],
5 | "script-src": [
6 | "'self'",
7 | "https://api.scrivito.com",
8 | "https://app.intercom.io",
9 | "https://assets.scrivito.com",
10 | "https://js.intercomcdn.com",
11 | "https://widget.intercom.io"
12 | ],
13 | "object-src": "'none'",
14 | "block-all-mixed-content": true,
15 | "frame-ancestors": ["'self'", "https://*.scrivito.com"]
16 | }
17 |
--------------------------------------------------------------------------------
/src/Widgets/DividerWidget/DividerWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | import "./DividerWidget.scss";
5 |
6 | Scrivito.provideComponent("DividerWidget", ({ widget }) => {
7 | const root = Scrivito.Obj.root();
8 |
9 | if (widget.get("showLogo") && root) {
10 | return (
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | return ;
18 | });
19 |
--------------------------------------------------------------------------------
/src/Components/InPlaceEditingPlaceholder.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { placeholderCss } from "../utils/placeholderCss";
4 |
5 | export const InPlaceEditingPlaceholder = ({ children, center, block }) => {
6 | if (!Scrivito.isInPlaceEditingActive()) return null;
7 |
8 | const innerSpan = {children};
9 |
10 | if (center) return {innerSpan}
;
11 |
12 | if (block) return {innerSpan}
;
13 |
14 | return innerSpan;
15 | };
16 |
--------------------------------------------------------------------------------
/src/Widgets/HeadlineWidget/HeadlineWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const HeadlineWidget = Scrivito.provideWidgetClass("HeadlineWidget", {
4 | attributes: {
5 | headline: "string",
6 | level: ["enum", { values: ["h1", "h2", "h3", "h4", "h5", "h6"] }],
7 | style: ["enum", { values: ["h1", "h2", "h3", "h4", "h5", "h6"] }],
8 | alignment: ["enum", { values: ["left", "center", "right"] }],
9 | showDividingLine: "boolean",
10 | showMargin: "boolean",
11 | },
12 | extractTextAttributes: ["headline"],
13 | });
14 |
--------------------------------------------------------------------------------
/src/Widgets/FactWidget/FactWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | import "./FactWidget.scss";
5 |
6 | Scrivito.provideComponent("FactWidget", ({ widget }) => (
7 |
8 |
14 |
20 |
21 | ));
22 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/validations/typeValidation.js:
--------------------------------------------------------------------------------
1 | import { isCustomType } from "../isCustomType";
2 | import { isFieldNameUnique } from "../isFieldNameUnique";
3 |
4 | export const typeValidation = [
5 | "type",
6 | (type, { widget }) => {
7 | if (!type) {
8 | return "Select the input type.";
9 | }
10 |
11 | if (!isCustomType(widget) && !isFieldNameUnique(widget)) {
12 | return `There must be only one element with the input type “${type.replace(
13 | /_/,
14 | " "
15 | )}”.`;
16 | }
17 | },
18 | ];
19 |
--------------------------------------------------------------------------------
/src/config/index.js:
--------------------------------------------------------------------------------
1 | import { configureScrivito } from "./scrivito";
2 | import { configureHistory } from "./history";
3 | import { configureObjClassForContentType } from "./objClassForContentType";
4 | import { configureScrivitoContentBrowser } from "./scrivitoContentBrowser";
5 | import { configureWindowScrivito } from "./windowScrivito";
6 |
7 | export function configure(options) {
8 | configureScrivito(options);
9 | configureObjClassForContentType();
10 |
11 | configureScrivitoContentBrowser();
12 | configureHistory();
13 | configureWindowScrivito();
14 | }
15 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/forms/_validation.scss:
--------------------------------------------------------------------------------
1 | // Form validation
2 | //
3 | // Provide feedback to users when form field values are valid or invalid. Works
4 | // primarily for client-side validation via scoped `:invalid` and `:valid`
5 | // pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for
6 | // server-side validation.
7 |
8 | // scss-docs-start form-validation-states-loop
9 | @each $state, $data in $form-validation-states {
10 | @include form-validation-state($state, $data...);
11 | }
12 | // scss-docs-end form-validation-states-loop
13 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_ratio.scss:
--------------------------------------------------------------------------------
1 | // Credit: Nicolas Gallagher and SUIT CSS.
2 |
3 | .ratio {
4 | position: relative;
5 | width: 100%;
6 |
7 | &::before {
8 | display: block;
9 | padding-top: var(--#{$variable-prefix}aspect-ratio);
10 | content: "";
11 | }
12 |
13 | > * {
14 | position: absolute;
15 | top: 0;
16 | left: 0;
17 | width: 100%;
18 | height: 100%;
19 | }
20 | }
21 |
22 | @each $key, $ratio in $aspect-ratios {
23 | .ratio-#{$key} {
24 | --#{$variable-prefix}aspect-ratio: #{$ratio};
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | @use "sass:list";
5 |
6 | .#{$fa-css-prefix} {
7 | display: inline-block;
8 | font: normal normal normal
9 | list.slash($fa-font-size-base, $fa-line-height-base) FontAwesome; // shortening font declaration
10 | font-size: inherit; // can't have font-size inherit on line above, so need to override
11 | text-rendering: auto; // optimizelegibility throws things off #1094
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | }
15 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/_transitions.scss:
--------------------------------------------------------------------------------
1 | .fade {
2 | @include transition($transition-fade);
3 |
4 | &:not(.show) {
5 | opacity: 0;
6 | }
7 | }
8 |
9 | // scss-docs-start collapse-classes
10 | .collapse {
11 | &:not(.show) {
12 | display: none;
13 | }
14 | }
15 |
16 | .collapsing {
17 | height: 0;
18 | overflow: hidden;
19 | @include transition($transition-collapse);
20 |
21 | &.collapse-horizontal {
22 | width: 0;
23 | height: auto;
24 | @include transition($transition-collapse-width);
25 | }
26 | }
27 | // scss-docs-end collapse-classes
28 |
--------------------------------------------------------------------------------
/src/Objs/BlogPost/BlogPostObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { metadataAttributes } from "../_metadataAttributes";
3 |
4 | export const BlogPost = Scrivito.provideObjClass("BlogPost", {
5 | attributes: {
6 | author: ["reference", { only: "Author" }],
7 | body: ["widgetlist", { only: "SectionWidget" }],
8 | publishedAt: "date",
9 | subtitle: "string",
10 | tags: "stringlist",
11 | title: "string",
12 | titleImage: ["reference", { only: ["Image"] }],
13 | ...metadataAttributes,
14 | },
15 | extractTextAttributes: ["body"],
16 | });
17 |
--------------------------------------------------------------------------------
/src/Widgets/DividerWidget/DividerWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import dividerWidgetIcon from "../../assets/images/divider_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("DividerWidget", {
5 | title: "Divider",
6 | thumbnail: dividerWidgetIcon,
7 | attributes: {
8 | showLogo: {
9 | title: "Show logo?",
10 | description:
11 | 'The divider logo can be changed on the homepage in the "Site settings". Default: Yes',
12 | },
13 | },
14 | properties: ["showLogo"],
15 | initialContent: {
16 | showLogo: true,
17 | },
18 | });
19 |
--------------------------------------------------------------------------------
/src/prerenderContent/generatePreloadDump.js:
--------------------------------------------------------------------------------
1 | export function generatePreloadDump(preloadDump) {
2 | return `window.preloadDump = ${stringLiteral(preloadDump)};`;
3 | }
4 |
5 | /**
6 | * JSON may contain line separators, which are invalid in string literals in older browsers.
7 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#issue_with_plain_json.stringify_for_use_as_javascript
8 | * */
9 | function stringLiteral(string) {
10 | return JSON.stringify(string)
11 | .replace(/\u2028/g, "\\u2028")
12 | .replace(/\u2029/g, "\\u2029");
13 | }
14 |
--------------------------------------------------------------------------------
/src/Objs/SearchResults/SearchResultsTagList.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { TagList } from "../../Components/TagList";
4 |
5 | export function SearchResultsTagList({ tags, params }) {
6 | return (
7 | {
11 | const newParams = { q: params.q };
12 | if (newTag) newParams.tag = newTag;
13 |
14 | Scrivito.navigateTo(() => Scrivito.currentPage(), newParams);
15 | }}
16 | currentTag={params.tag}
17 | />
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/src/_scrivito_extensions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 | Scrivito Extensions
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_reset-text.scss:
--------------------------------------------------------------------------------
1 | @mixin reset-text {
2 | font-family: $font-family-base;
3 | // We deliberately do NOT reset font-size or overflow-wrap / word-wrap.
4 | font-style: normal;
5 | font-weight: $font-weight-normal;
6 | line-height: $line-height-base;
7 | text-align: left; // Fallback for where `start` is not supported
8 | text-align: start;
9 | text-decoration: none;
10 | text-shadow: none;
11 | text-transform: none;
12 | letter-spacing: normal;
13 | word-break: normal;
14 | word-spacing: normal;
15 | white-space: normal;
16 | line-break: auto;
17 | }
18 |
--------------------------------------------------------------------------------
/src/Widgets/BlogOverviewWidget/BlogOverviewWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { BlogPostPreviewList } from "../../Components/BlogPost/BlogPostPreviewList";
4 |
5 | Scrivito.provideComponent("BlogOverviewWidget", ({ widget }) => {
6 | let { tag } = Scrivito.currentPageParams();
7 |
8 | const tags = widget.get("tags");
9 | if (!tag && tags.length) tag = tags;
10 |
11 | return (
12 |
17 | );
18 | });
19 |
--------------------------------------------------------------------------------
/src/config/history.js:
--------------------------------------------------------------------------------
1 | import { createBrowserHistory } from "history";
2 | import { useHistory as scrivitoUseHistory } from "scrivito";
3 | import { scrollToFragment } from "scroll-to-fragment";
4 |
5 | export function configureHistory() {
6 | const history = getHistory();
7 | if (!history) return;
8 |
9 | scrivitoUseHistory(history);
10 |
11 | scrollToFragment({ history });
12 | }
13 |
14 | let currentHistory;
15 |
16 | export function getHistory() {
17 | if (typeof window === "undefined") return;
18 |
19 | if (!currentHistory) currentHistory = createBrowserHistory();
20 | return currentHistory;
21 | }
22 |
--------------------------------------------------------------------------------
/src/Widgets/BoxWidget/BoxWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("BoxWidget", ({ widget }) => {
5 | const classNames = ["card"];
6 | if (widget.get("boxStyle") !== "white") classNames.push("card-theme");
7 | if (widget.get("useOffset")) classNames.push("box-offset");
8 |
9 | return (
10 |
11 |
16 |
17 | );
18 | });
19 |
--------------------------------------------------------------------------------
/src/Components/BlogPost/BlogPostDate.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { formatDate } from "../../utils/formatDate";
4 |
5 | export const BlogPostDate = Scrivito.connect(function BlogPostDate({ post }) {
6 | const date = post.get("publishedAt");
7 | if (!date) return null;
8 |
9 | return (
10 |
17 | {formatDate(date, "mm/dd")}
18 |
19 | );
20 | });
21 |
--------------------------------------------------------------------------------
/src/Components/Tracking.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Helmet } from "react-helmet-async";
3 | import { useCookieConsent } from "./CookieConsentContext";
4 |
5 | export function Tracking() {
6 | const [trackingEnabled, setTrackingEnabled] = React.useState(false);
7 | const { cookieConsentChoice } = useCookieConsent();
8 |
9 | React.useEffect(() => {
10 | if (cookieConsentChoice === "accepted") setTrackingEnabled(true);
11 | }, [cookieConsentChoice]);
12 |
13 | return (
14 | trackingEnabled && (
15 |
16 |
17 |
18 | )
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/src/Objs/SearchResults/ShowMoreButton.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | /* eslint-disable jsx-a11y/anchor-is-valid */
4 | export function ShowMoreButton({ currentMaxItems, totalCount, onClick }) {
5 | if (currentMaxItems >= totalCount) return null;
6 |
7 | return (
8 |
9 |
10 |
16 |
17 | );
18 | }
19 | /* eslint-enable jsx-a11y/anchor-is-valid */
20 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/isFieldNameUnique.js:
--------------------------------------------------------------------------------
1 | import { getFieldName } from "./getFieldName";
2 | import { getFormContainer } from "./getFormContainer";
3 |
4 | export function isFieldNameUnique(widget) {
5 | const fieldName = getFieldName(widget);
6 | if (!fieldName) {
7 | return true;
8 | }
9 |
10 | const formContainer = getFormContainer(widget);
11 | if (!formContainer) {
12 | return true;
13 | }
14 |
15 | const otherWidget = formContainer
16 | .widgets()
17 | .find(
18 | (child) => getFieldName(child) === fieldName && child.id() !== widget.id()
19 | );
20 |
21 | return !otherWidget;
22 | }
23 |
--------------------------------------------------------------------------------
/src/Widgets/ImageWidget/ImageWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const ImageWidget = Scrivito.provideWidgetClass("ImageWidget", {
4 | attributes: {
5 | image: ["reference", { only: "Image" }],
6 | alignment: ["enum", { values: ["left", "center", "right"] }],
7 | alternativeText: "string",
8 | link: "link",
9 | animation: [
10 | "enum",
11 | {
12 | values: [
13 | "none",
14 | "fadeInLeft",
15 | "fadeInRight",
16 | "fadeInDown",
17 | "fadeInUp",
18 | "zoomIn",
19 | ],
20 | },
21 | ],
22 | },
23 | });
24 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_stacked.scss:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .#{$fa-css-prefix}-stack-1x,
13 | .#{$fa-css-prefix}-stack-2x {
14 | position: absolute;
15 | left: 0;
16 | width: 100%;
17 | text-align: center;
18 | }
19 | .#{$fa-css-prefix}-stack-1x {
20 | line-height: inherit;
21 | }
22 | .#{$fa-css-prefix}-stack-2x {
23 | font-size: 2em;
24 | }
25 | .#{$fa-css-prefix}-inverse {
26 | color: $fa-inverse;
27 | }
28 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_list-group.scss:
--------------------------------------------------------------------------------
1 | // List Groups
2 |
3 | // scss-docs-start list-group-mixin
4 | @mixin list-group-item-variant($state, $background, $color) {
5 | .list-group-item-#{$state} {
6 | color: $color;
7 | background-color: $background;
8 |
9 | &.list-group-item-action {
10 | &:hover,
11 | &:focus {
12 | color: $color;
13 | background-color: shade-color($background, 10%);
14 | }
15 |
16 | &.active {
17 | color: $white;
18 | background-color: $color;
19 | border-color: $color;
20 | }
21 | }
22 | }
23 | }
24 | // scss-docs-end list-group-mixin
25 |
--------------------------------------------------------------------------------
/src/Components/Navigation/NavigationSection.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | export const NavigationSection = Scrivito.connect(function NavigationSection({
5 | heightClassName,
6 | }) {
7 | if (!["full-height", "medium-height"].includes(heightClassName)) return null;
8 |
9 | if (!Scrivito.currentPage()) return null;
10 | const obj = Scrivito.currentPage();
11 | if (!obj.get("navigationSection")) return null;
12 |
13 | return (
14 |
20 | );
21 | });
22 |
--------------------------------------------------------------------------------
/src/Widgets/FormCheckboxWidget/FormCheckboxWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const FormCheckboxWidget = Scrivito.provideWidgetClass(
4 | "FormCheckboxWidget",
5 | {
6 | attributes: {
7 | type: [
8 | "enum",
9 | {
10 | values: ["custom", "accept_terms"].concat(
11 | process.env.ENABLE_NEOLETTER_FORM_BUILDER_SUBSCRIPTION_FEATURE
12 | ? ["subscription"]
13 | : []
14 | ),
15 | },
16 | ],
17 | customFieldName: "string",
18 | label: "string",
19 | required: "boolean",
20 | helpText: "html",
21 | },
22 | }
23 | );
24 |
--------------------------------------------------------------------------------
/src/Components/Navigation/CollapseToggle.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export function CollapseToggle({ expanded, toggleExpanded }) {
4 | const classNames = ["navbar-toggler"];
5 | if (!expanded) classNames.push("collapsed");
6 |
7 | return (
8 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/helpers/_position.scss:
--------------------------------------------------------------------------------
1 | // Shorthand
2 |
3 | .fixed-top {
4 | position: fixed;
5 | top: 0;
6 | right: 0;
7 | left: 0;
8 | z-index: $zindex-fixed;
9 | }
10 |
11 | .fixed-bottom {
12 | position: fixed;
13 | right: 0;
14 | bottom: 0;
15 | left: 0;
16 | z-index: $zindex-fixed;
17 | }
18 |
19 | // Responsive sticky top
20 | @each $breakpoint in map-keys($grid-breakpoints) {
21 | @include media-breakpoint-up($breakpoint) {
22 | $infix: breakpoint-infix($breakpoint, $grid-breakpoints);
23 |
24 | .sticky#{$infix}-top {
25 | position: sticky;
26 | top: 0;
27 | z-index: $zindex-sticky;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Components/AnimateOnReveal.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import Zoom from "@successtar/react-reveal/Zoom";
3 | import Fade from "@successtar/react-reveal/Fade";
4 |
5 | export function AnimateOnReveal({ animation, children }) {
6 | switch (animation) {
7 | case "zoomIn":
8 | return {children};
9 | case "fadeInLeft":
10 | return {children};
11 | case "fadeInRight":
12 | return {children};
13 | case "fadeInDown":
14 | return {children};
15 | case "fadeInUp":
16 | return {children};
17 | default:
18 | return children;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Widgets/TableRowWidget/TableRowWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const TableRowWidget = Scrivito.provideWidgetClass("TableRowWidget", {
4 | attributes: {
5 | cell1: "string",
6 | cell2: [
7 | "widgetlist",
8 | { only: ["IconWidget", "TextWidget", "PriceWidget"] },
9 | ],
10 | cell3: [
11 | "widgetlist",
12 | { only: ["IconWidget", "TextWidget", "PriceWidget"] },
13 | ],
14 | cell4: [
15 | "widgetlist",
16 | { only: ["IconWidget", "TextWidget", "PriceWidget"] },
17 | ],
18 | },
19 | onlyInside: "TableWidget",
20 | extractTextAttributes: ["cell1", "cell2", "cell3", "cell4"],
21 | });
22 |
--------------------------------------------------------------------------------
/src/Widgets/FactWidget/FactWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import factWidgetIcon from "../../assets/images/fact_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("FactWidget", {
5 | title: "Fact",
6 | thumbnail: factWidgetIcon,
7 | initialContent: {
8 | key: "Lorem ipsum",
9 | value: "12",
10 | },
11 | validations: [
12 | [
13 | "value",
14 |
15 | (value, { widget }) => {
16 | if (!widget.get("key") && !value) {
17 | return {
18 | message: "The key or value (or both) must be set.",
19 | severity: "error",
20 | };
21 | }
22 | },
23 | ],
24 | ],
25 | });
26 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/_fontawesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "fontawesome/variables";
7 | @import "fontawesome/mixins";
8 | @import "fontawesome/path";
9 | @import "fontawesome/core";
10 | @import "fontawesome/larger";
11 | @import "fontawesome/fixed-width";
12 | @import "fontawesome/list";
13 | @import "fontawesome/bordered-pulled";
14 | @import "fontawesome/animated";
15 | @import "fontawesome/rotated-flipped";
16 | @import "fontawesome/stacked";
17 | @import "fontawesome/icons";
18 | @import "fontawesome/screen-reader";
19 |
--------------------------------------------------------------------------------
/src/config/scrivito.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export function configureScrivito(options) {
4 | const config = {
5 | adoptUi: true,
6 | autoConvertAttributes: true,
7 | optimizedWidgetLoading: true,
8 | strictSearchOperators: true,
9 | contentTagsForEmptyAttributes: false,
10 | tenant: process.env.SCRIVITO_TENANT,
11 | };
12 |
13 | if (process.env.SCRIVITO_ORIGIN) config.origin = process.env.SCRIVITO_ORIGIN;
14 |
15 | if (process.env.SCRIVITO_ENDPOINT) {
16 | config.endpoint = process.env.SCRIVITO_ENDPOINT;
17 | }
18 |
19 | if (options?.priority) config.priority = options.priority;
20 |
21 | Scrivito.configure(config);
22 | }
23 |
--------------------------------------------------------------------------------
/src/Components/Icon.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | function Icon({ icon, size, title }) {
5 | const actualIcon = icon || "fa-coffee";
6 | return (
7 |
12 | );
13 | }
14 |
15 | export function IconComponent({ icon, size, link }) {
16 | if (!link) return ;
17 |
18 | const title = link.title() || "";
19 |
20 | return (
21 |
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/Widgets/TickListItemWidget/TickListItemWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import tickListItemWidgetIcon from "../../assets/images/tick_list_item_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("TickListItemWidget", {
5 | title: "Tick List Item",
6 | thumbnail: tickListItemWidgetIcon,
7 | initialContent: {
8 | statement: "Lorem ipsum",
9 | },
10 | validations: [
11 | [
12 | "statement",
13 |
14 | (statement) => {
15 | if (!statement) {
16 | return {
17 | message: "The statement should be set.",
18 | severity: "warning",
19 | };
20 | }
21 | },
22 | ],
23 | ],
24 | });
25 |
--------------------------------------------------------------------------------
/src/Widgets/GalleryWidget/GalleryWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import galleryWidgetIcon from "../../assets/images/gallery_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("GalleryWidget", {
5 | title: "Gallery",
6 | thumbnail: galleryWidgetIcon,
7 | attributes: {
8 | images: {
9 | title: "Images",
10 | },
11 | },
12 | properties: ["images"],
13 | validations: [
14 | [
15 | "images",
16 |
17 | (images) => {
18 | if (images.length < 1) {
19 | return {
20 | message: "The gallery should contain at least one image.",
21 | severity: "warning",
22 | };
23 | }
24 | },
25 | ],
26 | ],
27 | });
28 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_deprecate.scss:
--------------------------------------------------------------------------------
1 | // Deprecate mixin
2 | //
3 | // This mixin can be used to deprecate mixins or functions.
4 | // `$enable-deprecation-messages` is a global variable, `$ignore-warning` is a variable that can be passed to
5 | // some deprecated mixins to suppress the warning (for example if the mixin is still be used in the current version of Bootstrap)
6 | @mixin deprecate(
7 | $name,
8 | $deprecate-version,
9 | $remove-version,
10 | $ignore-warning: false
11 | ) {
12 | @if ($enable-deprecation-messages != false and $ignore-warning != true) {
13 | @warn "#{$name} has been deprecated as of #{$deprecate-version}. It will be removed entirely in #{$remove-version}.";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Widgets/LinkWidget/LinkWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import linkWidgetIcon from "../../assets/images/link_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("LinkWidget", {
5 | title: "Link List item",
6 | thumbnail: linkWidgetIcon,
7 | attributes: {
8 | link: {
9 | title: "Link",
10 | description:
11 | "If no title is given, the obj's title or the external URl will be shown.",
12 | },
13 | },
14 | properties: ["link"],
15 | validations: [
16 | [
17 | "link",
18 |
19 | (link) => {
20 | if (!link) {
21 | return { message: "The link should be set.", severity: "warning" };
22 | }
23 | },
24 | ],
25 | ],
26 | });
27 |
--------------------------------------------------------------------------------
/src/Widgets/TickListWidget/TickListWidget.scss:
--------------------------------------------------------------------------------
1 | @import "src/assets/stylesheets/bootstrap5/mixins/clearfix";
2 | @import "src/assets/stylesheets/fontawesome/variables";
3 | @import "src/assets/stylesheets/fontawesome/mixins";
4 | @import "src/assets/stylesheets/variables";
5 |
6 | .tick-list-widget {
7 | list-style-type: none;
8 | padding-left: 15px;
9 | @include clearfix;
10 | }
11 |
12 | .tick-list-widget li {
13 | position: relative;
14 | padding: 0 0 20px 17px;
15 | font-weight: 500;
16 | font-size: 20px;
17 |
18 | &:before {
19 | display: block;
20 | position: absolute;
21 | top: 2px;
22 | left: -15px;
23 | content: "\f00c" !important;
24 | color: $primary;
25 | @include fa-icon;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Widgets/FeaturePanelWidget/FeaturePanelWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | Scrivito.provideComponent("FeaturePanelWidget", ({ widget }) => (
5 |
6 |
7 |
11 |
12 |
13 |
19 |
20 |
21 |
22 | ));
23 |
--------------------------------------------------------------------------------
/src/Widgets/IconContainerWidget/IconContainerWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import iconContainerWidgetIcon from "../../assets/images/icon_container_widget.svg";
3 | import { IconWidget } from "../IconWidget/IconWidgetClass";
4 |
5 | Scrivito.provideEditingConfig("IconContainerWidget", {
6 | title: "Icon List",
7 | thumbnail: iconContainerWidgetIcon,
8 | attributes: {
9 | iconList: {
10 | title: "Icon list",
11 | },
12 | },
13 | properties: ["iconList"],
14 | initialContent: {
15 | iconList: [
16 | new IconWidget({ icon: "fa-check-square-o" }),
17 | new IconWidget({ icon: "fa-check-square-o" }),
18 | new IconWidget({ icon: "fa-check-square-o" }),
19 | ],
20 | },
21 | });
22 |
--------------------------------------------------------------------------------
/src/Widgets/SectionWidget/SectionWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const SectionWidget = Scrivito.provideWidgetClass("SectionWidget", {
4 | attributes: {
5 | content: "widgetlist",
6 | useFullWidth: "boolean",
7 | useFullHeight: "boolean",
8 | showPadding: "boolean",
9 | backgroundColor: [
10 | "enum",
11 | {
12 | values: [
13 | "white",
14 | "greywhite",
15 | "greylight",
16 | "greymiddle",
17 | "greydark",
18 | "brand-primary",
19 | "brand-secondary",
20 | ],
21 | },
22 | ],
23 | backgroundImage: ["reference", { only: ["Image"] }],
24 | },
25 | extractTextAttributes: ["content"],
26 | });
27 |
--------------------------------------------------------------------------------
/src/Widgets/PriceWidget/PriceWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | import "./PriceWidget.scss";
5 |
6 | Scrivito.provideComponent("PriceWidget", ({ widget }) => (
7 |
8 |
14 |
20 |
26 |
27 | ));
28 |
--------------------------------------------------------------------------------
/src/Components/Footer.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { InPlaceEditingPlaceholder } from "./InPlaceEditingPlaceholder";
4 |
5 | export const Footer = Scrivito.connect(function Footer() {
6 | const root = Scrivito.Obj.root();
7 | if (!root) return null;
8 |
9 | return (
10 |
11 |
12 | The footer starts here. There’s only one footer. It belongs to the
13 | homepage but is displayed on all other pages as well.
14 |
15 |
21 |
22 | );
23 | });
24 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/_badge.scss:
--------------------------------------------------------------------------------
1 | // Base class
2 | //
3 | // Requires one of the contextual, color modifier classes for `color` and
4 | // `background-color`.
5 |
6 | .badge {
7 | display: inline-block;
8 | padding: $badge-padding-y $badge-padding-x;
9 | @include font-size($badge-font-size);
10 | font-weight: $badge-font-weight;
11 | line-height: 1;
12 | color: $badge-color;
13 | text-align: center;
14 | white-space: nowrap;
15 | vertical-align: baseline;
16 | @include border-radius($badge-border-radius);
17 | @include gradient-bg();
18 |
19 | // Empty badges collapse automatically
20 | &:empty {
21 | display: none;
22 | }
23 | }
24 |
25 | // Quick fix for badges in buttons
26 | .btn .badge {
27 | position: relative;
28 | top: -1px;
29 | }
30 |
--------------------------------------------------------------------------------
/src/Components/SchemaDotOrg/dataFromAddressWidget.js:
--------------------------------------------------------------------------------
1 | export function dataFromAddressWidget(addressWidget) {
2 | return {
3 | "@type": "Place",
4 | name: addressWidget.get("locationName"),
5 | address: addressFromAddressWidget(addressWidget),
6 | telephone: addressWidget.get("phone"),
7 | faxNumber: addressWidget.get("fax"),
8 | };
9 | }
10 |
11 | function addressFromAddressWidget(addressWidget) {
12 | return {
13 | "@type": "PostalAddress",
14 | streetAddress: addressWidget.get("locationStreetAddress"),
15 | addressLocality: addressWidget.get("locationLocality"),
16 | addressRegion: addressWidget.get("locationRegion"),
17 | postalCode: addressWidget.get("locationPostalCode"),
18 | addressCountry: addressWidget.get("locationCountry"),
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/src/Widgets/TextWidget/TextWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import textWidgetIcon from "../../assets/images/text_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("TextWidget", {
5 | title: "Text",
6 | thumbnail: textWidgetIcon,
7 | attributes: {
8 | alignment: {
9 | title: "Alignment",
10 | description: "Default: Left",
11 | values: [
12 | { value: "left", title: "Left" },
13 | { value: "center", title: "Center" },
14 | { value: "right", title: "Right" },
15 | ],
16 | },
17 | text: {
18 | title: "Text",
19 | description: "The actual source code of this text",
20 | },
21 | },
22 | properties: ["alignment", "text"],
23 | initialContent: {
24 | alignment: "left",
25 | },
26 | });
27 |
--------------------------------------------------------------------------------
/src/Objs/Event/EventObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { metadataAttributes } from "../_metadataAttributes";
3 |
4 | export const Event = Scrivito.provideObjClass("Event", {
5 | attributes: {
6 | body: ["widgetlist", { only: "SectionWidget" }],
7 | date: "date",
8 | image: ["reference", { only: ["Image"] }],
9 | locationName: "string",
10 | locationStreetAddress: "string",
11 | locationLocality: "string",
12 | locationPostalCode: "string",
13 | locationRegion: "string",
14 | locationCountry: "string",
15 | title: "string",
16 | tags: "stringlist",
17 | ...metadataAttributes,
18 | },
19 | extractTextAttributes: [
20 | "locationName",
21 | "locationLocality",
22 | "locationCountry",
23 | "body",
24 | ],
25 | });
26 |
--------------------------------------------------------------------------------
/src/Widgets/BoxWidget/BoxWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import boxWidgetIcon from "../../assets/images/box_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("BoxWidget", {
5 | title: "Box",
6 | thumbnail: boxWidgetIcon,
7 | attributes: {
8 | boxStyle: {
9 | title: "Background color",
10 | description: "Default: Transparent",
11 | values: [
12 | { value: "transparent", title: "Transparent" },
13 | { value: "white", title: "White with border" },
14 | ],
15 | },
16 | useOffset: {
17 | title: "Use offset?",
18 | description: 'If so, the box will move "up". Default: No',
19 | },
20 | },
21 | properties: ["boxStyle", "useOffset"],
22 | initialContent: {
23 | boxStyle: "transparent",
24 | },
25 | });
26 |
--------------------------------------------------------------------------------
/src/Widgets/FormButtonWidget/FormButtonWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { alignmentClassName } from "../../utils/alignmentClassName";
4 |
5 | Scrivito.provideComponent("FormButtonWidget", ({ widget }) => (
6 |
7 |
15 |
16 | ));
17 |
18 | function WrapIfClassName({ className, children }) {
19 | return className ? {children}
: children;
20 | }
21 |
--------------------------------------------------------------------------------
/src/Widgets/VideoWidget/videoPlaceholder.js:
--------------------------------------------------------------------------------
1 | export const videoPlaceholder = {
2 | backgroundColor: "#ccc",
3 | backgroundImage:
4 | 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAABaklEQVR42u3bIU7DcBTA4YWQIDAYFI4TECwGg+cIOLAEJIIDwCUaxNamGaoCxBBguQEOzwkYvJItWaYJfR3flzzbpvll7dr+OxgAAAAAAAAAAAAAACuvLMuvVR1BBBFEEEEE+fdBqqq6Go1Gxz2a81UPctizY9gTRJD+BIltnDRNsyFIniBPMa91Xe8KkidIu61pe9EVpOsgVfmxuL2IcjOZTNYFSRJkNs8xO4LkCdLOZ8yRIHmC/ESJU9h1WBMkR5D5PMRsC5InSDvv8Ws5ECRPkPn+LgRJFGQ29+PxeEuQPEHaeRsOh/uC5AnS7nsacypIkiALd/d3RVFsCpIkyGwqQfxCBFm+hkSMM9cQ/7IEcR+SNEicoi7dqXuWJcjSPHramyOI9yGJgnhjmCjIi3fqeYLcWnXSZRDrslIGsXIxURBrezMF6eAYBBHkb4P4gipTEN8YCiKIIIIIIggAAAAAAAAAAAAA/KpvIMhShRPBqAoAAAAASUVORK5CYII=")',
5 | backgroundRepeat: "no-repeat",
6 | backgroundPosition: "center",
7 | opacity: 0.5,
8 | };
9 |
--------------------------------------------------------------------------------
/src/Objs/Redirect/RedirectEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import redirectObjIcon from "../../assets/images/redirect_obj.svg";
3 |
4 | Scrivito.provideEditingConfig("Redirect", {
5 | title: "Redirect",
6 | thumbnail: redirectObjIcon,
7 | hideInSelectionDialogs: true,
8 | attributes: {
9 | title: {
10 | title: "Title",
11 | description: "Limit to 55 characters.",
12 | },
13 | link: {
14 | title: "Link",
15 | },
16 | },
17 | properties: ["title", "link"],
18 | validations: [
19 | [
20 | "link",
21 |
22 | (link) => {
23 | if (!link) {
24 | return {
25 | message: "The target must be set.",
26 | severity: "error",
27 | };
28 | }
29 | },
30 | ],
31 | ],
32 | });
33 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/_grid.scss:
--------------------------------------------------------------------------------
1 | // Row
2 | //
3 | // Rows contain your columns.
4 |
5 | @if $enable-grid-classes {
6 | .row {
7 | @include make-row();
8 |
9 | > * {
10 | @include make-col-ready();
11 | }
12 | }
13 | }
14 |
15 | @if $enable-cssgrid {
16 | .grid {
17 | display: grid;
18 | grid-template-rows: repeat(var(--#{$variable-prefix}rows, 1), 1fr);
19 | grid-template-columns: repeat(
20 | var(--#{$variable-prefix}columns, #{$grid-columns}),
21 | 1fr
22 | );
23 | gap: var(--#{$variable-prefix}gap, #{$grid-gutter-width});
24 |
25 | @include make-cssgrid();
26 | }
27 | }
28 |
29 | // Columns
30 | //
31 | // Common styles for small and large grid columns
32 |
33 | @if $enable-grid-classes {
34 | @include make-grid-columns();
35 | }
36 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | orbs:
4 | node: circleci/node@5.0
5 |
6 | jobs:
7 | execute-npm:
8 | parameters:
9 | npm-run-command:
10 | type: string
11 | docker:
12 | - image: cimg/base:stable
13 | environment:
14 | SCRIVITO_TENANT: "1234567890abcdef1234567890abcdef"
15 | steps:
16 | - checkout
17 | - node/install
18 | - node/install-packages
19 | - run: npm run << parameters.npm-run-command >>
20 |
21 | workflows:
22 | main:
23 | jobs:
24 | - execute-npm:
25 | name: npm run build
26 | npm-run-command: build
27 | - execute-npm:
28 | name: npm run eslint
29 | npm-run-command: eslint
30 | - execute-npm:
31 | name: npm run es-check
32 | npm-run-command: es-check
33 |
--------------------------------------------------------------------------------
/src/Widgets/IconWidget/IconWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { IconComponent } from "../../Components/Icon";
4 | import { WrapIfClassName } from "../../Components/WrapIfClassName";
5 | import { alignmentClassName } from "../../utils/alignmentClassName";
6 |
7 | export const IconWidgetComponent = Scrivito.connect(
8 | function IconWidgetComponent({ widget }) {
9 | return (
10 |
11 |
16 |
17 | );
18 | }
19 | );
20 |
21 | Scrivito.provideComponent("IconWidget", IconWidgetComponent);
22 |
--------------------------------------------------------------------------------
/src/Components/BlogPost/BlogPostMorePosts.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { BlogPostPreviewList } from "./BlogPostPreviewList";
4 |
5 | export const BlogPostMorePosts = Scrivito.connect(function BlogPostMorePosts({
6 | author,
7 | filterBlogPostId,
8 | }) {
9 | if (!author) return null;
10 | if (author.objClass() !== "Author") return null;
11 |
12 | return (
13 |
14 |
15 |
16 | More great blog posts from {author.get("title")}
17 |
18 |
22 |
23 |
24 | );
25 | });
26 |
--------------------------------------------------------------------------------
/src/Widgets/FormInputFieldWidget/FormInputFieldWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const FormInputFieldWidget = Scrivito.provideWidgetClass(
4 | "FormInputFieldWidget",
5 | {
6 | attributes: {
7 | label: "string",
8 | placeholder: "string",
9 | required: "boolean",
10 | helpText: "html",
11 | type: [
12 | "enum",
13 | {
14 | values: [
15 | "email",
16 | "name",
17 | "given_name",
18 | "family_name",
19 | "middle_name",
20 | "company",
21 | "phone_number",
22 | "custom",
23 | ],
24 | },
25 | ],
26 | customType: ["enum", { values: ["single_line", "multi_line"] }],
27 | customFieldName: "string",
28 | },
29 | }
30 | );
31 |
--------------------------------------------------------------------------------
/src/Components/ScrivitoExtensions/IconEditorTab/SingleIcon.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { IconComponent } from "../../Icon";
3 |
4 | /* eslint-disable jsx-a11y/anchor-is-valid */
5 | export function SingleIcon({ icon, setWidgetIcon, currentIcon }) {
6 | const cssIcon = `fa-${icon.id}`;
7 |
8 | const aClassNames = [];
9 | if (currentIcon === cssIcon) aClassNames.push("active");
10 |
11 | return (
12 |
23 | );
24 | }
25 | /* eslint-enable jsx-a11y/anchor-is-valid */
26 |
--------------------------------------------------------------------------------
/src/assets/images/button_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/generator-scrivito/app/index.js:
--------------------------------------------------------------------------------
1 | const Generator = require("yeoman-generator");
2 |
3 | module.exports = class extends Generator {
4 | constructor(args, opts) {
5 | super(args, opts);
6 | this.log("Welcome to the Scrivito Obj/Widget generator");
7 | }
8 |
9 | usage() {
10 | return `yo scrivito
11 | yo scrivito:obj []
12 | yo scrivito:widget []`;
13 | }
14 |
15 | async start() {
16 | const answers = await this.prompt({
17 | type: "list",
18 | name: "type",
19 | message: "What do you want to generate?",
20 | choices: ["An Obj class", "A Widget class"],
21 | });
22 |
23 | if (answers.type === "An Obj class") {
24 | this.composeWith("scrivito:obj");
25 | }
26 | if (answers.type === "A Widget class") {
27 | this.composeWith("scrivito:widget");
28 | }
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_animated.scss:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .#{$fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_rotated-flipped.scss:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-rotate-90 {
5 | @include fa-icon-rotate(90deg, 1);
6 | }
7 | .#{$fa-css-prefix}-rotate-180 {
8 | @include fa-icon-rotate(180deg, 2);
9 | }
10 | .#{$fa-css-prefix}-rotate-270 {
11 | @include fa-icon-rotate(270deg, 3);
12 | }
13 |
14 | .#{$fa-css-prefix}-flip-horizontal {
15 | @include fa-icon-flip(-1, 1, 0);
16 | }
17 | .#{$fa-css-prefix}-flip-vertical {
18 | @include fa-icon-flip(1, -1, 2);
19 | }
20 |
21 | // Hook for IE8-9
22 | // -------------------------
23 |
24 | :root .#{$fa-css-prefix}-rotate-90,
25 | :root .#{$fa-css-prefix}-rotate-180,
26 | :root .#{$fa-css-prefix}-rotate-270,
27 | :root .#{$fa-css-prefix}-flip-horizontal,
28 | :root .#{$fa-css-prefix}-flip-vertical {
29 | filter: none;
30 | }
31 |
--------------------------------------------------------------------------------
/src/Objs/Redirect/RedirectComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { InPlaceEditingPlaceholder } from "../../Components/InPlaceEditingPlaceholder";
4 |
5 | Scrivito.provideComponent("Redirect", ({ page }) => {
6 | const link = page.get("link");
7 |
8 | React.useEffect(() => {
9 | if (!link) return;
10 |
11 | Scrivito.load(() => Scrivito.urlFor(link)).then((url) => {
12 | if (link.isExternal()) {
13 | window.top.location.replace(url);
14 | } else {
15 | window.location.replace(url);
16 | }
17 | });
18 | }, [link]);
19 |
20 | if (!link) {
21 | return (
22 |
23 | Select a link in the redirect page properties.
24 |
25 | );
26 | }
27 |
28 | return null;
29 | });
30 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_bordered-pulled.scss:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-border {
5 | padding: 0.2em 0.25em 0.15em;
6 | border: solid 0.08em $fa-border-color;
7 | border-radius: 0.1em;
8 | }
9 |
10 | .#{$fa-css-prefix}-pull-left {
11 | float: left;
12 | }
13 | .#{$fa-css-prefix}-pull-right {
14 | float: right;
15 | }
16 |
17 | .#{$fa-css-prefix} {
18 | &.#{$fa-css-prefix}-pull-left {
19 | margin-right: 0.3em;
20 | }
21 | &.#{$fa-css-prefix}-pull-right {
22 | margin-left: 0.3em;
23 | }
24 | }
25 |
26 | /* Deprecated as of 4.4.0 */
27 | .pull-right {
28 | float: right;
29 | }
30 | .pull-left {
31 | float: left;
32 | }
33 |
34 | .#{$fa-css-prefix} {
35 | &.pull-left {
36 | margin-right: 0.3em;
37 | }
38 | &.pull-right {
39 | margin-left: 0.3em;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_transition.scss:
--------------------------------------------------------------------------------
1 | // stylelint-disable property-disallowed-list
2 | @mixin transition($transition...) {
3 | @if length($transition) == 0 {
4 | $transition: $transition-base;
5 | }
6 |
7 | @if length($transition) > 1 {
8 | @each $value in $transition {
9 | @if $value == null or $value == none {
10 | @warn "The keyword 'none' or 'null' must be used as a single argument.";
11 | }
12 | }
13 | }
14 |
15 | @if $enable-transitions {
16 | @if nth($transition, 1) != null {
17 | transition: $transition;
18 | }
19 |
20 | @if $enable-reduced-motion and
21 | nth($transition, 1) !=
22 | null and
23 | nth($transition, 1) !=
24 | none
25 | {
26 | @media (prefers-reduced-motion: reduce) {
27 | transition: none;
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Widgets/TickListWidget/TickListWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import tickListWidgetIcon from "../../assets/images/tick_list_widget.svg";
3 | import { TickListItemWidget } from "../TickListItemWidget/TickListItemWidgetClass";
4 |
5 | Scrivito.provideEditingConfig("TickListWidget", {
6 | title: "Tick List",
7 | thumbnail: tickListWidgetIcon,
8 | initialContent: {
9 | items: [
10 | new TickListItemWidget({}),
11 | new TickListItemWidget({}),
12 | new TickListItemWidget({}),
13 | ],
14 | },
15 | validations: [
16 | [
17 | "items",
18 |
19 | (items) => {
20 | if (items.length < 1) {
21 | return {
22 | message: "The ticklist must include at least one item.",
23 | severity: "error",
24 | };
25 | }
26 | },
27 | ],
28 | ],
29 | });
30 |
--------------------------------------------------------------------------------
/src/assets/images/video_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/Widgets/BlogOverviewWidget/BlogOverviewWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import blogOverviewWidgetIcon from "../../assets/images/blog_overview_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("BlogOverviewWidget", {
5 | title: "Blog Overview",
6 | thumbnail: blogOverviewWidgetIcon,
7 | attributes: {
8 | maxItems: {
9 | title: "Maximum number of blog posts",
10 | description: "Set to 0 to show all blog posts.",
11 | },
12 | author: {
13 | title: "Filter by author",
14 | description: "Leave empty to not filter by author.",
15 | },
16 | tags: {
17 | title: "Filter by tags",
18 | description:
19 | "Only show blog posts, that have one of the given tags." +
20 | " Leave empty to not filter by tags.",
21 | },
22 | },
23 | properties: ["maxItems", "author", "tags"],
24 | });
25 |
--------------------------------------------------------------------------------
/src/Widgets/FactWidget/FactWidget.scss:
--------------------------------------------------------------------------------
1 | @import "src/assets/stylesheets/variables";
2 |
3 | .fact-widget {
4 | padding: 30px 0;
5 |
6 | .value,
7 | .key {
8 | display: block;
9 | text-align: center;
10 | }
11 |
12 | .value {
13 | color: $primary;
14 | font-size: 80px;
15 | line-height: 80px;
16 | font-weight: 700;
17 | }
18 |
19 | .key {
20 | color: $theme-greydark;
21 | font-size: 18px;
22 | line-height: 22px;
23 | }
24 |
25 | span:empty {
26 | min-width: 20px !important;
27 | display: block;
28 | background: rgba(0, 255, 0, 0.2);
29 | }
30 | }
31 |
32 | .bg-grey,
33 | .bg-greymiddle,
34 | .bg-greydark,
35 | .bg-dark-image {
36 | .fact-widget .key {
37 | color: $theme-greylight;
38 | }
39 | }
40 |
41 | .bg-brand-primary,
42 | .bg-brand-secondary {
43 | .fact-widget .value {
44 | color: #fff;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Components/AuthorImage.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { InPlaceEditingPlaceholder } from "./InPlaceEditingPlaceholder";
4 | import { isImageObj } from "../utils/isImageObj";
5 |
6 | export const AuthorImage = Scrivito.connect(function AuthorImage({ image }) {
7 | if (!isImageObj(image)) {
8 | return (
9 |
10 | Click here to select an author image.
11 |
12 | );
13 | }
14 |
15 | return (
16 |
26 | );
27 | });
28 |
--------------------------------------------------------------------------------
/src/Objs/Blog/BlogComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { BlogPost } from "../BlogPost/BlogPostObjClass";
4 | import { navigateToBlogWithTag } from "../../utils/navigateToBlogWithTag";
5 | import { SchemaDotOrg } from "../../Components/SchemaDotOrg";
6 | import { TagList } from "../../Components/TagList";
7 |
8 | Scrivito.provideComponent("Blog", ({ page, params }) => {
9 | const tags = [...BlogPost.all().facet("tags")].map((facet) => facet.name());
10 | const currentTag = params.tag;
11 |
12 | return (
13 |
14 |
20 |
21 |
22 |
23 | );
24 | });
25 |
--------------------------------------------------------------------------------
/src/Widgets/AddressWidget/AddressWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const AddressWidget = Scrivito.provideWidgetClass("AddressWidget", {
4 | attributes: {
5 | showLogo: "boolean",
6 | showBorderBottom: "boolean",
7 |
8 | locationName: "string",
9 | locationStreetAddress: "string",
10 | locationLocality: "string",
11 | locationPostalCode: "string",
12 | locationRegion: "string",
13 | locationCountry: "string",
14 | addressFormat: ["enum", { values: ["USA", "GER"] }],
15 |
16 | phone: "string",
17 | fax: "string",
18 | email: "string",
19 | },
20 | extractTextAttributes: [
21 | "locationName",
22 | "locationStreetAddress",
23 | "locationLocality",
24 | "locationPostalCode",
25 | "locationRegion",
26 | "locationCountry",
27 | "phone",
28 | "fax",
29 | "email",
30 | ],
31 | });
32 |
--------------------------------------------------------------------------------
/src/Widgets/ColumnContainerWidget/ColumnContainerWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import columnContainerWidgetIcon from "../../assets/images/column_container_widget.svg";
3 | import { ColumnsEditorTab } from "../../Components/ScrivitoExtensions/ColumnsEditorTab";
4 | import { ColumnWidget } from "../ColumnWidget/ColumnWidgetClass";
5 |
6 | Scrivito.provideEditingConfig("ColumnContainerWidget", {
7 | title: "Columns",
8 | thumbnail: columnContainerWidgetIcon,
9 | propertiesGroups: [
10 | {
11 | title: "Columns layout",
12 | component: ColumnsEditorTab,
13 | key: "columns-layout-group",
14 | },
15 | ],
16 | initialContent: {
17 | columns: [
18 | new ColumnWidget({ colSize: 4 }),
19 | new ColumnWidget({ colSize: 4 }),
20 | new ColumnWidget({ colSize: 4 }),
21 | ],
22 | alignment: "start",
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/src/Widgets/EventOverviewWidget/EventOverviewWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import eventOverviewWidgetIcon from "../../assets/images/event_overview_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("EventOverviewWidget", {
5 | title: "Event Overview",
6 | thumbnail: eventOverviewWidgetIcon,
7 | attributes: {
8 | maxItems: {
9 | title: "Maximum number of events",
10 | description: "Set to 0 to show all events.",
11 | },
12 | tags: {
13 | title: "Filter by tags",
14 | description:
15 | "Only show events, that have one of the given tags." +
16 | " Leave empty to not filter by tags.",
17 | },
18 | showTags: {
19 | title: "Show list of tags?",
20 | description: "Default: No",
21 | },
22 | },
23 | properties: ["maxItems", "showTags", "tags"],
24 | initialContent: {
25 | maxItems: 0,
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/src/Widgets/TableRowWidget/TableRowWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | function PlainTableRowWidgetComponent({ widget, header2, header3, header4 }) {
5 | return (
6 |
7 |
8 |
14 |
20 |
26 |
27 | );
28 | }
29 |
30 | export const TableRowWidgetComponent = Scrivito.connect(
31 | PlainTableRowWidgetComponent
32 | );
33 |
--------------------------------------------------------------------------------
/src/Widgets/ThumbnailGalleryWidget/ThumbnailGalleryWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import thumbnailGalleryWidgetIcon from "../../assets/images/thumbnail_gallery_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("ThumbnailGalleryWidget", {
5 | title: "Thumbnail Gallery",
6 | thumbnail: thumbnailGalleryWidgetIcon,
7 | attributes: {
8 | images: {
9 | title: "Images",
10 | },
11 | showTags: {
12 | title: "Show list of tags?",
13 | description: "Default: No",
14 | },
15 | },
16 | properties: ["images", "showTags"],
17 | validations: [
18 | [
19 | "images",
20 |
21 | (images) => {
22 | if (images.length < 1) {
23 | return {
24 | message: "The thumbnail gallery should contain at least one image.",
25 | severity: "warning",
26 | };
27 | }
28 | },
29 | ],
30 | ],
31 | });
32 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_pagination.scss:
--------------------------------------------------------------------------------
1 | // Pagination
2 |
3 | // scss-docs-start pagination-mixin
4 | @mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) {
5 | .page-link {
6 | padding: $padding-y $padding-x;
7 | @include font-size($font-size);
8 | }
9 |
10 | .page-item {
11 | @if $pagination-margin-start == (-$pagination-border-width) {
12 | &:first-child {
13 | .page-link {
14 | @include border-start-radius($border-radius);
15 | }
16 | }
17 |
18 | &:last-child {
19 | .page-link {
20 | @include border-end-radius($border-radius);
21 | }
22 | }
23 | } @else {
24 | //Add border-radius to all pageLinks in case they have left margin
25 | .page-link {
26 | @include border-radius($border-radius);
27 | }
28 | }
29 | }
30 | }
31 | // scss-docs-end pagination-mixin
32 |
--------------------------------------------------------------------------------
/src/Objs/Homepage/HomepageObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { defaultPageAttributes } from "../_defaultPageAttributes";
3 | import { metadataAttributes } from "../_metadataAttributes";
4 |
5 | export const Homepage = Scrivito.provideObjClass("Homepage", {
6 | attributes: {
7 | ...defaultPageAttributes,
8 | showAsLandingPage: "boolean",
9 | cookieConsentLink: "link",
10 | contentTitle: "string",
11 | footer: ["widgetlist", { only: "SectionWidget" }],
12 | logoDark: ["reference", { only: ["Image"] }],
13 | logoWhite: ["reference", { only: ["Image"] }],
14 | dividerLogo: ["reference", { only: ["Image"] }],
15 | facebookAppId: "string",
16 | twitterSite: "string",
17 | googleMapsApiKey: "string",
18 | intercomAppId: "string",
19 | ...metadataAttributes,
20 | },
21 | extractTextAttributes: ["navigationSection", "body"],
22 | onlyAsRoot: true,
23 | });
24 |
--------------------------------------------------------------------------------
/src/Components/SchemaDotOrg/dataFromBlogPost.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { truncate } from "lodash-es";
3 | import { dataFromAuthor } from "./dataFromAuthor";
4 | import { formatDate } from "../../utils/formatDate";
5 | import { urlFromBinaryObj } from "../../utils/urlFromBinaryObj";
6 |
7 | export function dataFromBlogPost(blogPost) {
8 | const description = Scrivito.extractText(blogPost, { length: 330 });
9 | return {
10 | "@context": "http://schema.org",
11 | "@type": "BlogPosting",
12 | author: blogPost.get("author")
13 | ? dataFromAuthor(blogPost.get("author"))
14 | : undefined,
15 | datePublished: formatDate(blogPost.get("publishedAt"), "yyyy-mm-dd"),
16 | description: truncate(description, { length: 300 }),
17 | headline: blogPost.get("title"),
18 | image: urlFromBinaryObj(blogPost.get("titleImage")),
19 | keywords: blogPost.get("tags").join(", "),
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/src/Components/Navigation/Logo.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | function logoObj({ scrolled, navigationStyle }) {
5 | let logoVersion;
6 | if (scrolled) {
7 | logoVersion = "logoDark";
8 | } else if (navigationStyle === "transparentDark") {
9 | logoVersion = "logoWhite";
10 | } else {
11 | logoVersion = "logoDark";
12 | }
13 |
14 | const root = Scrivito.Obj.root();
15 | if (root) return root.get(logoVersion);
16 |
17 | return undefined;
18 | }
19 |
20 | export const Logo = Scrivito.connect(function Logo({
21 | scrolled,
22 | navigationStyle,
23 | }) {
24 | if (!Scrivito.Obj.root()) return null;
25 |
26 | const logo = logoObj({ scrolled, navigationStyle });
27 |
28 | return (
29 |
30 |
31 |
32 | );
33 | });
34 |
--------------------------------------------------------------------------------
/src/Widgets/CarouselWidget/CarouselWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import carouselWidgetIcon from "../../assets/images/carousel_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("CarouselWidget", {
5 | title: "Carousel",
6 | thumbnail: carouselWidgetIcon,
7 | attributes: {
8 | images: {
9 | title: "Images",
10 | },
11 | showDescription: {
12 | title: "Show description?",
13 | description:
14 | "This allows to show an image and some text below this carousel. Default: No",
15 | },
16 | },
17 | properties: ["images", "showDescription"],
18 | validations: [
19 | [
20 | "images",
21 |
22 | (images) => {
23 | if (images.length < 1) {
24 | return {
25 | message: "The carousel should contain at least one image.",
26 | severity: "warning",
27 | };
28 | }
29 | },
30 | ],
31 | ],
32 | });
33 |
--------------------------------------------------------------------------------
/src/Widgets/FeaturePanelWidget/FeaturePanelWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import featurePanelWidgetIcon from "../../assets/images/feature_panel_widget.svg";
3 | import { IconEditorTab } from "../../Components/ScrivitoExtensions/IconEditorTab";
4 |
5 | Scrivito.provideEditingConfig("FeaturePanelWidget", {
6 | title: "Feature Panel",
7 | thumbnail: featurePanelWidgetIcon,
8 | propertiesGroups: [
9 | {
10 | title: "Icon",
11 | component: IconEditorTab,
12 | key: "icon-group",
13 | },
14 | ],
15 | initialContent: {
16 | icon: "fa-check",
17 | headline: "Lorem Ipsum",
18 | },
19 | validations: [
20 | [
21 | "headline",
22 |
23 | (headline) => {
24 | if (!headline) {
25 | return {
26 | message: "The headline should be set.",
27 | severity: "warning",
28 | };
29 | }
30 | },
31 | ],
32 | ],
33 | });
34 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/fontawesome/_path.scss:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: "FontAwesome";
6 | src: url("#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}");
7 | src: url("#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}")
8 | format("embedded-opentype"),
9 | url("#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}")
10 | format("woff2"),
11 | url("#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}")
12 | format("woff"),
13 | url("#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}")
14 | format("truetype"),
15 | url("#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular")
16 | format("svg");
17 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
18 | font-weight: normal;
19 | font-style: normal;
20 | font-display: swap;
21 | }
22 |
--------------------------------------------------------------------------------
/src/assets/images/divider_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/Widgets/HeadlineWidget/HeadlineWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import * as speakingUrl from "speakingurl";
4 | import { alignmentClassName } from "../../utils/alignmentClassName";
5 |
6 | Scrivito.provideComponent("HeadlineWidget", ({ widget }) => {
7 | const style = widget.get("style") || "h2";
8 | const level = widget.get("level") || style;
9 | const classNames = [style];
10 |
11 | const alignment = alignmentClassName(widget.get("alignment"));
12 | if (alignment) classNames.push(alignment);
13 |
14 | if (widget.get("showDividingLine")) classNames.push("b-bottom");
15 | if (!widget.get("showMargin")) classNames.push("no-margin");
16 |
17 | return (
18 |
25 | );
26 | });
27 |
--------------------------------------------------------------------------------
/src/Widgets/ThumbnailGalleryImageWidget/ThumbnailGalleryImageWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import thumbnailGalleryImageWidgetIcon from "../../assets/images/thumbnail_gallery_image_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("ThumbnailGalleryImageWidget", {
5 | title: "Thumbnail Gallery Image",
6 | thumbnail: thumbnailGalleryImageWidgetIcon,
7 | attributes: {
8 | image: {
9 | title: "Image",
10 | },
11 | title: {
12 | title: "Title",
13 | },
14 | subtitle: {
15 | title: "Subtitle",
16 | },
17 | tags: {
18 | title: "Tags",
19 | },
20 | },
21 | properties: ["image", "title", "subtitle", "tags"],
22 | titleForContent: (widget) => {
23 | const parts = [widget.get("title"), widget.get("subtitle")];
24 | const summary = parts.filter((e) => e).join(" - ");
25 |
26 | if (summary) {
27 | return `Thumbnail Gallery Image: ${summary}`;
28 | }
29 | },
30 | });
31 |
--------------------------------------------------------------------------------
/src/prerenderContent/storeResult.js:
--------------------------------------------------------------------------------
1 | import filesize from "filesize";
2 | import fse from "fs-extra";
3 | import path from "path";
4 |
5 | import { reportError } from "./reportError";
6 |
7 | export async function storeResult(targetDir, { filename, content }) {
8 | const filePath = path.join(targetDir, filename);
9 | if (!path.normalize(filePath).startsWith(`${targetDir}`)) {
10 | reportError(`filename "${filename}" is invalid! Skipping file...`);
11 | return;
12 | }
13 | console.log(
14 | ` 📥 [storeResult] Storing "${filename}" (file size: ${filesize(
15 | content.length
16 | )})...`
17 | );
18 | try {
19 | await fse.outputFile(filePath, content, { flag: "wx" });
20 | return filePath.substring(targetDir.length);
21 | } catch (e) {
22 | if (e.code === "EEXIST") {
23 | reportError(
24 | `Filename "${filename}" already exists in ${targetDir}! Skipping file...`
25 | );
26 | } else {
27 | throw e;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Widgets/LinkWidget/LinkWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { InPlaceEditingPlaceholder } from "../../Components/InPlaceEditingPlaceholder";
4 |
5 | Scrivito.provideComponent("LinkWidget", ({ widget }) => {
6 | const link = widget.get("link");
7 |
8 | if (!link) {
9 | return (
10 |
11 |
12 | Provide a link in the widget properties.
13 |
14 |
15 | );
16 | }
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 | );
25 | });
26 |
27 | const LinkTitle = Scrivito.connect(({ link }) => {
28 | if (link.title()) return link.title();
29 | if (link.isInternal()) return link.obj().get("title");
30 |
31 | return link.url();
32 | });
33 |
--------------------------------------------------------------------------------
/src/Widgets/VideoWidget/VideoWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import videoWidgetIcon from "../../assets/images/video_widget.svg";
3 |
4 | Scrivito.provideEditingConfig("VideoWidget", {
5 | title: "Video",
6 | thumbnail: videoWidgetIcon,
7 | attributes: {
8 | source: {
9 | title: "Video",
10 | description:
11 | "Click to select or upload video. This should be of type video/mp4.",
12 | },
13 | poster: {
14 | title: "Poster image (optional)",
15 | description:
16 | "This poster image is shown, until the video is loaded." +
17 | " Without an poster image, the browser may show the first frame of the video.",
18 | },
19 | },
20 | properties: ["source", "poster"],
21 | validations: [
22 | [
23 | "source",
24 |
25 | (source) => {
26 | if (!source) {
27 | return { message: "The video should be set.", severity: "warning" };
28 | }
29 | },
30 | ],
31 | ],
32 | });
33 |
--------------------------------------------------------------------------------
/src/Widgets/TestimonialSliderWidget/TestimonialSliderWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import testimonialSliderWidgetIcon from "../../assets/images/testimonial_slider_widget.svg";
3 | import { TestimonialWidget } from "../TestimonialWidget/TestimonialWidgetClass";
4 |
5 | Scrivito.provideEditingConfig("TestimonialSliderWidget", {
6 | title: "Testimonial Slider",
7 | thumbnail: testimonialSliderWidgetIcon,
8 | attributes: {
9 | testimonials: {
10 | title: "Testimonials",
11 | },
12 | },
13 | properties: ["testimonials"],
14 | initialContent: {
15 | testimonials: [new TestimonialWidget({})],
16 | },
17 | validations: [
18 | [
19 | "testimonials",
20 |
21 | (testimonials) => {
22 | if (testimonials.length < 1) {
23 | return {
24 | message: "The testimonial slider must contain at least one entry.",
25 | severity: "error",
26 | };
27 | }
28 | },
29 | ],
30 | ],
31 | });
32 |
--------------------------------------------------------------------------------
/src/Widgets/GoogleMapsWidget/GoogleMapsWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const GoogleMapsWidget = Scrivito.provideWidgetClass(
4 | "GoogleMapsWidget",
5 | {
6 | attributes: {
7 | address: "string",
8 | mapType: ["enum", { values: ["interactive", "static"] }],
9 | zoom: [
10 | "enum",
11 | {
12 | values: [
13 | "1",
14 | "2",
15 | "3",
16 | "4",
17 | "5",
18 | "6",
19 | "7",
20 | "8",
21 | "9",
22 | "10",
23 | "11",
24 | "12",
25 | "13",
26 | "14",
27 | "15",
28 | "16",
29 | "17",
30 | "18",
31 | "19",
32 | "20",
33 | ],
34 | },
35 | ],
36 | showWidgets: "boolean",
37 | content: "widgetlist",
38 | },
39 | extractTextAttributes: ["content"],
40 | }
41 | );
42 |
--------------------------------------------------------------------------------
/src/Widgets/VideoWidget/VideoWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { urlFromBinaryObj } from "../../utils/urlFromBinaryObj";
4 | import { videoPlaceholder } from "./videoPlaceholder";
5 |
6 | Scrivito.provideComponent("VideoWidget", ({ widget }) => {
7 | const videoUrl = urlFromBinaryObj(widget.get("source"));
8 |
9 | if (!videoUrl && !Scrivito.isInPlaceEditingActive()) {
10 | return null;
11 | }
12 |
13 | const posterUrl = urlFromBinaryObj(widget.get("poster"));
14 | const src = posterUrl ? videoUrl : `${videoUrl}#t=0.01`;
15 |
16 | let style = {};
17 | if (Scrivito.isInPlaceEditingActive() && !videoUrl && !posterUrl) {
18 | style = videoPlaceholder;
19 | }
20 |
21 | return (
22 |
32 | );
33 | });
34 |
--------------------------------------------------------------------------------
/src/Objs/Page/PageEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import PageObjIcon from "../../assets/images/page_obj.svg";
3 | import {
4 | defaultPageEditingConfigAttributes,
5 | defaultPageInitialContent,
6 | defaultPageProperties,
7 | defaultPageValidations,
8 | } from "../_defaultPageEditingConfig";
9 | import {
10 | metadataEditingConfigAttributes,
11 | metadataInitialContent,
12 | metadataPropertiesGroups,
13 | metadataValidations,
14 | } from "../_metadataEditingConfig";
15 |
16 | Scrivito.provideEditingConfig("Page", {
17 | title: "Page",
18 | thumbnail: PageObjIcon,
19 | attributes: {
20 | ...defaultPageEditingConfigAttributes,
21 | ...metadataEditingConfigAttributes,
22 | },
23 | properties: (obj) => [...defaultPageProperties(obj)],
24 | propertiesGroups: [...metadataPropertiesGroups],
25 | initialContent: {
26 | ...defaultPageInitialContent,
27 | ...metadataInitialContent,
28 | },
29 | validations: [...defaultPageValidations, ...metadataValidations],
30 | });
31 |
--------------------------------------------------------------------------------
/src/Components/CurrentPageMetadata.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { Helmet } from "react-helmet-async";
4 | import { getMetadata } from "../utils/getMetadata";
5 | import favicon from "../assets/images/favicon.png";
6 |
7 | export const CurrentPageMetadata = Scrivito.connect(() => {
8 | let lang = "en";
9 | let title = "";
10 | let meta = [];
11 | const links = [
12 | {
13 | rel: "shortcut icon",
14 | type: "image/png",
15 | href: favicon,
16 | },
17 | ];
18 |
19 | const page = Scrivito.currentPage();
20 | if (page) {
21 | lang = page.language() || "en";
22 | title = page.get("title") || "";
23 | meta = getMetadata(page);
24 | links.push({ rel: "canonical", href: Scrivito.urlFor(page) });
25 | }
26 |
27 | const htmlAttributes = { lang };
28 |
29 | return (
30 |
36 | );
37 | });
38 |
--------------------------------------------------------------------------------
/src/assets/images/redirect_obj.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
--------------------------------------------------------------------------------
/src/assets/images/testimonial_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/src/catch_all_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 | Your Scrivito powered site is loading ...
12 |
13 |
14 |
15 | <%= htmlWebpackPlugin.tags.headTags %>
16 |
17 |
18 |
19 |
20 |
21 |
22 | Your Scrivito powered site is
23 | loading ...
24 |
25 |
26 | <%= htmlWebpackPlugin.tags.bodyTags %>
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/generator-scrivito/generators/obj/templates/XEditingConfig.js.ejs:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import HeadlineWidget from "../../Widgets/HeadlineWidget/HeadlineWidgetClass";
3 | import SectionWidget from "../../Widgets/SectionWidget/SectionWidgetClass";
4 | import {
5 | metadataEditingConfigAttributes,
6 | metadataInitialContent,
7 | metadataPropertiesGroups,
8 | metadataValidations,
9 | } from "../_metadataEditingConfig";
10 |
11 | Scrivito.provideEditingConfig("<%= objClassName %>", {
12 | title: "<%= humanFriendlyName %>",
13 | attributes: {
14 | ...metadataEditingConfigAttributes,
15 | title: {
16 | title: "Title",
17 | description: "Limit to 55 characters.",
18 | },
19 | },
20 | properties: ["title"],
21 | propertiesGroups: [...metadataPropertiesGroups],
22 | initialContent: {
23 | body: [
24 | new SectionWidget({
25 | content: [new HeadlineWidget({ style: "h1" })],
26 | }),
27 | ],
28 | ...metadataInitialContent,
29 | },
30 | validations: [...metadataValidations],
31 | });
32 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as ReactDOM from "react-dom/client";
3 | import * as Scrivito from "scrivito";
4 | import "./Objs";
5 | import "./Widgets";
6 | import { App } from "./App";
7 | import { configure } from "./config";
8 | import "./assets/stylesheets/index.scss";
9 |
10 | configure();
11 |
12 | if (window.preloadDump) {
13 | Scrivito.preload(window.preloadDump).then(({ dumpLoaded }) => {
14 | delete window.preloadDump;
15 | dumpLoaded ? hydrateApp() : renderApp();
16 | });
17 | } else {
18 | renderApp();
19 | }
20 |
21 | function renderApp() {
22 | ReactDOM.createRoot(document.getElementById("application")).render();
23 | }
24 |
25 | function hydrateApp() {
26 | ReactDOM.hydrateRoot(
27 | document.getElementById("application"),
28 | {
30 | if (el) Scrivito.updateContent();
31 | }}
32 | />
33 | );
34 | }
35 |
36 | if (Scrivito.isEditorLoggedIn()) {
37 | import("./Objs/editingConfigs");
38 | import("./Widgets/editingConfigs");
39 | }
40 |
--------------------------------------------------------------------------------
/src/Widgets/LinkContainerWidget/LinkContainerWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 |
4 | import { InPlaceEditingPlaceholder } from "../../Components/InPlaceEditingPlaceholder";
5 | import "./LinkContainerWidget.scss";
6 |
7 | Scrivito.provideComponent("LinkContainerWidget", ({ widget }) => (
8 |
9 |
10 |
16 |
17 | ));
18 |
19 | const Headline = Scrivito.connect(({ widget }) => {
20 | const headline = widget.get("headline");
21 |
22 | if (!headline) {
23 | return (
24 |
25 | Optional: Provide a headline in the widget properties.
26 |
27 | );
28 | }
29 |
30 | return (
31 |
32 | {widget.get("headline")}
33 |
34 | );
35 | });
36 |
--------------------------------------------------------------------------------
/src/Objs/LandingPage/LandingPageEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import landingPageObjIcon from "../../assets/images/landing_page_obj.svg";
3 | import {
4 | defaultPageEditingConfigAttributes,
5 | defaultPageInitialContent,
6 | defaultPageProperties,
7 | defaultPageValidations,
8 | } from "../_defaultPageEditingConfig";
9 | import {
10 | metadataEditingConfigAttributes,
11 | metadataInitialContent,
12 | metadataPropertiesGroups,
13 | metadataValidations,
14 | } from "../_metadataEditingConfig";
15 |
16 | Scrivito.provideEditingConfig("LandingPage", {
17 | title: "Landing Page",
18 | thumbnail: landingPageObjIcon,
19 | attributes: {
20 | ...defaultPageEditingConfigAttributes,
21 | ...metadataEditingConfigAttributes,
22 | },
23 | properties: (obj) => [...defaultPageProperties(obj)],
24 | propertiesGroups: [...metadataPropertiesGroups],
25 | initialContent: {
26 | ...defaultPageInitialContent,
27 | ...metadataInitialContent,
28 | },
29 | validations: [...defaultPageValidations, ...metadataValidations],
30 | });
31 |
--------------------------------------------------------------------------------
/src/assets/images/icon_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/feature_panel_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_table-variants.scss:
--------------------------------------------------------------------------------
1 | // scss-docs-start table-variant
2 | @mixin table-variant($state, $background) {
3 | .table-#{$state} {
4 | $color: color-contrast(opaque($body-bg, $background));
5 | $hover-bg: mix($color, $background, percentage($table-hover-bg-factor));
6 | $striped-bg: mix($color, $background, percentage($table-striped-bg-factor));
7 | $active-bg: mix($color, $background, percentage($table-active-bg-factor));
8 |
9 | --#{$variable-prefix}table-bg: #{$background};
10 | --#{$variable-prefix}table-striped-bg: #{$striped-bg};
11 | --#{$variable-prefix}table-striped-color: #{color-contrast($striped-bg)};
12 | --#{$variable-prefix}table-active-bg: #{$active-bg};
13 | --#{$variable-prefix}table-active-color: #{color-contrast($active-bg)};
14 | --#{$variable-prefix}table-hover-bg: #{$hover-bg};
15 | --#{$variable-prefix}table-hover-color: #{color-contrast($hover-bg)};
16 |
17 | color: $color;
18 | border-color: mix($color, $background, percentage($table-border-factor));
19 | }
20 | }
21 | // scss-docs-end table-variant
22 |
--------------------------------------------------------------------------------
/src/Widgets/GoogleMapsWidget/GoogleMapsWidget.scss:
--------------------------------------------------------------------------------
1 | @import "src/assets/stylesheets/variables";
2 |
3 | .google-maps-widget {
4 | overflow: hidden;
5 | position: relative;
6 | min-height: 350px;
7 |
8 | a,
9 | a:hover,
10 | a:focus {
11 | color: $theme-greydark;
12 | text-decoration: none;
13 | }
14 |
15 | .b-bottom {
16 | padding: 0 0 20px 0;
17 | }
18 |
19 | .card {
20 | padding: 30px;
21 | margin: 40px 0 100px 0;
22 | background: #fff;
23 | }
24 |
25 | iframe {
26 | left: 0;
27 | top: 0;
28 | height: 100%;
29 | width: 100%;
30 | position: absolute;
31 | }
32 |
33 | .social-links i {
34 | padding: 10px 15px;
35 | }
36 |
37 | table td {
38 | padding: 0 5px 0 0;
39 | }
40 | }
41 |
42 | @media (max-width: $screen-xs-max) {
43 | .google-maps-widget .card {
44 | margin: 200px 0 -10px 0;
45 | }
46 | }
47 |
48 | /* google maps fix
49 | ================================================== */
50 |
51 | .gm-style img {
52 | max-width: none !important;
53 | }
54 | .gm-style label {
55 | width: auto;
56 | display: inline;
57 | }
58 |
--------------------------------------------------------------------------------
/src/Objs/Job/JobObjClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { metadataAttributes } from "../_metadataAttributes";
3 |
4 | export const Job = Scrivito.provideObjClass("Job", {
5 | attributes: {
6 | body: ["widgetlist", { only: "SectionWidget" }],
7 | image: ["reference", { only: ["Image"] }],
8 | title: "string",
9 |
10 | datePosted: "date",
11 | validThrough: "date",
12 |
13 | hiringOrganizationName: "string",
14 | hiringOrganizationWebsite: "string",
15 |
16 | locationStreetAddress: "string",
17 | locationLocality: "string",
18 | locationRegion: "string",
19 | locationPostalCode: "string",
20 | locationCountry: "string",
21 |
22 | employmentType: [
23 | "multienum",
24 | {
25 | values: [
26 | "FULL_TIME",
27 | "PART_TIME",
28 | "CONTRACTOR",
29 | "TEMPORARY",
30 | "INTERN",
31 | "VOLUNTEER",
32 | "PER_DIEM",
33 | "OTHER",
34 | ],
35 | },
36 | ],
37 |
38 | ...metadataAttributes,
39 | },
40 | extractTextAttributes: ["body"],
41 | });
42 |
--------------------------------------------------------------------------------
/src/Widgets/PricingWidget/PricingWidgetClass.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 |
3 | export const PricingWidget = Scrivito.provideWidgetClass("PricingWidget", {
4 | attributes: {
5 | currency: "string",
6 |
7 | // Plan Names
8 | smallPlanName: "string",
9 | mediumPlanName: "string",
10 | largePlanName: "string",
11 |
12 | // Plan Prices
13 | smallPlanPrice: "string",
14 | mediumPlanPrice: "string",
15 | largePlanPrice: "string",
16 |
17 | // Plan Periods
18 | smallPlanPeriod: "string",
19 | mediumPlanPeriod: "string",
20 | largePlanPeriod: "string",
21 |
22 | // Plan Specs
23 | smallPlanSpecs: ["widgetlist", { only: "PricingSpecWidget" }],
24 | mediumPlanSpecs: ["widgetlist", { only: "PricingSpecWidget" }],
25 | largePlanSpecs: ["widgetlist", { only: "PricingSpecWidget" }],
26 |
27 | // Plan Buttons
28 | smallPlanButton: "link",
29 | mediumPlanButton: "link",
30 | largePlanButton: "link",
31 | },
32 | extractTextAttributes: [
33 | "smallPlanSpecs",
34 | "mediumPlanSpecs",
35 | "largePlanSpecs",
36 | ],
37 | });
38 |
--------------------------------------------------------------------------------
/src/assets/images/section_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Toggles
2 | //
3 | // Used in conjunction with global variables to enable certain theme features.
4 |
5 | // Vendor
6 | @import "vendor/rfs";
7 |
8 | // Deprecate
9 | @import "mixins/deprecate";
10 |
11 | // Helpers
12 | @import "mixins/breakpoints";
13 | @import "mixins/color-scheme";
14 | @import "mixins/image";
15 | @import "mixins/resize";
16 | @import "mixins/visually-hidden";
17 | @import "mixins/reset-text";
18 | @import "mixins/text-truncate";
19 |
20 | // Utilities
21 | @import "mixins/utilities";
22 |
23 | // Components
24 | @import "mixins/alert";
25 | @import "mixins/backdrop";
26 | @import "mixins/buttons";
27 | @import "mixins/caret";
28 | @import "mixins/pagination";
29 | @import "mixins/lists";
30 | @import "mixins/list-group";
31 | @import "mixins/forms";
32 | @import "mixins/table-variants";
33 |
34 | // Skins
35 | @import "mixins/border-radius";
36 | @import "mixins/box-shadow";
37 | @import "mixins/gradients";
38 | @import "mixins/transition";
39 |
40 | // Layout
41 | @import "mixins/clearfix";
42 | @import "mixins/container";
43 | @import "mixins/grid";
44 |
--------------------------------------------------------------------------------
/src/Objs/Blog/BlogEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import blogObjIcon from "../../assets/images/blog_obj.svg";
3 | import { SectionWidget } from "../../Widgets/SectionWidget/SectionWidgetClass";
4 | import {
5 | metadataEditingConfigAttributes,
6 | metadataInitialContent,
7 | metadataPropertiesGroups,
8 | metadataValidations,
9 | } from "../_metadataEditingConfig";
10 |
11 | Scrivito.provideEditingConfig("Blog", {
12 | title: "Blog",
13 | thumbnail: blogObjIcon,
14 | hideInSelectionDialogs: true,
15 | attributes: {
16 | ...metadataEditingConfigAttributes,
17 | title: {
18 | title: "Title",
19 | description: "Limit to 55 characters.",
20 | },
21 | navigationBackgroundImage: {
22 | title: "Header image",
23 | description: "The background image of the header.",
24 | },
25 | },
26 | properties: ["title", "navigationBackgroundImage"],
27 | propertiesGroups: [...metadataPropertiesGroups],
28 | initialContent: {
29 | ...metadataInitialContent,
30 | body: [new SectionWidget({})],
31 | },
32 | validations: [...metadataValidations],
33 | });
34 |
--------------------------------------------------------------------------------
/src/Widgets/IconContainerWidget/IconContainerWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { IconComponent } from "../../Components/Icon";
4 | import { InPlaceEditingPlaceholder } from "../../Components/InPlaceEditingPlaceholder";
5 |
6 | Scrivito.provideComponent("IconContainerWidget", ({ widget }) => {
7 | const icons = widget.get("iconList");
8 |
9 | if (!icons.length) {
10 | return (
11 |
12 | Select icons in the widget properties.
13 |
14 | );
15 | }
16 |
17 | return (
18 |
19 | {icons.map((iconListItem) => {
20 | const icon = iconListItem.get("icon");
21 | const link = iconListItem.get("link");
22 | const size = iconListItem.get("size");
23 |
24 | return (
25 |
31 | );
32 | })}
33 |
34 | );
35 | });
36 |
--------------------------------------------------------------------------------
/src/assets/images/tick_list_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/space_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/Components/BlogPost/BlogPostTagList.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { navigateToBlogWithTag } from "../../utils/navigateToBlogWithTag";
4 |
5 | /* eslint-disable jsx-a11y/anchor-is-valid */
6 | export const BlogPostTagList = Scrivito.connect(function BlogPostTagList({
7 | tags,
8 | }) {
9 | return (
10 |
33 | );
34 | });
35 | /* eslint-enable jsx-a11y/anchor-is-valid */
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 JustRelate Group GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/Objs/SearchResults/SearchResultsEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import SearchResultsObjIcon from "../../assets/images/search_results_obj.svg";
3 | import {
4 | metadataEditingConfigAttributes,
5 | metadataInitialContent,
6 | metadataPropertiesGroups,
7 | metadataValidations,
8 | } from "../_metadataEditingConfig";
9 | import { defaultPageValidations } from "../_defaultPageEditingConfig";
10 |
11 | Scrivito.provideEditingConfig("SearchResults", {
12 | title: "Search Results",
13 | thumbnail: SearchResultsObjIcon,
14 | hideInSelectionDialogs: true,
15 | attributes: {
16 | ...metadataEditingConfigAttributes,
17 | title: {
18 | title: "Title",
19 | description: "Limit to 55 characters.",
20 | },
21 | navigationBackgroundImage: {
22 | title: "Header image",
23 | description: "The background image of the header.",
24 | },
25 | },
26 | properties: ["title", "navigationBackgroundImage"],
27 | propertiesGroups: [...metadataPropertiesGroups],
28 | initialContent: {
29 | ...metadataInitialContent,
30 | },
31 | validations: [...defaultPageValidations, ...metadataValidations],
32 | });
33 |
--------------------------------------------------------------------------------
/src/Widgets/LinkContainerWidget/LinkContainerWidget.scss:
--------------------------------------------------------------------------------
1 | @import "src/assets/stylesheets/variables";
2 |
3 | .link-container-widget {
4 | list-style-type: none;
5 | padding: 0;
6 |
7 | &,
8 | & li,
9 | & li a,
10 | & li span {
11 | display: block;
12 | color: $theme-greydark;
13 | }
14 |
15 | .b-bottom {
16 | color: $theme-greydark;
17 | text-align: left;
18 | padding: 0 0 20px 0;
19 | text-transform: uppercase;
20 | font-size: 14px;
21 | font-weight: 700;
22 | }
23 |
24 | a,
25 | a:hover,
26 | a:focus {
27 | text-decoration: none;
28 | }
29 |
30 | &--headline {
31 | color: $theme-greydark;
32 | text-align: left;
33 | padding: 0 0 20px 0;
34 | text-transform: uppercase;
35 | font-size: 14px;
36 | font-weight: 700;
37 |
38 | &.b-bottom {
39 | &:after {
40 | left: 0;
41 | margin: 0;
42 | }
43 | }
44 | }
45 | }
46 |
47 | .bg-dark-image,
48 | .bg-brand-primary,
49 | .bg-brand-secondary,
50 | .bg-grey,
51 | .bg-greydark,
52 | .bg-greymiddle {
53 | .link-container-widget li {
54 | a,
55 | span {
56 | color: #fff;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Objs/SearchResults/SearchResultItem.scss:
--------------------------------------------------------------------------------
1 | @import "src/assets/stylesheets/variables";
2 |
3 | .search-result-item {
4 | margin: 20px 0;
5 | padding-bottom: 20px;
6 | overflow: hidden;
7 | border-bottom: 1px solid $theme-greylight;
8 |
9 | &--image {
10 | display: table-cell;
11 | vertical-align: top;
12 | width: 150px;
13 | text-align: center;
14 | padding: 0 20px 0 0;
15 |
16 | img {
17 | width: 150px;
18 | max-width: none;
19 | }
20 | }
21 |
22 | &--content {
23 | display: table-cell;
24 | vertical-align: top;
25 | padding: 0 20px 0 0;
26 | width: 10000px;
27 |
28 | .h3,
29 | p {
30 | margin-bottom: 5px;
31 | }
32 | }
33 |
34 | &--options {
35 | display: table-cell;
36 | vertical-align: middle;
37 | min-width: 100px;
38 | }
39 | }
40 |
41 | @media (max-width: $screen-xs-max) {
42 | .search-result-item {
43 | &--image,
44 | &--content,
45 | &--options {
46 | display: block;
47 | width: 100%;
48 | padding: 0;
49 | }
50 |
51 | &--image {
52 | &,
53 | img {
54 | width: 100%;
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/_breadcrumb.scss:
--------------------------------------------------------------------------------
1 | .breadcrumb {
2 | display: flex;
3 | flex-wrap: wrap;
4 | padding: $breadcrumb-padding-y $breadcrumb-padding-x;
5 | margin-bottom: $breadcrumb-margin-bottom;
6 | @include font-size($breadcrumb-font-size);
7 | list-style: none;
8 | background-color: $breadcrumb-bg;
9 | @include border-radius($breadcrumb-border-radius);
10 | }
11 |
12 | .breadcrumb-item {
13 | // The separator between breadcrumbs (by default, a forward-slash: "/")
14 | + .breadcrumb-item {
15 | padding-left: $breadcrumb-item-padding-x;
16 |
17 | &::before {
18 | float: left; // Suppress inline spacings and underlining of the separator
19 | padding-right: $breadcrumb-item-padding-x;
20 | color: $breadcrumb-divider-color;
21 | content: var(
22 | --#{$variable-prefix}breadcrumb-divider,
23 | escape-svg($breadcrumb-divider)
24 | )
25 | #{"/* rtl:"} var(
26 | --#{$variable-prefix}breadcrumb-divider,
27 | escape-svg($breadcrumb-divider-flipped)
28 | ) #{"*/"};
29 | }
30 | }
31 |
32 | &.active {
33 | color: $breadcrumb-active-color;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/_placeholders.scss:
--------------------------------------------------------------------------------
1 | .placeholder {
2 | display: inline-block;
3 | min-height: 1em;
4 | vertical-align: middle;
5 | cursor: wait;
6 | background-color: currentColor;
7 | opacity: $placeholder-opacity-max;
8 |
9 | &.btn::before {
10 | display: inline-block;
11 | content: "";
12 | }
13 | }
14 |
15 | // Sizing
16 | .placeholder-xs {
17 | min-height: 0.6em;
18 | }
19 |
20 | .placeholder-sm {
21 | min-height: 0.8em;
22 | }
23 |
24 | .placeholder-lg {
25 | min-height: 1.2em;
26 | }
27 |
28 | // Animation
29 | .placeholder-glow {
30 | .placeholder {
31 | animation: placeholder-glow 2s ease-in-out infinite;
32 | }
33 | }
34 |
35 | @keyframes placeholder-glow {
36 | 50% {
37 | opacity: $placeholder-opacity-min;
38 | }
39 | }
40 |
41 | .placeholder-wave {
42 | mask-image: linear-gradient(
43 | 130deg,
44 | $black 55%,
45 | rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%,
46 | $black 95%
47 | );
48 | mask-size: 200% 100%;
49 | animation: placeholder-wave 2s linear infinite;
50 | }
51 |
52 | @keyframes placeholder-wave {
53 | 100% {
54 | mask-position: -200% 0%;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/mixins/_visually-hidden.scss:
--------------------------------------------------------------------------------
1 | // stylelint-disable declaration-no-important
2 |
3 | // Hide content visually while keeping it accessible to assistive technologies
4 | //
5 | // See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/
6 | // See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/
7 |
8 | @mixin visually-hidden() {
9 | position: absolute !important;
10 | width: 1px !important;
11 | height: 1px !important;
12 | padding: 0 !important;
13 | margin: -1px !important; // Fix for https://github.com/twbs/bootstrap/issues/25686
14 | overflow: hidden !important;
15 | clip: rect(0, 0, 0, 0) !important;
16 | white-space: nowrap !important;
17 | border: 0 !important;
18 | }
19 |
20 | // Use to only display content when it's focused, or one of its child elements is focused
21 | // (i.e. when focus is within the element/container that the class was applied to)
22 | //
23 | // Useful for "Skip to main content" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
24 |
25 | @mixin visually-hidden-focusable() {
26 | &:not(:focus):not(:focus-within) {
27 | @include visually-hidden();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Widgets/ImageWidget/ImageWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { AnimateOnReveal } from "../../Components/AnimateOnReveal";
4 | import { alignmentClassName } from "../../utils/alignmentClassName";
5 |
6 | Scrivito.provideComponent("ImageWidget", ({ widget }) => {
7 | let image = (
8 |
13 | );
14 |
15 | const link = widget.get("link");
16 | if (link && !Scrivito.isInPlaceEditingActive()) {
17 | image = {image};
18 | }
19 |
20 | return (
21 |
22 | {image}
23 |
24 | );
25 | });
26 |
27 | function alternativeText(widget) {
28 | const widgetAlternativeText = widget.get("alternativeText");
29 | if (widgetAlternativeText) return widgetAlternativeText;
30 |
31 | const image = widget.get("image");
32 | if (image) return image.get("alternativeText");
33 |
34 | return "";
35 | }
36 |
--------------------------------------------------------------------------------
/src/assets/images/cookie_consent_icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/Components/SchemaDotOrg/dataFromEvent.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { formatDate } from "../../utils/formatDate";
3 | import { urlFromBinaryObj } from "../../utils/urlFromBinaryObj";
4 |
5 | export function dataFromEvent(event) {
6 | return {
7 | "@context": "http://schema.org",
8 | "@type": "Event",
9 | name: event.get("title"),
10 | url: Scrivito.urlFor(event),
11 | startDate: formatDate(event.get("date"), "yyyy-mm-dd"),
12 | location: locationFromEvent(event),
13 | image: urlFromBinaryObj(event.get("image")),
14 | description: event.get("metaDataDescription"),
15 | };
16 | }
17 |
18 | function locationFromEvent(event) {
19 | return {
20 | "@type": "Place",
21 | name: event.get("locationName"),
22 | address: addressFromEvent(event),
23 | };
24 | }
25 |
26 | function addressFromEvent(event) {
27 | return {
28 | "@type": "PostalAddress",
29 | streetAddress: event.get("locationStreetAddress"),
30 | addressLocality: event.get("locationLocality"),
31 | addressRegion: event.get("locationRegion"),
32 | postalCode: event.get("locationPostalCode"),
33 | addressCountry: event.get("locationCountry"),
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/src/Widgets/FormContainerWidget/utils/validations/customFieldNameValidation.js:
--------------------------------------------------------------------------------
1 | import { isCustomType } from "../isCustomType";
2 | import { isFieldNameUnique } from "../isFieldNameUnique";
3 |
4 | export const customFieldNameValidation = [
5 | "customFieldName",
6 |
7 | (customFieldName, { widget }) => {
8 | if (!isCustomType(widget)) {
9 | return;
10 | }
11 |
12 | if (!customFieldName.startsWith("custom_")) {
13 | return 'Custom field names must start with "custom_".';
14 | }
15 |
16 | if (customFieldName.length <= "custom_".length) {
17 | return "Specify the custom field's name.";
18 | }
19 |
20 | if (customFieldName.match(/^[A-Za-z_][A-Za-z0-9_]*$/) === null) {
21 | return 'Custom field names may consist of the following characters: "a-z", "A-Z", "0-9", "_".';
22 | }
23 |
24 | if (customFieldName.length > 50) {
25 | return `Custom field names may be up to 50 characters long. This name is ${customFieldName.length} characters long.`;
26 | }
27 |
28 | if (!isFieldNameUnique(widget)) {
29 | return "Specify a unique custom field name. There is at least one other element with the same custom field name.";
30 | }
31 | },
32 | ];
33 |
--------------------------------------------------------------------------------
/src/Objs/Author/AuthorEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import authorObjIcon from "../../assets/images/author_obj.svg";
3 | import {
4 | metadataEditingConfigAttributes,
5 | metadataInitialContent,
6 | metadataPropertiesGroups,
7 | metadataValidations,
8 | } from "../_metadataEditingConfig";
9 |
10 | Scrivito.provideEditingConfig("Author", {
11 | title: "Author",
12 | thumbnail: authorObjIcon,
13 | thumbnailForContent: (obj) => obj.get("image"),
14 | attributes: {
15 | ...metadataEditingConfigAttributes,
16 | title: {
17 | title: "Name",
18 | },
19 | description: {
20 | title: "Description",
21 | },
22 | image: {
23 | title: "Image",
24 | },
25 | },
26 | properties: ["title", "description", "image"],
27 | propertiesGroups: [...metadataPropertiesGroups],
28 | initialContent: {
29 | ...metadataInitialContent,
30 | title: "Lorem Ipsum",
31 | },
32 | validations: [
33 | ...metadataValidations,
34 | [
35 | "title",
36 |
37 | (title) => {
38 | if (!title) {
39 | return { message: "The name must be set.", severity: "error" };
40 | }
41 | },
42 | ],
43 | ],
44 | });
45 |
--------------------------------------------------------------------------------
/src/Widgets/FormButtonWidget/FormButtonWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import formButtonWidgetIcon from "../../assets/images/form_button_widget.svg";
3 | import { insideFormContainerValidation } from "../FormContainerWidget/utils/validations/insideFormContainerValidation";
4 |
5 | Scrivito.provideEditingConfig("FormButtonWidget", {
6 | title: "Form Button",
7 | thumbnail: formButtonWidgetIcon,
8 | attributes: {
9 | buttonText: {
10 | title: "Button Text",
11 | },
12 | alignment: {
13 | title: "Alignment",
14 | values: [
15 | { value: "left", title: "Left" },
16 | { value: "center", title: "Center" },
17 | { value: "right", title: "Right" },
18 | { value: "block", title: "Full width" },
19 | ],
20 | },
21 | },
22 | properties: ["buttonText", "alignment"],
23 | initialContent: {
24 | buttonText: "send message",
25 | alignment: "center",
26 | },
27 | validations: [
28 | insideFormContainerValidation,
29 | [
30 | "alignment",
31 | (alignment) => {
32 | if (!alignment) {
33 | return "Select the alignment.";
34 | }
35 | },
36 | ],
37 | ],
38 | });
39 |
--------------------------------------------------------------------------------
/src/Widgets/LinkContainerWidget/LinkContainerWidgetEditingConfig.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import linkListWidgetIcon from "../../assets/images/link_list_widget.svg";
3 | import { LinkWidget } from "../LinkWidget/LinkWidgetClass";
4 |
5 | Scrivito.provideEditingConfig("LinkContainerWidget", {
6 | title: "Link List",
7 | thumbnail: linkListWidgetIcon,
8 | attributes: {
9 | headline: {
10 | title: "Headline",
11 | description: "Leave empty to not show a headline.",
12 | },
13 | },
14 | properties: ["headline"],
15 | initialContent: {
16 | headline: "Links headline",
17 | links: ["Link 1", "Link 2", "Link 3"].map(
18 | (title) =>
19 | new LinkWidget({
20 | link: new Scrivito.Link({
21 | title,
22 | url: "https://scrivito.com",
23 | target: "_blank",
24 | }),
25 | })
26 | ),
27 | },
28 | validations: [
29 | [
30 | "links",
31 |
32 | (links) => {
33 | if (links.length < 1) {
34 | return {
35 | message: "The link list should contain at least one link.",
36 | severity: "warning",
37 | };
38 | }
39 | },
40 | ],
41 | ],
42 | });
43 |
--------------------------------------------------------------------------------
/src/Widgets/ButtonWidget/ButtonWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { InPlaceEditingPlaceholder } from "../../Components/InPlaceEditingPlaceholder";
4 | import { WrapIfClassName } from "../../Components/WrapIfClassName";
5 | import { alignmentClassName } from "../../utils/alignmentClassName";
6 |
7 | Scrivito.provideComponent("ButtonWidget", ({ widget }) => {
8 | const target = widget.get("target");
9 | let text = target && target.title();
10 | if (!text) {
11 | text = (
12 |
13 | Provide the button text in the widget properties.
14 |
15 | );
16 | }
17 |
18 | const classNames = ["btn"];
19 | classNames.push(widget.get("style") || "btn-primary");
20 |
21 | const alignment = widget.get("alignment");
22 | if (alignment === "block") classNames.push("btn-block");
23 |
24 | return (
25 |
26 |
27 | {text}
28 |
29 |
30 |
31 | );
32 | });
33 |
--------------------------------------------------------------------------------
/src/Widgets/ColumnContainerWidget/ColumnContainerWidgetComponent.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as Scrivito from "scrivito";
3 | import { InPlaceEditingPlaceholder } from "../../Components/InPlaceEditingPlaceholder";
4 |
5 | Scrivito.provideComponent("ColumnContainerWidget", ({ widget }) => {
6 | const columns = widget.get("columns");
7 |
8 | if (!columns.length) {
9 | return (
10 |
11 | Define columns in the widget properties.
12 |
13 | );
14 | }
15 |
16 | const content = columns.map((columnWidget, index) => {
17 | const colSize = columnWidget.get("colSize") || 1;
18 | return (
19 |
20 |
25 |
26 | );
27 | });
28 |
29 | const classNames = ["row"];
30 |
31 | if (widget.get("alignment")) {
32 | classNames.push(`align-items-${widget.get("alignment")}`);
33 | } else {
34 | classNames.push("align-items-start");
35 | }
36 |
37 | return {content}
;
38 | });
39 |
--------------------------------------------------------------------------------
/src/prerenderContent/generateHtml.js:
--------------------------------------------------------------------------------
1 | export async function generateHtml({
2 | objId,
3 | htmlAttributes,
4 | headContent,
5 | bodyAttributes,
6 | bodyContent,
7 | preloadDumpFileName,
8 | assetManifest,
9 | }) {
10 | return `
11 |
12 |
13 |
14 |
15 |
19 | ${headContent}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | ${bodyContent}
29 |
30 |
31 |
32 |
33 |
34 | `;
35 | }
36 |
--------------------------------------------------------------------------------
/src/assets/images/tick_list_item_widget.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
27 |
--------------------------------------------------------------------------------
/src/Components/ScrivitoExtensions/IconEditorTab/IconSearchResults.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import Fuse from "fuse.js";
3 | import { fontAwesomeIcons } from "./fontAwesomeIcons";
4 | import { SingleIcon } from "./SingleIcon";
5 |
6 | export function IconSearchResults({ searchValue, setWidgetIcon, currentIcon }) {
7 | const fuse = React.useMemo(() => {
8 | const fuseOptions = {
9 | threshold: 0.2,
10 | keys: ["name", "id", "filter", "aliases"],
11 | };
12 |
13 | return new Fuse(fontAwesomeIcons, fuseOptions);
14 | }, []);
15 |
16 | if (!searchValue.length) return null;
17 |
18 | const results = fuse.search(searchValue);
19 |
20 | return (
21 |
22 |
23 | {`Search for '${searchValue}'`}
24 |
25 |
26 | {results.map((result, index) => {
27 | const icon = result.item;
28 |
29 | return (
30 |
36 | );
37 | })}
38 |
39 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/src/Widgets/DividerWidget/DividerWidget.scss:
--------------------------------------------------------------------------------
1 | @import "src/assets/stylesheets/variables";
2 |
3 | .divider-widget {
4 | clear: both;
5 | position: relative;
6 | padding: 60px 0;
7 | text-align: center;
8 | height: 0;
9 |
10 | &:after {
11 | background: #666;
12 | content: "";
13 | position: absolute;
14 | top: 50%;
15 | left: 0;
16 | right: 0;
17 | display: block;
18 | height: 1px;
19 | }
20 |
21 | img {
22 | display: inline-block;
23 | padding: 0 15px;
24 | height: 40px;
25 | position: relative;
26 | transform: translate(0, -50%);
27 | z-index: 1;
28 | }
29 | }
30 |
31 | .bg-grey .divider-widget img {
32 | background-color: $theme-grey;
33 | }
34 | .bg-greylight .divider-widget img {
35 | background-color: $theme-greylight;
36 | }
37 | .bg-greydark .divider-widget img {
38 | background-color: $theme-greydark;
39 | }
40 | .bg-greymiddle .divider-widget img {
41 | background-color: $theme-greymiddle;
42 | }
43 | .bg-greywhite .divider-widget img {
44 | background-color: $theme-greywhite;
45 | }
46 | .bg-white .divider-widget img {
47 | background-color: #fff;
48 | }
49 |
50 | .bg-brand-primary .divider-widget img {
51 | background-color: $primary;
52 | }
53 | .bg-brand-secondary .divider-widget img {
54 | background-color: $secondary;
55 | }
56 |
--------------------------------------------------------------------------------
/src/Components/SchemaDotOrg/dataFromJob.js:
--------------------------------------------------------------------------------
1 | import * as Scrivito from "scrivito";
2 | import { formatDate } from "../../utils/formatDate";
3 |
4 | export function dataFromJob(job) {
5 | return {
6 | "@context": "http://schema.org",
7 | "@type": "JobPosting",
8 | title: job.get("title"),
9 | datePosted: formatDate(job.get("datePosted"), "yyyy-mm-dd"),
10 | validThrough: formatDate(job.get("validThrough"), "yyyy-mm-dd"),
11 | description: Scrivito.extractText(job),
12 | employmentType: job.get("employmentType"),
13 | hiringOrganization: {
14 | "@type": "Organization",
15 | name: job.get("hiringOrganizationName"),
16 | sameAs: job.get("hiringOrganizationWebsite"),
17 | },
18 | jobLocation: locationFromJob(job),
19 | };
20 | }
21 |
22 | function locationFromJob(job) {
23 | return {
24 | "@type": "Place",
25 | name: job.get("locationName"),
26 | address: addressFromJob(job),
27 | };
28 | }
29 |
30 | function addressFromJob(job) {
31 | return {
32 | "@type": "PostalAddress",
33 | streetAddress: job.get("locationStreetAddress"),
34 | addressLocality: job.get("locationLocality"),
35 | addressRegion: job.get("locationRegion"),
36 | postalCode: job.get("locationPostalCode"),
37 | addressCountry: job.get("locationCountry"),
38 | };
39 | }
40 |
--------------------------------------------------------------------------------
/src/assets/stylesheets/bootstrap5/forms/_labels.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Labels
3 | //
4 |
5 | .form-label {
6 | margin-bottom: $form-label-margin-bottom;
7 | @include font-size($form-label-font-size);
8 | font-style: $form-label-font-style;
9 | font-weight: $form-label-font-weight;
10 | color: $form-label-color;
11 | }
12 |
13 | // For use with horizontal and inline forms, when you need the label (or legend)
14 | // text to align with the form controls.
15 | .col-form-label {
16 | padding-top: add($input-padding-y, $input-border-width);
17 | padding-bottom: add($input-padding-y, $input-border-width);
18 | margin-bottom: 0; // Override the `