├── .babelrc
├── .commitlintrc.js
├── .cz-config.js
├── .eslintignore
├── .github
└── workflows
│ ├── release.yaml
│ └── test.yaml
├── .gitignore
├── .prettierignore
├── .releaserc.json
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── example
├── .env.example
├── .gitignore
├── .graphqlrc.yaml
├── README.md
├── custom.d.ts
├── jest.config.js
├── jest.setup.js
├── next-env.d.ts
├── next.config.js
├── package.json
├── public
│ ├── favicon.ico
│ └── static
│ │ └── fonts
│ │ ├── DomaineDisp-Bold.woff
│ │ ├── DomaineDisp-Bold.woff2
│ │ ├── Inter-Bold.woff
│ │ ├── Inter-Bold.woff2
│ │ ├── Inter-BoldItalic.woff
│ │ ├── Inter-BoldItalic.woff2
│ │ ├── Inter-Italic.woff
│ │ ├── Inter-Italic.woff2
│ │ ├── Inter-Medium.woff
│ │ ├── Inter-Medium.woff2
│ │ ├── Inter-MediumItalic.woff
│ │ ├── Inter-MediumItalic.woff2
│ │ ├── Inter-Regular.woff
│ │ ├── Inter-Regular.woff2
│ │ └── stylesheet.css
├── src
│ ├── config
│ │ ├── index.ts
│ │ └── seo.ts
│ ├── globals.d.ts
│ ├── graphql
│ │ ├── queries
│ │ │ ├── articleItem.graphql
│ │ │ ├── articleItems.graphql
│ │ │ └── galleryItem.graphql
│ │ └── sdk.ts
│ ├── lib
│ │ ├── graphqlClient.ts
│ │ ├── index.ts
│ │ └── test-utils.ts
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ ├── _error.tsx
│ │ ├── api
│ │ │ └── preview
│ │ │ │ └── [[...handle]].ts
│ │ ├── article
│ │ │ └── [slug].tsx
│ │ ├── gallery.tsx
│ │ ├── index.tsx
│ │ └── unmounttest.tsx
│ └── styles
│ │ ├── styled.d.ts
│ │ └── theme.ts
├── tsconfig.json
└── yarn.lock
├── index.ts
├── jest.config.js
├── jest.setup.js
├── package.json
├── rollup.config.js
├── src
├── bridge
│ ├── __tests__
│ │ ├── context.test.tsx
│ │ ├── useStory.test.tsx
│ │ └── withStory.test.tsx
│ ├── context.tsx
│ ├── index.ts
│ ├── init.ts
│ ├── useStory.ts
│ └── withStory.tsx
├── client
│ ├── __tests__
│ │ ├── getClient.test.ts
│ │ └── getStaticPropsWithSdk.test.ts
│ ├── getClient.ts
│ ├── getStaticPropsWithSdk.ts
│ └── index.ts
├── image
│ ├── Image.tsx
│ ├── Picture.tsx
│ ├── Placeholder.tsx
│ ├── Wrapper.tsx
│ ├── __tests__
│ │ ├── Image.test.tsx
│ │ ├── Picture.test.tsx
│ │ ├── createIntersectionObserver.test.tsx
│ │ ├── getImageProps.test.ts
│ │ └── helpers.test.tsx
│ ├── createIntersectionObserver.ts
│ ├── getImageProps.ts
│ ├── helpers.ts
│ └── index.ts
├── index.ts
├── next
│ ├── __tests__
│ │ └── previewHandlers.test.ts
│ └── previewHandlers.ts
├── story.ts
└── utils
│ ├── __tests__
│ ├── getExcerpt.test.ts
│ └── getPlainText.test.ts
│ ├── getExcerpt.ts
│ ├── getPlainText.ts
│ └── index.ts
├── tsconfig.build.json
├── tsconfig.json
├── website
├── .gitignore
├── README.md
├── babel.config.js
├── docs
│ ├── api
│ │ ├── Image.md
│ │ ├── StoryProvider.md
│ │ ├── getClient.md
│ │ ├── getExcerpt.md
│ │ ├── getImageProps.md
│ │ ├── getPlainText.md
│ │ ├── getStaticPropsWithSdk.md
│ │ ├── nextPreviewHandlers.md
│ │ ├── useStory.md
│ │ └── withStory.md
│ └── getting-started.md
├── docusaurus.config.js
├── package.json
├── sidebars.js
├── src
│ ├── css
│ │ └── custom.css
│ └── pages
│ │ ├── index.jsx
│ │ └── styles.module.css
├── static
│ ├── .nojekyll
│ └── img
│ │ ├── favicon.ico
│ │ ├── logo-dark.png
│ │ ├── logo.png
│ │ └── preview-mode.png
└── yarn.lock
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env",
4 | "@babel/preset-typescript",
5 | "@babel/react"
6 | ],
7 | "plugins": [
8 | "@babel/plugin-proposal-class-properties",
9 | "@babel/plugin-transform-runtime"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.commitlintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = { extends: ["@commitlint/config-conventional"] };
2 |
--------------------------------------------------------------------------------
/.cz-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // add additional standard scopes here
3 | scopes: [{ name: "accounts" }, { name: "admin" }],
4 | // use this to permanently skip any questions by listing the message key as a string
5 | skipQuestions: [],
6 |
7 | /* DEFAULT CONFIG */
8 | messages: {
9 | type: "What type of changes are you committing:",
10 | scope: "\nEnlighten us with the scope (optional):",
11 | customScope: "Add the scope of your liking:",
12 | subject: "Write a short and simple description of the change:\n",
13 | body:
14 | 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
15 | breaking: "List any BREAKING CHANGES (optional):\n",
16 | footer:
17 | "List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n",
18 | confirmCommit: "Are you sure you the above looks right?",
19 | },
20 | types: [
21 | {
22 | value: "fix",
23 | name: "🐛 fix: Changes that fix a bug",
24 | emoji: "🐛",
25 | },
26 | {
27 | value: "feat",
28 | name: " 🚀 feat: Changes that introduce a new feature",
29 | emoji: "🚀",
30 | },
31 | {
32 | value: "refactor",
33 | name:
34 | "🔍 refactor: Changes that neither fixes a bug nor adds a feature",
35 | emoji: "🔍",
36 | },
37 | {
38 | value: "test",
39 | name: "💡 test: Adding missing tests",
40 | emoji: "💡",
41 | },
42 | {
43 | value: "style",
44 | name:
45 | "💅 style: Changes that do not impact the code base \n (white-space, formatting, missing semi-colons, etc)",
46 | emoji: "💅",
47 | },
48 | {
49 | value: "docs",
50 | name: "📝 docs: Changes to the docs",
51 | emoji: "📝",
52 | },
53 | {
54 | value: "chore",
55 | name:
56 | "🤖 chore: Changes to the build process or auxiliary tools\n and or libraries such as auto doc generation",
57 | emoji: "🤖",
58 | },
59 | ],
60 | allowTicketNumber: false,
61 | isTicketNumberRequired: false,
62 | ticketNumberPrefix: "#",
63 | ticketNumberRegExp: "\\d{1,5}",
64 | allowCustomScopes: true,
65 | allowBreakingChanges: ["feat", "fix", "chore"],
66 | breakingPrefix: "🚧 BREAKING CHANGES 🚧",
67 | footerPrefix: "CLOSES ISSUE:",
68 | subjectLimit: 100,
69 | };
70 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | node_modules
3 | public/*
4 | dist/
5 | .next
6 | .next/*
7 |
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Release
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | release:
8 | name: Release
9 | runs-on: ubuntu-18.04
10 | steps:
11 | - name: Checkout
12 | uses: actions/checkout@v2
13 | with:
14 | fetch-depth: 0
15 | - name: Setup Node.js
16 | uses: actions/setup-node@v2
17 | with:
18 | node-version: 12
19 | - name: Install dependencies
20 | run: yarn
21 | - name: Release
22 | env:
23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
25 | run: yarn semantic-release
26 |
--------------------------------------------------------------------------------
/.github/workflows/test.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | pull_request:
9 |
10 | jobs:
11 | run-tests:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - name: Checkout repo
16 | uses: actions/checkout@v2
17 |
18 | - name: Setup Node.js
19 | uses: actions/setup-node@v2
20 | with:
21 | node-version: 12
22 |
23 | - name: Get yarn cache directory path
24 | id: yarn-cache-dir-path
25 | run: echo "::set-output name=dir::$(yarn cache dir)"
26 |
27 | - name: Cache yarn dependencies
28 | uses: actions/cache@v2
29 | id: yarn-cache
30 | with:
31 | path: |
32 | ${{ steps.yarn-cache-dir-path.outputs.dir }}
33 | node_modules
34 | */*/node_modules
35 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
36 | restore-keys: |
37 | ${{ runner.os }}-yarn-
38 | - name: Install modules
39 | run: yarn
40 |
41 | - name: Run tests
42 | run: yarn test --silent --coverage
43 |
44 | - name: Upload coverage to Codecov
45 | uses: codecov/codecov-action@v1
46 | with:
47 | # project specific codecov token
48 | token: ${{ secrets.CODECOV_TOKEN }}
49 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 | .pnp
6 | .pnp.js
7 |
8 | # testing
9 | coverage
10 |
11 | # production
12 | dist
13 |
14 | # misc
15 | .DS_Store
16 | .env*
17 |
18 | # debug
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 | storybook-static
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | public/*
3 | .next
4 | .next/*
5 | dist
6 | coverage
7 |
--------------------------------------------------------------------------------
/.releaserc.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | [
4 | "@semantic-release/commit-analyzer",
5 | {
6 | "preset": "angular",
7 | "releaseRules": [
8 | {
9 | "release": "patch",
10 | "type": "chore"
11 | },
12 | {
13 | "release": "patch",
14 | "type": "refactor"
15 | },
16 | {
17 | "release": "patch",
18 | "type": "style"
19 | }
20 | ]
21 | }
22 | ],
23 | "@semantic-release/release-notes-generator",
24 | [
25 | "@semantic-release/changelog",
26 | {
27 | "changelogFile": "CHANGELOG.md"
28 | }
29 | ],
30 | "@semantic-release/npm",
31 | [
32 | "@semantic-release/github",
33 | {
34 | "assets": ["CHANGELOG.md"]
35 | }
36 | ]
37 | ]
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // These are all my auto-save configs
3 | "editor.formatOnSave": true,
4 | // turn it off for JS and JSX, we will do this via eslint
5 | "[javascript]": {
6 | "editor.formatOnSave": false
7 | },
8 | "[javascriptreact]": {
9 | "editor.formatOnSave": false
10 | },
11 | "[typescript]": {
12 | "editor.formatOnSave": false
13 | },
14 | "[typescriptreact]": {
15 | "editor.formatOnSave": false
16 | },
17 | // tell the ESLint plugin to run on save
18 | "editor.codeActionsOnSave": {
19 | "source.fixAll": true
20 | },
21 | // Optional BUT IMPORTANT: If you have the prettier extension enabled for other languages like CSS and HTML, turn it off for JS since we are doing it through Eslint already
22 | "prettier.disableLanguages": ["javascript", "javascriptreact", "typescript", "typescriptreact"]
23 | }
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Story of AMS
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
@storyofams/storyblok-toolkit
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Batteries-included toolset for efficient development of React frontends with Storyblok as a headless CMS.
View docs
21 |
22 |
23 | ---
24 |
25 | ## Purpose
26 |
27 | The aim of this library is to make integrating Storyblok in a React frontend easy.
28 |
29 | We provide wrappers to abstract away the setup process (implementing the Storyblok JS Bridge, making the app work with the Visual Editor). We also provide an easy way to configure a GraphQL client, an optimized image component and some utility functions.
30 |
31 | ## Installation
32 |
33 | ```sh
34 | yarn add @storyofams/storyblok-toolkit
35 | # or
36 | npm install @storyofams/storyblok-toolkit
37 | ```
38 |
39 | ## Features
40 |
41 | The following API's are included:
42 |
43 | - `withStory()` and `StoryProvider`: `withStory` wraps a component/page where a story is loaded, and makes sure to keep it in sync with the Visual Editor. `StoryProvider` is a global provider that provides the context to make `withStory` work.
44 | - `useStory()`: alternative to `withStory`, gets the synced story.
45 | - `getClient()`: properly configures a `graphql-request` client to interact with Storyblok's GraphQL API.
46 | - `Image`: automatically optimized and responsive images using Storyblok's image service. With LQIP (Low-Quality Image Placeholders) support.
47 | - `getImageProps()`: get optimized image sizes without using `Image`.
48 | - `getExcerpt()`: get an excerpt text from a richtext field.
49 | - `getPlainText()`: get plaintext from a richtext field.
50 |
51 | Next.js specific:
52 | - `getStaticPropsWithSdk()`: provides a properly configured `graphql-request` client, typed using `graphql-code-generator` to interact with Storyblok's GraphQL API, as a prop inside of `getStaticProps`.
53 | - `nextPreviewHandlers()`: API handlers to implement Next.js's preview mode.
54 |
--------------------------------------------------------------------------------
/example/.env.example:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_STORYBLOK_TOKEN=
2 | STORYBLOK_PREVIEW_TOKEN=
3 | PREVIEW_TOKEN=
4 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | .env*
21 | !.env.example
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
--------------------------------------------------------------------------------
/example/.graphqlrc.yaml:
--------------------------------------------------------------------------------
1 | projects:
2 | default:
3 | schema:
4 | - https://gapi.storyblok.com/v1/api:
5 | headers:
6 | Token: ${NEXT_PUBLIC_STORYBLOK_TOKEN}
7 | Version: "draft"
8 | documents: "src/**/*.graphql"
9 | extensions:
10 | codegen:
11 | hooks:
12 | afterAllFileWrite:
13 | - eslint --fix
14 | generates:
15 | src/graphql/sdk.ts:
16 | plugins:
17 | - typescript
18 | - typescript-operations
19 | - typescript-graphql-request
20 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
@storyofams/storyblok-toolkit example
6 |
7 |
8 | ## Setup
9 |
10 | Rename `.env.example` to `.env.local`
11 |
--------------------------------------------------------------------------------
/example/custom.d.ts:
--------------------------------------------------------------------------------
1 | import { SxStyleProp } from 'rebass';
2 | import * as StyledComponents from 'styled-components';
3 | import * as StyledSystem from 'styled-system';
4 |
5 | declare module 'rebass' {
6 | type ThemedSxStyleProps =
7 | | SxStyleProp
8 | | StyledSystem.SpaceProps
9 | | StyledSystem.TypographyProps
10 | | StyledSystem.FlexboxProps
11 | | StyledSystem.GridProps
12 | | StyledSystem.LayoutProps
13 | | StyledSystem.ColorProps;
14 |
15 | export interface SxProps {
16 | maatje?: boolean;
17 | sx?: ThemedSxStyleProps;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/example/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: 'jsdom',
3 | roots: ['/src'],
4 | transform: {
5 | '^.+\\.tsx?$': 'babel-jest',
6 | },
7 | moduleNameMapper: {
8 | '^~/(.*)$': '/src/$1',
9 | },
10 | moduleDirectories: [
11 | 'node_modules',
12 | 'src/lib', // a utility folder
13 | __dirname, // the root directory
14 | ],
15 | setupFilesAfterEnv: [
16 | '@testing-library/jest-dom/extend-expect',
17 | './jest.setup.js',
18 | ],
19 | };
20 |
--------------------------------------------------------------------------------
/example/jest.setup.js:
--------------------------------------------------------------------------------
1 | jest.mock('./src/components/common/Icon/req');
2 |
--------------------------------------------------------------------------------
/example/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 |
5 | // NOTE: This file should not be edited
6 | // see https://nextjs.org/docs/basic-features/typescript for more information.
7 |
--------------------------------------------------------------------------------
/example/next.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin');
3 |
4 | const hasNextBabelLoader = (r) => {
5 | if (Array.isArray(r.use)) {
6 | return r.use.find((l) => l && l.loader === 'next-babel-loader');
7 | }
8 |
9 | return r.use && r.use.loader === 'next-babel-loader';
10 | };
11 |
12 | module.exports = {
13 | env: {
14 | PASSWORD_PROTECT: process.env.ENVIRONMENT === 'staging',
15 | },
16 | webpack(config, options) {
17 | config.module.rules.forEach((rule) => {
18 | if (/(ts|tsx)/.test(String(rule.test)) && hasNextBabelLoader(rule)) {
19 | rule.include = [...rule.include, path.join(__dirname, '..', 'src')];
20 |
21 | return rule;
22 | }
23 | });
24 |
25 | config.module.rules.push({
26 | test: /\.svg$/,
27 | use: [{ loader: '@svgr/webpack', options: { icon: true, svgo: false } }],
28 | });
29 |
30 | config.resolve.plugins = [
31 | new TsconfigPathsPlugin({ extensions: config.resolve.extensions }),
32 | ];
33 |
34 | config.resolve.alias = {
35 | ...config.resolve.alias,
36 | next: path.resolve('./node_modules/next'),
37 | react: path.resolve('./node_modules/react'),
38 | 'react-dom': path.resolve('./node_modules/react-dom'),
39 | };
40 |
41 | return config;
42 | },
43 | };
44 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "storyblok-toolkit-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "commit": "./node_modules/cz-customizable/standalone.js",
10 | "test": "jest --coverage",
11 | "test:watch": "jest --watch",
12 | "lint": "eslint --ext .ts --ext .tsx ./src",
13 | "prettier": "prettier \"**/*.+(js|jsx|json|yml|yaml|css|ts|tsx|md|mdx)\"",
14 | "codegen": "DOTENV_CONFIG_PATH=.env.development graphql-codegen -r dotenv/config"
15 | },
16 | "dependencies": {
17 | "@reach/alert": "^0.7.4",
18 | "@storyofams/react-helpers": "0.3.6",
19 | "@storyofams/storyblok-toolkit": "link:..",
20 | "@styled-system/css": "^5.1.4",
21 | "@styled-system/props": "^5.1.4",
22 | "@svgr/webpack": "^5.0.1",
23 | "axios": "^0.21.1",
24 | "fontfaceobserver": "^2.1.0",
25 | "graphql": "^15.5.0",
26 | "graphql-request": "^3.4.0",
27 | "graphql-tag": "^2.11.0",
28 | "next": "12.0.0",
29 | "next-seo": "^3.3.0",
30 | "object-fit-images": "^3.2.4",
31 | "react": "^17.0.1",
32 | "react-dom": "^17.0.1",
33 | "react-hook-form": "6.14.1",
34 | "react-select": "^3.0.8",
35 | "rebass": "^4.0.7",
36 | "storyblok-react": "^0.1.2",
37 | "storyblok-rich-text-react-renderer": "^2.1.1",
38 | "styled-components": "^5.1.1",
39 | "styled-system": "^5.1.5",
40 | "yup": "^0.28.0"
41 | },
42 | "devDependencies": {
43 | "@babel/core": "^7.7.7",
44 | "@babel/runtime-corejs2": "^7.9.2",
45 | "@commitlint/cli": "^8.3.4",
46 | "@commitlint/config-conventional": "^8.3.4",
47 | "@graphql-codegen/cli": "^1.21.3",
48 | "@graphql-codegen/typescript": "^1.21.1",
49 | "@graphql-codegen/typescript-graphql-request": "^3.1.0",
50 | "@graphql-codegen/typescript-operations": "^1.17.15",
51 | "@storybook/addon-actions": "^5.2.8",
52 | "@storybook/addon-links": "^5.2.8",
53 | "@storybook/addons": "^5.2.8",
54 | "@storybook/preset-typescript": "^1.2.0",
55 | "@storybook/react": "^5.2.8",
56 | "@testing-library/jest-dom": "^5.0.2",
57 | "@testing-library/react": "^9.4.0",
58 | "@types/jest": "^24.9.1",
59 | "@types/node": "^13.1.6",
60 | "@types/react": "^16.9.17",
61 | "@types/react-dom": "^16.9.4",
62 | "@types/react-select": "^3.0.10",
63 | "@types/rebass": "4.0.7",
64 | "@types/styled-components": "^5.1.1",
65 | "@types/styled-system": "^5.1.9",
66 | "@types/yup": "^0.26.27",
67 | "@typescript-eslint/eslint-plugin": "^2.15.0",
68 | "@typescript-eslint/parser": "^2.15.0",
69 | "awesome-typescript-loader": "^5.2.1",
70 | "babel-eslint": "^10.1.0",
71 | "babel-loader": "^8.0.6",
72 | "babel-plugin-styled-components": "^1.10.6",
73 | "babel-preset-react-app": "^9.1.0",
74 | "cz-customizable": "git+https://github.com/storyofams/cz-customizable.git",
75 | "eslint": "^7.6.0",
76 | "eslint-config-ams": "git+https://github.com/storyofams/eslint-config-ams.git",
77 | "eslint-config-prettier": "^6.11.0",
78 | "eslint-import-resolver-alias": "^1.1.2",
79 | "eslint-plugin-import": "^2.22.0",
80 | "eslint-plugin-jsx-a11y": "^6.3.1",
81 | "eslint-plugin-prettier": "^3.1.4",
82 | "eslint-plugin-react": "^7.20.5",
83 | "eslint-plugin-react-hooks": "^4.0.8",
84 | "fork-ts-checker-webpack-plugin": "^3.1.1",
85 | "husky": "^4.0.6",
86 | "jest": "^24.3.0",
87 | "lint-staged": "^9.5.0",
88 | "prettier": "^2.0.5",
89 | "react-docgen-typescript-loader": "^3.6.0",
90 | "react-select-event": "^4.1.2",
91 | "ts-jest": "^25.0.0",
92 | "ts-loader": "^6.2.1",
93 | "typescript": "^3.7.4"
94 | },
95 | "eslintConfig": {
96 | "extends": [
97 | "ams/web"
98 | ]
99 | },
100 | "config": {
101 | "commitizen": {
102 | "path": "node_modules/cz-customizable"
103 | }
104 | },
105 | "husky": {
106 | "hooks": {
107 | "pre-commit": "lint-staged",
108 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
109 | }
110 | },
111 | "lint-staged": {
112 | "**/*.+(js|jsx|ts|tsx)": [
113 | "yarn lint --fix",
114 | "git add"
115 | ]
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/favicon.ico
--------------------------------------------------------------------------------
/example/public/static/fonts/DomaineDisp-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/DomaineDisp-Bold.woff
--------------------------------------------------------------------------------
/example/public/static/fonts/DomaineDisp-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/DomaineDisp-Bold.woff2
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-Bold.woff
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-Bold.woff2
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-BoldItalic.woff
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-BoldItalic.woff2
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-Italic.woff
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-Italic.woff2
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-Medium.woff
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-Medium.woff2
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-MediumItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-MediumItalic.woff
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-MediumItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-MediumItalic.woff2
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-Regular.woff
--------------------------------------------------------------------------------
/example/public/static/fonts/Inter-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storyofams/storyblok-toolkit/cd1c2e9ab5309357c2805dca57b46d7b31f31def/example/public/static/fonts/Inter-Regular.woff2
--------------------------------------------------------------------------------
/example/public/static/fonts/stylesheet.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Domaine Disp';
3 | src: url('DomaineDisp-Bold.woff2') format('woff2'),
4 | url('DomaineDisp-Bold.woff') format('woff');
5 | font-weight: bold;
6 | font-style: normal;
7 | }
8 |
9 | @font-face {
10 | font-family: 'Inter';
11 | src: url('Inter-Bold.woff2') format('woff2'),
12 | url('Inter-Bold.woff') format('woff');
13 | font-weight: bold;
14 | font-style: normal;
15 | }
16 |
17 | @font-face {
18 | font-family: 'Inter';
19 | src: url('Inter-BoldItalic.woff2') format('woff2'),
20 | url('Inter-BoldItalic.woff') format('woff');
21 | font-weight: bold;
22 | font-style: italic;
23 | }
24 |
25 | @font-face {
26 | font-family: 'Inter';
27 | src: url('Inter-Regular.woff2') format('woff2'),
28 | url('Inter-Regular.woff') format('woff');
29 | font-weight: normal;
30 | font-style: normal;
31 | }
32 |
33 | @font-face {
34 | font-family: 'Inter';
35 | src: url('Inter-Italic.woff2') format('woff2'),
36 | url('Inter-Italic.woff') format('woff');
37 | font-weight: normal;
38 | font-style: italic;
39 | }
40 |
41 | @font-face {
42 | font-family: 'Inter';
43 | src: url('Inter-Medium.woff2') format('woff2'),
44 | url('Inter-Medium.woff') format('woff');
45 | font-weight: 500;
46 | font-style: normal;
47 | }
48 |
49 | @font-face {
50 | font-family: 'Inter';
51 | src: url('Inter-MediumItalic.woff2') format('woff2'),
52 | url('Inter-MediumItalic.woff') format('woff');
53 | font-weight: 500;
54 | font-style: italic;
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/example/src/config/index.ts:
--------------------------------------------------------------------------------
1 | export { default as seo } from './seo';
2 |
--------------------------------------------------------------------------------
/example/src/config/seo.ts:
--------------------------------------------------------------------------------
1 | const siteTitle = 'Boilerplate';
2 |
3 | const defaultSeo = {
4 | openGraph: {
5 | type: 'website',
6 | locale: 'en_IE',
7 | url: 'https://www.Boilerplate.com/',
8 | site_name: siteTitle,
9 | },
10 | twitter: {
11 | handle: '@Boilerplate',
12 | cardType: 'summary_large_image',
13 | },
14 | titleTemplate: `%s | ${siteTitle}`,
15 | };
16 |
17 | if (process.env.NODE_ENV === 'development') {
18 | defaultSeo.titleTemplate = `%s | dev-${siteTitle}`;
19 | }
20 |
21 | export default defaultSeo;
22 |
--------------------------------------------------------------------------------
/example/src/globals.d.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom/extend-expect';
2 |
--------------------------------------------------------------------------------
/example/src/graphql/queries/articleItem.graphql:
--------------------------------------------------------------------------------
1 | query articleItem($slug: ID!) {
2 | ArticleItem(id: $slug) {
3 | content {
4 | title
5 | teaser_image {
6 | filename
7 | focus
8 | }
9 | intro
10 | _editable
11 | }
12 | uuid
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/example/src/graphql/queries/articleItems.graphql:
--------------------------------------------------------------------------------
1 | query articleItems($perPage: Int) {
2 | ArticleItems(per_page: $perPage) {
3 | items {
4 | content {
5 | title
6 | teaser_image {
7 | filename
8 | alt
9 | }
10 | intro
11 | }
12 | uuid
13 | full_slug
14 | slug
15 | }
16 | total
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/example/src/graphql/queries/galleryItem.graphql:
--------------------------------------------------------------------------------
1 | query galleryItem($slug: ID!) {
2 | GalleryItem(id: $slug) {
3 | content {
4 | images {
5 | filename
6 | alt
7 | focus
8 | }
9 | _editable
10 | }
11 | uuid
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/src/graphql/sdk.ts:
--------------------------------------------------------------------------------
1 | import { GraphQLClient } from 'graphql-request';
2 | import * as Dom from 'graphql-request/dist/types.dom';
3 | import gql from 'graphql-tag';
4 | export type Maybe = T | null;
5 | export type Exact = {
6 | [K in keyof T]: T[K];
7 | };
8 | export type MakeOptional = Omit &
9 | { [SubKey in K]?: Maybe };
10 | export type MakeMaybe = Omit &
11 | { [SubKey in K]: Maybe };
12 | /** All built-in and custom scalars, mapped to their actual values */
13 | export type Scalars = {
14 | ID: string;
15 | String: string;
16 | Boolean: boolean;
17 | Int: number;
18 | Float: number;
19 | BlockScalar: any;
20 | /** An ISO 8601-encoded datetime */
21 | ISO8601DateTime: any;
22 | JsonScalar: any;
23 | };
24 |
25 | export type Alternate = {
26 | __typename?: 'Alternate';
27 | fullSlug: Scalars['String'];
28 | id: Scalars['Int'];
29 | isFolder?: Maybe;
30 | name: Scalars['String'];
31 | parentId?: Maybe;
32 | published: Scalars['Boolean'];
33 | slug: Scalars['String'];
34 | };
35 |
36 | export type ArticleComponent = {
37 | __typename?: 'ArticleComponent';
38 | _editable?: Maybe;
39 | _uid?: Maybe;
40 | author?: Maybe;
41 | categories?: Maybe>>;
42 | component?: Maybe;
43 | intro?: Maybe;
44 | long_text?: Maybe;
45 | seo?: Maybe;
46 | teaser_image?: Maybe;
47 | title?: Maybe;
48 | };
49 |
50 | export type ArticleComponentCategoriesArgs = {
51 | fields?: Maybe>>;
52 | language?: Maybe;
53 | };
54 |
55 | export type ArticleFilterQuery = {
56 | title?: Maybe;
57 | categories?: Maybe;
58 | };
59 |
60 | export type ArticleItem = {
61 | __typename?: 'ArticleItem';
62 | alternates?: Maybe>>;
63 | content?: Maybe;
64 | created_at?: Maybe;
65 | default_full_slug?: Maybe;
66 | first_published_at?: Maybe;
67 | full_slug?: Maybe;
68 | group_id?: Maybe;
69 | id?: Maybe;
70 | is_startpage?: Maybe;
71 | lang?: Maybe;
72 | meta_data?: Maybe;
73 | name?: Maybe;
74 | parent_id?: Maybe;
75 | path?: Maybe;
76 | position?: Maybe;
77 | published_at?: Maybe;
78 | release_id?: Maybe;
79 | slug?: Maybe;
80 | sort_by_date?: Maybe;
81 | tag_list?: Maybe>>;
82 | translated_slugs?: Maybe>>;
83 | uuid?: Maybe;
84 | };
85 |
86 | export type ArticleItems = {
87 | __typename?: 'ArticleItems';
88 | items?: Maybe>>;
89 | total?: Maybe;
90 | };
91 |
92 | export type ArticleoverviewComponent = {
93 | __typename?: 'ArticleoverviewComponent';
94 | _editable?: Maybe;
95 | _uid?: Maybe;
96 | component?: Maybe;
97 | headline?: Maybe;
98 | };
99 |
100 | export type ArticleoverviewFilterQuery = {
101 | headline?: Maybe;
102 | };
103 |
104 | export type ArticleoverviewItem = {
105 | __typename?: 'ArticleoverviewItem';
106 | alternates?: Maybe>>;
107 | content?: Maybe;
108 | created_at?: Maybe;
109 | default_full_slug?: Maybe;
110 | first_published_at?: Maybe;
111 | full_slug?: Maybe;
112 | group_id?: Maybe;
113 | id?: Maybe;
114 | is_startpage?: Maybe;
115 | lang?: Maybe;
116 | meta_data?: Maybe;
117 | name?: Maybe;
118 | parent_id?: Maybe;
119 | path?: Maybe;
120 | position?: Maybe;
121 | published_at?: Maybe;
122 | release_id?: Maybe;
123 | slug?: Maybe;
124 | sort_by_date?: Maybe;
125 | tag_list?: Maybe>>;
126 | translated_slugs?: Maybe>>;
127 | uuid?: Maybe;
128 | };
129 |
130 | export type ArticleoverviewItems = {
131 | __typename?: 'ArticleoverviewItems';
132 | items?: Maybe>>;
133 | total?: Maybe;
134 | };
135 |
136 | export type Asset = {
137 | __typename?: 'Asset';
138 | alt?: Maybe;
139 | copyright?: Maybe;
140 | filename: Scalars['String'];
141 | focus?: Maybe;
142 | id?: Maybe;
143 | name?: Maybe;
144 | title?: Maybe;
145 | };
146 |
147 | export type AuthorComponent = {
148 | __typename?: 'AuthorComponent';
149 | _editable?: Maybe;
150 | _uid?: Maybe;
151 | component?: Maybe;
152 | image?: Maybe;
153 | name?: Maybe;
154 | };
155 |
156 | export type AuthorFilterQuery = {
157 | name?: Maybe;
158 | };
159 |
160 | export type AuthorItem = {
161 | __typename?: 'AuthorItem';
162 | alternates?: Maybe>>;
163 | content?: Maybe;
164 | created_at?: Maybe;
165 | default_full_slug?: Maybe;
166 | first_published_at?: Maybe;
167 | full_slug?: Maybe;
168 | group_id?: Maybe;
169 | id?: Maybe;
170 | is_startpage?: Maybe;
171 | lang?: Maybe;
172 | meta_data?: Maybe;
173 | name?: Maybe;
174 | parent_id?: Maybe;
175 | path?: Maybe;
176 | position?: Maybe;
177 | published_at?: Maybe;
178 | release_id?: Maybe;
179 | slug?: Maybe;
180 | sort_by_date?: Maybe;
181 | tag_list?: Maybe>>;
182 | translated_slugs?: Maybe>>;
183 | uuid?: Maybe;
184 | };
185 |
186 | export type AuthorItems = {
187 | __typename?: 'AuthorItems';
188 | items?: Maybe>>;
189 | total?: Maybe;
190 | };
191 |
192 | export type BlankComponent = {
193 | __typename?: 'BlankComponent';
194 | _editable?: Maybe;
195 | _uid?: Maybe;
196 | body?: Maybe;
197 | component?: Maybe;
198 | };
199 |
200 | export type BlankItem = {
201 | __typename?: 'BlankItem';
202 | alternates?: Maybe>>;
203 | content?: Maybe;
204 | created_at?: Maybe;
205 | default_full_slug?: Maybe;
206 | first_published_at?: Maybe;
207 | full_slug?: Maybe;
208 | group_id?: Maybe;
209 | id?: Maybe;
210 | is_startpage?: Maybe;
211 | lang?: Maybe;
212 | meta_data?: Maybe;
213 | name?: Maybe;
214 | parent_id?: Maybe;
215 | path?: Maybe;
216 | position?: Maybe;
217 | published_at?: Maybe;
218 | release_id?: Maybe;
219 | slug?: Maybe;
220 | sort_by_date?: Maybe;
221 | tag_list?: Maybe>>;
222 | translated_slugs?: Maybe>>;
223 | uuid?: Maybe;
224 | };
225 |
226 | export type BlankItems = {
227 | __typename?: 'BlankItems';
228 | items?: Maybe>>;
229 | total?: Maybe;
230 | };
231 |
232 | export type CategoriesComponent = {
233 | __typename?: 'CategoriesComponent';
234 | _editable?: Maybe;
235 | _uid?: Maybe;
236 | component?: Maybe;
237 | intro?: Maybe;
238 | };
239 |
240 | export type CategoriesItem = {
241 | __typename?: 'CategoriesItem';
242 | alternates?: Maybe>>;
243 | content?: Maybe;
244 | created_at?: Maybe;
245 | default_full_slug?: Maybe;
246 | first_published_at?: Maybe;
247 | full_slug?: Maybe;
248 | group_id?: Maybe;
249 | id?: Maybe;
250 | is_startpage?: Maybe;
251 | lang?: Maybe;
252 | meta_data?: Maybe;
253 | name?: Maybe;
254 | parent_id?: Maybe;
255 | path?: Maybe;
256 | position?: Maybe;
257 | published_at?: Maybe;
258 | release_id?: Maybe;
259 | slug?: Maybe;
260 | sort_by_date?: Maybe;
261 | tag_list?: Maybe>>;
262 | translated_slugs?: Maybe>>;
263 | uuid?: Maybe;
264 | };
265 |
266 | export type CategoriesItems = {
267 | __typename?: 'CategoriesItems';
268 | items?: Maybe>>;
269 | total?: Maybe;
270 | };
271 |
272 | export type ContentItem = {
273 | __typename?: 'ContentItem';
274 | alternates?: Maybe>>;
275 | content?: Maybe;
276 | content_string?: Maybe;
277 | created_at?: Maybe;
278 | default_full_slug?: Maybe;
279 | first_published_at?: Maybe;
280 | full_slug?: Maybe;
281 | group_id?: Maybe;
282 | id?: Maybe;
283 | is_startpage?: Maybe;
284 | lang?: Maybe;
285 | meta_data?: Maybe;
286 | name?: Maybe;
287 | parent_id?: Maybe;
288 | path?: Maybe;
289 | position?: Maybe;
290 | published_at?: Maybe;
291 | release_id?: Maybe;
292 | slug?: Maybe;
293 | sort_by_date?: Maybe;
294 | tag_list?: Maybe>>;
295 | translated_slugs?: Maybe>>;
296 | uuid?: Maybe;
297 | };
298 |
299 | export type ContentItems = {
300 | __typename?: 'ContentItems';
301 | items?: Maybe>>;
302 | total?: Maybe;
303 | };
304 |
305 | export type Datasource = {
306 | __typename?: 'Datasource';
307 | id: Scalars['Int'];
308 | name: Scalars['String'];
309 | slug: Scalars['String'];
310 | };
311 |
312 | export type DatasourceEntries = {
313 | __typename?: 'DatasourceEntries';
314 | items: Array;
315 | total: Scalars['Int'];
316 | };
317 |
318 | export type DatasourceEntry = {
319 | __typename?: 'DatasourceEntry';
320 | dimensionValue?: Maybe;
321 | id: Scalars['Int'];
322 | name: Scalars['String'];
323 | value: Scalars['String'];
324 | };
325 |
326 | export type Datasources = {
327 | __typename?: 'Datasources';
328 | items: Array;
329 | };
330 |
331 | export type FilterQueryOperations = {
332 | /** Matches exactly one value */
333 | in?: Maybe;
334 | /** Matches all without the given value */
335 | not_in?: Maybe;
336 | /** Matches exactly one value with a wildcard search using * */
337 | like?: Maybe;
338 | /** Matches all without the given value */
339 | not_like?: Maybe;
340 | /** Matches any value of given array */
341 | in_array?: Maybe>>;
342 | /** Must match all values of given array */
343 | all_in_array?: Maybe>>;
344 | /** Greater than date (Exmples: 2019-03-03 or 2020-03-03T03:03:03) */
345 | gt_date?: Maybe;
346 | /** Less than date (Format: 2019-03-03 or 2020-03-03T03:03:03) */
347 | lt_date?: Maybe;
348 | /** Greater than integer value */
349 | gt_int?: Maybe;
350 | /** Less than integer value */
351 | lt_int?: Maybe;
352 | /** Matches exactly one integer value */
353 | in_int?: Maybe;
354 | /** Greater than float value */
355 | gt_float?: Maybe;
356 | /** Less than float value */
357 | lt_float?: Maybe;
358 | };
359 |
360 | export type GalleryComponent = {
361 | __typename?: 'GalleryComponent';
362 | _editable?: Maybe;
363 | _uid?: Maybe;
364 | component?: Maybe;
365 | images?: Maybe>>;
366 | };
367 |
368 | export type GalleryItem = {
369 | __typename?: 'GalleryItem';
370 | alternates?: Maybe>>;
371 | content?: Maybe;
372 | created_at?: Maybe;
373 | default_full_slug?: Maybe;
374 | first_published_at?: Maybe;
375 | full_slug?: Maybe;
376 | group_id?: Maybe;
377 | id?: Maybe;
378 | is_startpage?: Maybe;
379 | lang?: Maybe;
380 | meta_data?: Maybe;
381 | name?: Maybe;
382 | parent_id?: Maybe;
383 | path?: Maybe;
384 | position?: Maybe;
385 | published_at?: Maybe;
386 | release_id?: Maybe;
387 | slug?: Maybe;
388 | sort_by_date?: Maybe;
389 | tag_list?: Maybe>>;
390 | translated_slugs?: Maybe>>;
391 | uuid?: Maybe;
392 | };
393 |
394 | export type GalleryItems = {
395 | __typename?: 'GalleryItems';
396 | items?: Maybe>>;
397 | total?: Maybe;
398 | };
399 |
400 | export type GlobalComponent = {
401 | __typename?: 'GlobalComponent';
402 | _editable?: Maybe;
403 | _uid?: Maybe;
404 | component?: Maybe;
405 | footer?: Maybe;
406 | header?: Maybe;
407 | };
408 |
409 | export type GlobalItem = {
410 | __typename?: 'GlobalItem';
411 | alternates?: Maybe>>;
412 | content?: Maybe;
413 | created_at?: Maybe;
414 | default_full_slug?: Maybe