main 7ab5f0b7e292 cached
204 files
214.7 KB
63.2k tokens
61 symbols
1 requests
Download .txt
Showing preview only (271K chars total). Download the full file or copy to clipboard to get everything.
Repository: strapi/starters-and-templates
Branch: main
Commit: 7ab5f0b7e292
Files: 204
Total size: 214.7 KB

Directory structure:
gitextract_ipi637vq/

├── .gitignore
├── LICENSE.txt
├── README.md
├── lerna.json
├── package.json
└── packages/
    ├── starters/
    │   ├── .gitkeep
    │   ├── gatsby-blog/
    │   │   ├── README.md
    │   │   ├── package.json
    │   │   ├── starter/
    │   │   │   ├── .eslintrc.js
    │   │   │   ├── .gitignore
    │   │   │   ├── README.md
    │   │   │   ├── gatsby-browser.js
    │   │   │   ├── gatsby-config.js
    │   │   │   ├── gatsby-node.js
    │   │   │   ├── package.json
    │   │   │   ├── postcss.config.js
    │   │   │   ├── src/
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── article-card.js
    │   │   │   │   │   ├── articles-grid.js
    │   │   │   │   │   ├── block-media.js
    │   │   │   │   │   ├── block-quote.js
    │   │   │   │   │   ├── block-rich-text.js
    │   │   │   │   │   ├── block-slider.js
    │   │   │   │   │   ├── blocks-renderer.js
    │   │   │   │   │   ├── footer.js
    │   │   │   │   │   ├── headings.js
    │   │   │   │   │   ├── layout.js
    │   │   │   │   │   ├── navbar.js
    │   │   │   │   │   └── seo.js
    │   │   │   │   ├── pages/
    │   │   │   │   │   ├── about.js
    │   │   │   │   │   └── index.js
    │   │   │   │   ├── styles/
    │   │   │   │   │   └── global.css
    │   │   │   │   └── templates/
    │   │   │   │       └── article-post.js
    │   │   │   └── tailwind.config.js
    │   │   └── starter.json
    │   ├── gatsby-corporate/
    │   │   └── README.md
    │   ├── next-blog/
    │   │   ├── README.md
    │   │   ├── package.json
    │   │   ├── starter/
    │   │   │   ├── .eslintrc
    │   │   │   ├── .prettierrc
    │   │   │   ├── assets/
    │   │   │   │   └── css/
    │   │   │   │       └── style.css
    │   │   │   ├── components/
    │   │   │   │   ├── articles.js
    │   │   │   │   ├── card.js
    │   │   │   │   ├── image.js
    │   │   │   │   ├── layout.js
    │   │   │   │   ├── nav.js
    │   │   │   │   └── seo.js
    │   │   │   ├── lib/
    │   │   │   │   ├── api.js
    │   │   │   │   └── media.js
    │   │   │   ├── next.config.js
    │   │   │   ├── package.json
    │   │   │   └── pages/
    │   │   │       ├── _app.js
    │   │   │       ├── _document.js
    │   │   │       ├── article/
    │   │   │       │   └── [slug].js
    │   │   │       ├── category/
    │   │   │       │   └── [slug].js
    │   │   │       └── index.js
    │   │   └── starter.json
    │   └── next-corporate/
    │       ├── README.md
    │       ├── package.json
    │       ├── starter/
    │       │   ├── .eslintrc
    │       │   ├── .gitignore
    │       │   ├── README.md
    │       │   ├── components/
    │       │   │   ├── elements/
    │       │   │   │   ├── button-link.js
    │       │   │   │   ├── button.js
    │       │   │   │   ├── custom-link.js
    │       │   │   │   ├── footer.js
    │       │   │   │   ├── image.js
    │       │   │   │   ├── loader.js
    │       │   │   │   ├── mobile-nav-menu.js
    │       │   │   │   ├── navbar.js
    │       │   │   │   ├── notification-banner.js
    │       │   │   │   ├── seo.js
    │       │   │   │   └── video.js
    │       │   │   ├── icons/
    │       │   │   │   └── world.js
    │       │   │   ├── layout.js
    │       │   │   ├── locale-switch.js
    │       │   │   ├── sections/
    │       │   │   │   ├── bottom-actions.js
    │       │   │   │   ├── feature-columns-group.js
    │       │   │   │   ├── feature-rows-group.js
    │       │   │   │   ├── hero.js
    │       │   │   │   ├── large-video.js
    │       │   │   │   ├── lead-form.js
    │       │   │   │   ├── pricing.js
    │       │   │   │   ├── rich-text.js
    │       │   │   │   └── testimonials-group.js
    │       │   │   └── sections.js
    │       │   ├── jsconfig.json
    │       │   ├── next.config.js
    │       │   ├── package.json
    │       │   ├── pages/
    │       │   │   ├── [[...slug]].js
    │       │   │   ├── _app.js
    │       │   │   ├── _document.js
    │       │   │   └── api/
    │       │   │       ├── exit-preview.js
    │       │   │       └── preview.js
    │       │   ├── postcss.config.js
    │       │   ├── public/
    │       │   │   └── .gitkeep
    │       │   ├── styles/
    │       │   │   └── index.css
    │       │   ├── tailwind.config.js
    │       │   └── utils/
    │       │       ├── api.js
    │       │       ├── button.js
    │       │       ├── hooks.js
    │       │       ├── localize.js
    │       │       ├── media.js
    │       │       ├── parse-cookies.js
    │       │       └── types.js
    │       └── starter.json
    └── templates/
        ├── .gitkeep
        ├── blog/
        │   ├── README.md
        │   ├── package.json
        │   ├── template/
        │   │   ├── data/
        │   │   │   └── data.json
        │   │   └── src/
        │   │       ├── api/
        │   │       │   ├── .gitkeep
        │   │       │   ├── about/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── about/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── about.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── about.js
        │   │       │   │   └── services/
        │   │       │   │       └── about.js
        │   │       │   ├── article/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── article/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── article.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── article.js
        │   │       │   │   └── services/
        │   │       │   │       └── article.js
        │   │       │   ├── author/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── author/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── author.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── author.js
        │   │       │   │   └── services/
        │   │       │   │       └── author.js
        │   │       │   ├── category/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── category/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── category.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── category.js
        │   │       │   │   └── services/
        │   │       │   │       └── category.js
        │   │       │   └── global/
        │   │       │       ├── content-types/
        │   │       │       │   └── global/
        │   │       │       │       └── schema.json
        │   │       │       ├── controllers/
        │   │       │       │   └── global.js
        │   │       │       ├── routes/
        │   │       │       │   └── global.js
        │   │       │       └── services/
        │   │       │           └── global.js
        │   │       ├── bootstrap.js
        │   │       ├── components/
        │   │       │   └── shared/
        │   │       │       ├── media.json
        │   │       │       ├── quote.json
        │   │       │       ├── rich-text.json
        │   │       │       ├── seo.json
        │   │       │       └── slider.json
        │   │       ├── extensions/
        │   │       │   └── .gitkeep
        │   │       └── index.js
        │   └── template.json
        ├── corporate/
        │   ├── README.md
        │   ├── package.json
        │   ├── template/
        │   │   ├── data/
        │   │   │   ├── data.js
        │   │   │   ├── en/
        │   │   │   │   ├── global.json
        │   │   │   │   ├── index.js
        │   │   │   │   └── pages.json
        │   │   │   ├── fr/
        │   │   │   │   ├── global.json
        │   │   │   │   ├── index.js
        │   │   │   │   └── pages.json
        │   │   │   └── lead-form-submissions.json
        │   │   └── src/
        │   │       ├── api/
        │   │       │   ├── .gitkeep
        │   │       │   ├── global/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── global/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── global.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── global.js
        │   │       │   │   └── services/
        │   │       │   │       └── global.js
        │   │       │   ├── lead-form-submission/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── lead-form-submission/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── lead-form-submission.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── lead-form-submission.js
        │   │       │   │   └── services/
        │   │       │   │       └── lead-form-submission.js
        │   │       │   └── page/
        │   │       │       ├── content-types/
        │   │       │       │   └── page/
        │   │       │       │       └── schema.json
        │   │       │       ├── controllers/
        │   │       │       │   └── page.js
        │   │       │       ├── routes/
        │   │       │       │   └── page.js
        │   │       │       └── services/
        │   │       │           └── page.js
        │   │       ├── bootstrap.js
        │   │       ├── components/
        │   │       │   ├── elements/
        │   │       │   │   ├── feature-column.json
        │   │       │   │   ├── feature-row.json
        │   │       │   │   ├── feature.json
        │   │       │   │   ├── footer-section.json
        │   │       │   │   ├── logos.json
        │   │       │   │   ├── notification-banner.json
        │   │       │   │   ├── plan.json
        │   │       │   │   └── testimonial.json
        │   │       │   ├── layout/
        │   │       │   │   ├── footer.json
        │   │       │   │   └── navbar.json
        │   │       │   ├── links/
        │   │       │   │   ├── button-link.json
        │   │       │   │   ├── button.json
        │   │       │   │   └── link.json
        │   │       │   ├── meta/
        │   │       │   │   └── metadata.json
        │   │       │   └── sections/
        │   │       │       ├── bottom-actions.json
        │   │       │       ├── feature-columns-group.json
        │   │       │       ├── feature-rows-group.json
        │   │       │       ├── hero.json
        │   │       │       ├── large-video.json
        │   │       │       ├── lead-form.json
        │   │       │       ├── pricing.json
        │   │       │       ├── rich-text.json
        │   │       │       └── testimonials-group.json
        │   │       └── index.js
        │   └── template.json
        └── ecommerce/
            ├── README.md
            ├── package.json
            ├── template/
            │   ├── data/
            │   │   └── data.js
            │   └── src/
            │       ├── api/
            │       │   ├── .gitkeep
            │       │   ├── category/
            │       │   │   ├── content-types/
            │       │   │   │   └── category/
            │       │   │   │       └── schema.json
            │       │   │   ├── controllers/
            │       │   │   │   └── category.js
            │       │   │   ├── routes/
            │       │   │   │   └── category.js
            │       │   │   └── services/
            │       │   │       └── category.js
            │       │   └── product/
            │       │       ├── content-types/
            │       │       │   └── product/
            │       │       │       └── schema.json
            │       │       ├── controllers/
            │       │       │   └── product.js
            │       │       ├── routes/
            │       │       │   └── product.js
            │       │       └── services/
            │       │           └── product.js
            │       ├── bootstrap.js
            │       ├── components/
            │       │   └── custom/
            │       │       └── custom-field.json
            │       └── index.js
            └── template.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================

# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,visualstudiocode

### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test
.env.production

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

### VisualStudioCode ###
.vscode/*
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace

# Local History for Visual Studio Code
.history/

### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide

### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,visualstudiocode

# Template development directory
template-dev/

================================================
FILE: LICENSE.txt
================================================
MIT License

Copyright (c) 2021 Strapi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
> [!WARNING]
> This repository is only compatible with Strapi v4 version<br/>
> The most recent information can be found at https://docs.strapi.io/


# Strapi starters & templates

Monorepo for all official Strapi v4 starters and templates.

### Starters

> As you may have [noticed](https://github.com/strapi/starters-and-templates/issues?q=is%3Aissue+is%3Aopen+install), a lot of the Starters are out of date and given constraints in bandwidth and other priorities, we've decided to sunset all Starters and only actively maintain a single Next.js Starter. 


- [Gatsby Blog](./packages/starters/gatsby-blog)
- [Next Blog](./packages/starters/next-blog)
- [Next Corporate Site](./packages/starters/next-corporate)

### Templates

- [Blog](./packages/templates/blog)
- [Corporate](./packages/templates/corporate)
- [Ecommerce](./packages/templates/ecommerce)


================================================
FILE: lerna.json
================================================
{
  "packages": [
    "packages/templates/*",
    "packages/starters/*"
  ],
  "npmClient": "yarn",
  "useWorkspaces": true,
  "version": "independent"
}


================================================
FILE: package.json
================================================
{
  "name": "@strapi/starters-and-templates",
  "version": "1.0.0",
  "private": true,
  "description": "All Strapi templates",
  "repository": "https://github.com/strapi/starters-and-templates.git",
  "license": "MIT",
  "author": {
    "name": "Strapi team",
    "email": "hi@strapi.io",
    "url": "https://strapi.io"
  },
  "maintainers": [
    {
      "name": "Strapi team",
      "email": "hi@strapi.io",
      "url": "https://strapi.io"
    }
  ],
  "workspaces": [
    "packages/**/*"
  ],
  "devDependencies": {
    "lerna": "^4.0.0"
  }
}


================================================
FILE: packages/starters/.gitkeep
================================================


================================================
FILE: packages/starters/gatsby-blog/README.md
================================================
# Strapi Starter Gatsby Blog

Gatsby starter for creating a blog with Strapi.

This starter allows you to try Strapi with Gatsby with the example of a simple blog. It is fully customizable and due to the fact that it is open source, fully open to contributions. So do not hesitate to add new features and report bugs!

This starter uses the [Strapi blog template](https://github.com/strapi/starters-and-templates/tree/main/packages/templates/blog)

## Getting started

Use our `create-strapi-starter` CLI to create your project.

```sh
# Using Yarn
yarn create strapi-starter my-project gatsby-blog

# Or using NPM
npx create-strapi-starter my-project gatsby-blog
```

The CLI will create a monorepo, install dependencies, and run your project automatically.

The Gatsby frontend server will run here => [http://localhost:3000](http://localhost:3000)

The Strapi backend server will run here => [http://localhost:1337](http://localhost:1337)

You will however need to manually create a full access [API token](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/api-tokens.html) in Strapi. Once it's created, save it as `STRAPI_TOKEN` in your environment variables.

## Deploying to production

You will need to deploy the `frontend` and `backend` projects separately. Here are the docs to deploy each one:

- [Deploy Strapi](https://strapi.io/documentation/developer-docs/latest/setup-deployment-guides/deployment.html#hosting-provider-guides)
- [Deploy Gatsby](https://www.gatsbyjs.com/docs/deploying-and-hosting/)

Enjoy this starter!

================================================
FILE: packages/starters/gatsby-blog/package.json
================================================
{
  "name": "@strapi/starter-gatsby-blog",
  "version": "1.0.7",
  "description": "Strapi blog starter with Gatsby",
  "keywords": [
    "strapi",
    "starter",
    "gatsby",
    "blog"
  ],
  "homepage": "https://github.com/strapi/starters-and-templates/tree/main/packages/starters/gatsby-blog#readme",
  "bugs": {
    "url": "https://github.com/strapi/starters-and-templates/issues"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/strapi/starters-and-templates.git"
  },
  "license": "MIT",
  "author": {
    "name": "Strapi team",
    "email": "hi@strapi.io",
    "url": "https://strapi.io"
  },
  "maintainers": [
    {
      "name": "Strapi team",
      "email": "hi@strapi.io",
      "url": "https://strapi.io"
    }
  ]
}


================================================
FILE: packages/starters/gatsby-blog/starter/.eslintrc.js
================================================
module.exports = {
  globals: {
    __PATH_PREFIX__: true,
  },
  extends: ["react-app", "prettier"],
  plugins: ["prettier"],
  rules: {
    "prettier/prettier": [
      "error",
      {
        printWidth: 80,
        singleQuote: false,
        trailingComma: "es5",
        semi: false,
        tabWidth: 2,
      },
    ],
  },
}


================================================
FILE: packages/starters/gatsby-blog/starter/.gitignore
================================================
node_modules/
.cache/
public
.env
.env.production
.env.local
.env.development


================================================
FILE: packages/starters/gatsby-blog/starter/README.md
================================================
<p align="center">
  <a href="https://www.gatsbyjs.com/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter">
    <img alt="Gatsby" src="https://www.gatsbyjs.com/Gatsby-Monogram.svg" width="60" />
  </a>
</p>
<h1 align="center">
  Gatsby minimal starter
</h1>

## 🚀 Quick start

1.  **Create a Gatsby site.**

    Use the Gatsby CLI to create a new site, specifying the minimal starter.

    ```shell
    # create a new Gatsby site using the minimal starter
    npm init gatsby
    ```

2.  **Start developing.**

    Navigate into your new site’s directory and start it up.

    ```shell
    cd my-gatsby-site/
    npm run develop
    ```

3.  **Open the code and start customizing!**

    Your site is now running at http://localhost:8000!

    Edit `src/pages/index.js` to see your site update in real-time!

4.  **Learn more**

    - [Documentation](https://www.gatsbyjs.com/docs/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter)

    - [Tutorials](https://www.gatsbyjs.com/tutorial/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter)

    - [Guides](https://www.gatsbyjs.com/tutorial/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter)

    - [API Reference](https://www.gatsbyjs.com/docs/api-reference/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter)

    - [Plugin Library](https://www.gatsbyjs.com/plugins?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter)

    - [Cheat Sheet](https://www.gatsbyjs.com/docs/cheat-sheet/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter)

## 🚀 Quick start (Gatsby Cloud)

Deploy this starter with one click on [Gatsby Cloud](https://www.gatsbyjs.com/cloud/):

[<img src="https://www.gatsbyjs.com/deploynow.svg" alt="Deploy to Gatsby Cloud">](https://www.gatsbyjs.com/dashboard/deploynow?url=https://github.com/gatsbyjs/gatsby-starter-minimal)


================================================
FILE: packages/starters/gatsby-blog/starter/gatsby-browser.js
================================================
import "./src/styles/global.css"


================================================
FILE: packages/starters/gatsby-blog/starter/gatsby-config.js
================================================
require("dotenv").config({
  path: `.env.${process.env.NODE_ENV}`,
})

module.exports = {
  plugins: [
    "gatsby-plugin-gatsby-cloud",
    "gatsby-plugin-postcss",
    {
      resolve: "gatsby-source-strapi",
      options: {
        apiURL: process.env.STRAPI_API_URL || "http://localhost:1337",
        accessToken: process.env.STRAPI_TOKEN,
        collectionTypes: [
          {
            singularName: "article",
            queryParams: {
              publicationState:
                process.env.GATSBY_IS_PREVIEW === "true" ? "preview" : "live",
              populate: {
                cover: "*",
                blocks: {
                  populate: "*",
                },
              },
            },
          },
          {
            singularName: "author",
          },
          {
            singularName: "category",
          },
        ],
        singleTypes: [
          {
            singularName: "about",
            queryParams: {
              populate: {
                blocks: {
                  populate: "*",
                },
              },
            },
          },
          {
            singularName: "global",
            queryParams: {
              populate: {
                favicon: "*",
                defaultSeo: {
                  populate: "*",
                },
              },
            },
          },
        ],
      },
    },
    "gatsby-plugin-image",
    "gatsby-plugin-sharp",
    "gatsby-transformer-sharp",
    "gatsby-transformer-remark",
  ],
}


================================================
FILE: packages/starters/gatsby-blog/starter/gatsby-node.js
================================================
const path = require("path")

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions

  // Define a template for blog post
  const articlePost = path.resolve("./src/templates/article-post.js")

  const result = await graphql(
    `
      {
        allStrapiArticle {
          nodes {
            title
            slug
          }
        }
      }
    `
  )

  if (result.errors) {
    reporter.panicOnBuild(
      `There was an error loading your Strapi articles`,
      result.errors
    )

    return
  }

  const articles = result.data.allStrapiArticle.nodes

  if (articles.length > 0) {
    articles.forEach((article) => {
      createPage({
        path: `/article/${article.slug}`,
        component: articlePost,
        context: {
          slug: article.slug,
        },
      })
    })
  }
}


================================================
FILE: packages/starters/gatsby-blog/starter/package.json
================================================
{
  "name": "my-gatsby-blog",
  "version": "1.0.7",
  "private": true,
  "description": "Strapi Gatsby Blog",
  "author": "Strapi team",
  "keywords": [
    "gatsby"
  ],
  "scripts": {
    "develop": "gatsby develop",
    "start": "gatsby develop",
    "build": "gatsby build",
    "serve": "gatsby serve",
    "clean": "gatsby clean",
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  },
  "dependencies": {
    "gatsby": "^4.6.1",
    "gatsby-plugin-gatsby-cloud": "^4.7.0",
    "gatsby-plugin-image": "^2.6.0",
    "gatsby-plugin-postcss": "^5.6.0",
    "gatsby-plugin-sharp": "^4.6.0",
    "gatsby-source-strapi": "^2.0.0",
    "gatsby-transformer-remark": "^5.6.0",
    "gatsby-transformer-sharp": "^4.6.0",
    "postcss": "^8.4.6",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-helmet": "^6.1.0",
    "react-slick": "^0.28.1",
    "slick-carousel": "^1.8.1"
  },
  "devDependencies": {
    "@tailwindcss/line-clamp": "^0.3.1",
    "@tailwindcss/typography": "^0.5.1",
    "autoprefixer": "^10.4.2",
    "eslint": "^8.8.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-config-react-app": "^7.0.0",
    "eslint-plugin-prettier": "^4.0.0",
    "prettier": "^2.5.1",
    "prettier-plugin-tailwindcss": "^0.1.4",
    "tailwindcss": "^3.0.18"
  }
}


================================================
FILE: packages/starters/gatsby-blog/starter/postcss.config.js
================================================
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/article-card.js
================================================
import React from "react"
import { Link, graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"

const ArticleCard = ({ article }) => {
  return (
    <Link
      to={`/article/${article.slug}`}
      className="overflow-hidden rounded-lg bg-white shadow-sm transition-shadow hover:shadow-md"
    >
      <GatsbyImage
        image={getImage(article.cover?.localFile)}
        alt={article.cover?.alternativeText}
      />
      <div className="px-4 py-4">
        <h3 className="font-bold text-neutral-700">{article.title}</h3>
        <p className="line-clamp-2 mt-2 text-neutral-500">
          {article.description}
        </p>
      </div>
    </Link>
  )
}

export const query = graphql`
  fragment ArticleCard on STRAPI_ARTICLE {
    id
    slug
    title
    description
    cover {
      alternativeText
      localFile {
        childImageSharp {
          gatsbyImageData(aspectRatio: 1.77)
        }
      }
    }
  }
`

export default ArticleCard


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/articles-grid.js
================================================
import React from "react"
import ArticleCard from "./article-card"

const ArticlesGrid = ({ articles }) => {
  return (
    <div className="container mt-12 grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
      {articles.map((article) => (
        <ArticleCard article={article} />
      ))}
    </div>
  )
}

export default ArticlesGrid


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/block-media.js
================================================
import React from "react"
import { GatsbyImage, getImage } from "gatsby-plugin-image"

const BlockMedia = ({ data }) => {
  const isVideo = data.file.mime.startsWith("video")

  return (
    <div className="py-8">
      {isVideo ? (
        <p>TODO video</p>
      ) : (
        <GatsbyImage
          image={getImage(data.file.localFile)}
          alt={data.file.alternativeText}
        />
      )}
    </div>
  )
}

export default BlockMedia


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/block-quote.js
================================================
import React from "react"

const BlockQuote = ({ data }) => {
  return (
    <div className="py-6">
      <blockquote className="container max-w-xl border-l-4 border-neutral-700 py-2 pl-6 text-neutral-700">
        <p className="text-5xl font-medium italic">{data.quoteBody}</p>
        <cite className="mt-4 block font-bold uppercase not-italic">
          {data.title}
        </cite>
      </blockquote>
    </div>
  )
}

export default BlockQuote


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/block-rich-text.js
================================================
import React from "react"

const BlockRichText = ({ data }) => {
  return (
    <div className="prose mx-auto py-8">
      <div
        dangerouslySetInnerHTML={{
          __html: data.richTextBody.data.childMarkdownRemark.html,
        }}
      />
    </div>
  )
}

export default BlockRichText


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/block-slider.js
================================================
import React from "react"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import Slider from "react-slick"
import "slick-carousel/slick/slick.css"
import "slick-carousel/slick/slick-theme.css"

const BlockSlider = ({ data }) => {
  return (
    <div className="container max-w-3xl py-8">
      <Slider
        dots={true}
        infinite={true}
        speed={300}
        slidesToShow={1}
        slidesToScroll={1}
        arrows={true}
        swipe={true}
      >
        {data.files.map((file) => (
          <GatsbyImage
            key={file.id}
            image={getImage(file.localFile)}
            alt={file.alternativeText}
          />
        ))}
      </Slider>
    </div>
  )
}

export default BlockSlider


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/blocks-renderer.js
================================================
import React from "react"
import { graphql } from "gatsby"
import BlockRichText from "./block-rich-text"
import BlockMedia from "./block-media"
import BlockQuote from "./block-quote"
import BlockSlider from "./block-slider"

const componentsMap = {
  STRAPI__COMPONENT_SHARED_RICH_TEXT: BlockRichText,
  STRAPI__COMPONENT_SHARED_MEDIA: BlockMedia,
  STRAPI__COMPONENT_SHARED_QUOTE: BlockQuote,
  STRAPI__COMPONENT_SHARED_SLIDER: BlockSlider,
}

const Block = ({ block }) => {
  const Component = componentsMap[block.__typename]

  if (!Component) {
    return null
  }

  return <Component data={block} />
}

const BlocksRenderer = ({ blocks }) => {
  return (
    <div>
      {blocks.map((block, index) => (
        <Block key={`${index}${block.__typename}`} block={block} />
      ))}
    </div>
  )
}

export const query = graphql`
  fragment Blocks on STRAPI__COMPONENT_SHARED_MEDIASTRAPI__COMPONENT_SHARED_QUOTESTRAPI__COMPONENT_SHARED_RICH_TEXTSTRAPI__COMPONENT_SHARED_SLIDERUnion {
    __typename
    ... on STRAPI__COMPONENT_SHARED_RICH_TEXT {
      richTextBody: body {
        __typename
        data {
          id
          childMarkdownRemark {
            html
          }
        }
      }
    }
    ... on STRAPI__COMPONENT_SHARED_MEDIA {
      file {
        mime
        localFile {
          childImageSharp {
            gatsbyImageData
          }
        }
      }
    }
    ... on STRAPI__COMPONENT_SHARED_QUOTE {
      title
      quoteBody: body
    }
    ... on STRAPI__COMPONENT_SHARED_SLIDER {
      files {
        id
        mime
        localFile {
          childImageSharp {
            gatsbyImageData
          }
        }
      }
    }
  }
`

export default BlocksRenderer


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/footer.js
================================================
import React from "react"

const Footer = () => {
  const currentYear = new Date().getFullYear()

  return (
    <footer className="mt-16 bg-neutral-100 py-8 text-neutral-700">
      <div className="container">
        <p>Copyright {currentYear}</p>
      </div>
    </footer>
  )
}

export default Footer


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/headings.js
================================================
import React from "react"

const Headings = ({ title, description }) => {
  return (
    <header className="container mt-8">
      <h1 className="text-6xl font-bold text-neutral-700">{title}</h1>
      {description && (
        <p className="mt-4 text-2xl text-neutral-500">{description}</p>
      )}
    </header>
  )
}

export default Headings


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/layout.js
================================================
import React from "react"
import Footer from "./footer"
import Navbar from "./navbar"

const Layout = ({ children }) => {
  return (
    <div className="flex min-h-screen flex-col justify-between bg-neutral-50 text-neutral-900">
      <div>
        <Navbar />
        {children}
      </div>
      <Footer />
    </div>
  )
}

export default Layout


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/navbar.js
================================================
import { Link } from "gatsby"
import React from "react"

const Navbar = () => {
  return (
    <header className="bg-primary-200">
      <nav className="container flex flex-row items-baseline justify-between py-6">
        <Link to="/" className="text-xl font-medium">
          Blog
        </Link>
        <div className="flex flex-row items-baseline justify-end">
          <Link className="font-medium" to="/about">
            About
          </Link>
        </div>
      </nav>
    </header>
  )
}

export default Navbar


================================================
FILE: packages/starters/gatsby-blog/starter/src/components/seo.js
================================================
import React from "react"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"

const Seo = ({ seo = {} }) => {
  const { strapiGlobal } = useStaticQuery(graphql`
    query {
      strapiGlobal {
        siteName
        favicon {
          localFile {
            url
          }
        }
        defaultSeo {
          metaTitle
          metaDescription
          shareImage {
            localFile {
              url
            }
          }
        }
      }
    }
  `)

  const { siteName, defaultSeo, favicon } = strapiGlobal

  // Merge default and page-specific SEO values
  const fullSeo = { ...defaultSeo, ...seo }

  // Add site name to title
  fullSeo.metaTitle = `${fullSeo.metaTitle} | ${siteName}`

  const getMetaTags = () => {
    const tags = []

    if (fullSeo.metaTitle) {
      tags.push(
        {
          property: "og:title",
          content: fullSeo.metaTitle,
        },
        {
          name: "twitter:title",
          content: fullSeo.metaTitle,
        }
      )
    }
    if (fullSeo.metaDescription) {
      tags.push(
        {
          name: "description",
          content: fullSeo.metaDescription,
        },
        {
          property: "og:description",
          content: fullSeo.metaDescription,
        },
        {
          name: "twitter:description",
          content: fullSeo.metaDescription,
        }
      )
    }
    if (fullSeo.shareImage) {
      const imageUrl = fullSeo.shareImage.localFile.url
      tags.push(
        {
          name: "image",
          content: imageUrl,
        },
        {
          property: "og:image",
          content: imageUrl,
        },
        {
          name: "twitter:image",
          content: imageUrl,
        }
      )
    }
    if (fullSeo.article) {
      tags.push({
        property: "og:type",
        content: "article",
      })
    }
    tags.push({ name: "twitter:card", content: "summary_large_image" })

    return tags
  }

  const metaTags = getMetaTags()

  return (
    <Helmet
      title={fullSeo.metaTitle}
      link={[
        {
          rel: "icon",
          href: favicon.localFile.url,
        },
      ]}
      meta={metaTags}
    />
  )
}

export default Seo


================================================
FILE: packages/starters/gatsby-blog/starter/src/pages/about.js
================================================
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
import BlocksRenderer from "../components/blocks-renderer"
import Headings from "../components/headings"

const AboutPage = () => {
  const { strapiAbout } = useStaticQuery(graphql`
    query {
      strapiAbout {
        title
        blocks {
          ...Blocks
        }
      }
    }
  `)
  const { title, blocks } = strapiAbout

  const seo = {
    metaTitle: title,
    metaDescription: title,
  }

  return (
    <Layout>
      <Seo seo={seo} />
      <Headings title={strapiAbout.title} />
      <BlocksRenderer blocks={blocks} />
    </Layout>
  )
}

export default AboutPage


================================================
FILE: packages/starters/gatsby-blog/starter/src/pages/index.js
================================================
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Layout from "../components/layout"
import ArticlesGrid from "../components/articles-grid"
import Seo from "../components/seo"
import Headings from "../components/headings"

const IndexPage = () => {
  const { allStrapiArticle, strapiGlobal } = useStaticQuery(graphql`
    query {
      allStrapiArticle {
        nodes {
          ...ArticleCard
        }
      }
      strapiGlobal {
        siteName
        siteDescription
      }
    }
  `)

  return (
    <Layout>
      <Seo seo={{ metaTitle: "Home" }} />
      <Headings
        title={strapiGlobal.siteName}
        description={strapiGlobal.siteDescription}
      />
      <main>
        <ArticlesGrid articles={allStrapiArticle.nodes} />
      </main>
    </Layout>
  )
}

export default IndexPage


================================================
FILE: packages/starters/gatsby-blog/starter/src/styles/global.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;


================================================
FILE: packages/starters/gatsby-blog/starter/src/templates/article-post.js
================================================
import React from "react"
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import Layout from "../components/layout"
import BlocksRenderer from "../components/blocks-renderer"
import Seo from "../components/seo"

const ArticlePage = ({ data }) => {
  const article = data.strapiArticle

  const seo = {
    metaTitle: article.title,
    metaDescription: article.description,
    shareImage: article.cover,
  }

  return (
    <Layout as="article">
      <Seo seo={seo} />
      <header className="container max-w-4xl py-8">
        <h1 className="text-6xl font-bold text-neutral-700">{article.title}</h1>
        <p className="mt-4 text-2xl text-neutral-500">{article.description}</p>
        <GatsbyImage
          image={getImage(article?.cover?.localFile)}
          alt={article?.cover?.alternativeText}
          className="mt-6"
        />
      </header>
      <main className="mt-8">
        <BlocksRenderer blocks={article.blocks || []} />
      </main>
    </Layout>
  )
}

export const pageQuery = graphql`
  query ($slug: String) {
    strapiArticle(slug: { eq: $slug }) {
      id
      slug
      title
      description
      blocks {
        ...Blocks
      }
      cover {
        alternativeText
        localFile {
          url
          childImageSharp {
            gatsbyImageData
          }
        }
      }
    }
  }
`

export default ArticlePage


================================================
FILE: packages/starters/gatsby-blog/starter/tailwind.config.js
================================================
const colors = require("tailwindcss/colors")

module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {
      colors: {
        neutral: colors.neutral,
        primary: colors.sky,
      },
    },
    container: {
      center: true,
      padding: {
        DEFAULT: "1rem",
        xs: "1rem",
        sm: "2rem",
        xl: "5rem",
        "2xl": "6rem",
      },
    },
  },
  plugins: [
    require("@tailwindcss/line-clamp"),
    require("@tailwindcss/typography"),
  ],
}


================================================
FILE: packages/starters/gatsby-blog/starter.json
================================================
{
  "template": {
    "name": "@strapi/template-blog",
    "version": "^2.0.0"
  }
}


================================================
FILE: packages/starters/gatsby-corporate/README.md
================================================
# Placeholder for Strapi Gatsby corporate starter

The Strapi team will build this starter soon.

In the meantime, you can check out our other Strapi v4 starters:

- [Gatsby Blog](https://github.com/strapi/starters-and-templates/tree/main/packages/starters/gatsby-blog)
- [Next Blog](https://github.com/strapi/starters-and-templates/tree/main/packages/starters/next-blog)
- [Next Corporate Site](https://github.com/strapi/starters-and-templates/tree/main/packages/starters/next-corporate)


================================================
FILE: packages/starters/next-blog/README.md
================================================
# Strapi Starter Next Blog

Next starter for creating a blog with Strapi.

![screenshot image](./screenshot.png)

This starter allows you to try Strapi with Next with the example of a simple blog. It is fully customizable and due to the fact that it is open source, fully open to contributions. So do not hesitate to add new features and report bugs!

This starter uses the [Strapi blog template](https://github.com/strapi/strapi-template-blog)

Check out all of our starters [here](https://strapi.io/starters)

## Features

- 2 Content types: Article, Category
- 2 Created articles
- 3 Created categories
- Responsive design using UIkit

Pages:

- "/" to display every articles
- "/article/:id" to display one article
- "/category/:id" display articles depending on the category

## Getting started

Use our `create-strapi-starter` CLI to create your project.

```sh
# Using Yarn
yarn create strapi-starter my-project next-blog

# Or using NPM
npx create-strapi-starter my-project next-blog
```

The CLI will create a monorepo, install dependencies, and run your project automatically.

The Next frontend server will run here => [http://localhost:3000](http://localhost:3000)

The Strapi backend server will run here => [http://localhost:1337](http://localhost:1337)

## Deploying to production

You will need to deploy the `frontend` and `backend` projects separately. Here are the docs to deploy each one:

- [Deploy Strapi](https://strapi.io/documentation/developer-docs/latest/setup-deployment-guides/deployment.html#hosting-provider-guides)
- [Deploy Next](https://nextjs.org/docs/deployment)

Don't forget to setup the environment variables on your production app:

For the frontend the following environment variable is required:

- `NEXT_PUBLIC_STRAPI_API_URL`: URL of your Strapi backend, without trailing slash

Enjoy this starter!


================================================
FILE: packages/starters/next-blog/package.json
================================================
{
  "name": "@strapi/starter-next-blog",
  "version": "1.0.4",
  "description": "Strapi blog starter with Next.js",
  "keywords": [
    "strapi",
    "starter",
    "nextjs",
    "blog"
  ],
  "homepage": "https://github.com/strapi/starters-and-templates/tree/main/packages/starters/next-blog#readme",
  "bugs": {
    "url": "https://github.com/strapi/starters-and-templates/issues"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/strapi/starters-and-templates.git"
  },
  "license": "MIT",
  "author": {
    "name": "Strapi team",
    "email": "hi@strapi.io",
    "url": "https://strapi.io"
  },
  "maintainers": [
    {
      "name": "Strapi team",
      "email": "hi@strapi.io",
      "url": "https://strapi.io"
    }
  ]
}


================================================
FILE: packages/starters/next-blog/starter/.eslintrc
================================================
{
  "extends": [
    "next",
    "prettier"
  ],
  "plugins": [
    "prettier"
  ],
  "rules": {
    "prettier/prettier": "error"
  }
}


================================================
FILE: packages/starters/next-blog/starter/.prettierrc
================================================
{
  "printWidth": 80,
  "singleQuote": false,
  "trailingComma": "es5",
  "semi": false,
  "tabWidth": 2
}

================================================
FILE: packages/starters/next-blog/starter/assets/css/style.css
================================================
a {
  text-decoration: none;
}

h1 {
  font-family: Staatliches;
  font-size: 120px;
}

#category {
  font-family: Staatliches;
  font-weight: 500;
}

#title {
  letter-spacing: 0.4px;
  font-size: 22px;
  font-size: 1.375rem;
  line-height: 1.13636;
}

#banner {
  margin: 20px;
  height: 800px;
}

#editor {
  font-size: 16px;
  font-size: 1rem;
  line-height: 1.75;
}

.uk-navbar-container {
  background: #fff !important;
  font-family: Staatliches;
}

img:hover {
  opacity: 1;
  transition: opacity 0.25s cubic-bezier(0.39, 0.575, 0.565, 1);
}


================================================
FILE: packages/starters/next-blog/starter/components/articles.js
================================================
import React from "react"
import Card from "./card"

const Articles = ({ articles }) => {
  const leftArticlesCount = Math.ceil(articles.length / 5)
  const leftArticles = articles.slice(0, leftArticlesCount)
  const rightArticles = articles.slice(leftArticlesCount, articles.length)

  return (
    <div>
      <div className="uk-child-width-1-2@s" data-uk-grid="true">
        <div>
          {leftArticles.map((article, i) => {
            return (
              <Card
                article={article}
                key={`article__left__${article.attributes.slug}`}
              />
            )
          })}
        </div>
        <div>
          <div className="uk-child-width-1-2@m uk-grid-match" data-uk-grid>
            {rightArticles.map((article, i) => {
              return (
                <Card
                  article={article}
                  key={`article__left__${article.attributes.slug}`}
                />
              )
            })}
          </div>
        </div>
      </div>
    </div>
  )
}

export default Articles


================================================
FILE: packages/starters/next-blog/starter/components/card.js
================================================
import React from "react"
import Link from "next/link"
import NextImage from "./image"

const Card = ({ article }) => {
  return (
    <Link href={`/article/${article.attributes.slug}`}>
      <a className="uk-link-reset">
        <div className="uk-card uk-card-muted">
          <div className="uk-card-media-top">
            <NextImage image={article.attributes.image} />
          </div>
          <div className="uk-card-body">
            <p id="category" className="uk-text-uppercase">
              {article.attributes.category.name}
            </p>
            <p id="title" className="uk-text-large">
              {article.attributes.title}
            </p>
          </div>
        </div>
      </a>
    </Link>
  )
}

export default Card


================================================
FILE: packages/starters/next-blog/starter/components/image.js
================================================
import { getStrapiMedia } from "../lib/media"
import NextImage from "next/image"

const Image = ({ image, style }) => {
  const { url, alternativeText, width, height } = image.data.attributes

  // const loader = () => {
  //   return getStrapiMedia(image)
  // }

  return (
    <NextImage
      // loader={loader}
      layout="responsive"
      width={width || "100%"}
      height={height || "100%"}
      objectFit="contain"
      src={getStrapiMedia(image)}
      alt={alternativeText || ""}
    />
  )
}

export default Image


================================================
FILE: packages/starters/next-blog/starter/components/layout.js
================================================
import Nav from "./nav"

const Layout = ({ children, categories, seo }) => (
  <>
    <Nav categories={categories} />
    {children}
  </>
)

export default Layout


================================================
FILE: packages/starters/next-blog/starter/components/nav.js
================================================
import React from "react"
import Link from "next/link"

const Nav = ({ categories }) => {
  return (
    <div>
      <nav className="uk-navbar-container" data-uk-navbar>
        <div className="uk-navbar-left">
          <ul className="uk-navbar-nav">
            <li>
              <Link href="/">
                <a>Strapi Blog</a>
              </Link>
            </li>
          </ul>
        </div>
        <div className="uk-navbar-right">
          <ul className="uk-navbar-nav">
            {categories.map((category) => {
              return (
                <li key={category.id}>
                  <Link href={`/category/${category.attributes.slug}`}>
                    <a className="uk-link-reset">{category.attributes.name}</a>
                  </Link>
                </li>
              )
            })}
          </ul>
        </div>
      </nav>
    </div>
  )
}

export default Nav


================================================
FILE: packages/starters/next-blog/starter/components/seo.js
================================================
import Head from "next/head"
import { useContext } from "react"
import { GlobalContext } from "../pages/_app"
import { getStrapiMedia } from "../lib/media"

const Seo = ({ seo }) => {
  const { defaultSeo, siteName } = useContext(GlobalContext)
  const seoWithDefaults = {
    ...defaultSeo,
    ...seo,
  }
  const fullSeo = {
    ...seoWithDefaults,
    // Add title suffix
    metaTitle: `${seoWithDefaults.metaTitle} | ${siteName}`,
    // Get full image URL
    shareImage: getStrapiMedia(seoWithDefaults.shareImage),
  }

  return (
    <Head>
      {fullSeo.metaTitle && (
        <>
          <title>{fullSeo.metaTitle}</title>
          <meta property="og:title" content={fullSeo.metaTitle} />
          <meta name="twitter:title" content={fullSeo.metaTitle} />
        </>
      )}
      {fullSeo.metaDescription && (
        <>
          <meta name="description" content={fullSeo.metaDescription} />
          <meta property="og:description" content={fullSeo.metaDescription} />
          <meta name="twitter:description" content={fullSeo.metaDescription} />
        </>
      )}
      {fullSeo.shareImage && (
        <>
          <meta property="og:image" content={fullSeo.shareImage} />
          <meta name="twitter:image" content={fullSeo.shareImage} />
          <meta name="image" content={fullSeo.shareImage} />
        </>
      )}
      {fullSeo.article && <meta property="og:type" content="article" />}
      <meta name="twitter:card" content="summary_large_image" />
    </Head>
  )
}

export default Seo


================================================
FILE: packages/starters/next-blog/starter/lib/api.js
================================================
import qs from "qs"

/**
 * Get full Strapi URL from path
 * @param {string} path Path of the URL
 * @returns {string} Full Strapi URL
 */
export function getStrapiURL(path = "") {
  return `${
    process.env.NEXT_PUBLIC_STRAPI_API_URL || "http://localhost:1337"
  }${path}`
}

/**
 * Helper to make GET requests to Strapi API endpoints
 * @param {string} path Path of the API route
 * @param {Object} urlParamsObject URL params object, will be stringified
 * @param {Object} options Options passed to fetch
 * @returns Parsed API call response
 */
export async function fetchAPI(path, urlParamsObject = {}, options = {}) {
  // Merge default and user options
  const mergedOptions = {
    headers: {
      "Content-Type": "application/json",
    },
    ...options,
  }

  // Build request URL
  const queryString = qs.stringify(urlParamsObject)
  const requestUrl = `${getStrapiURL(
    `/api${path}${queryString ? `?${queryString}` : ""}`
  )}`

  // Trigger API call
  const response = await fetch(requestUrl, mergedOptions)

  // Handle response
  if (!response.ok) {
    console.error(response.statusText)
    throw new Error(`An error occurred please try again`)
  }
  const data = await response.json()
  return data
}


================================================
FILE: packages/starters/next-blog/starter/lib/media.js
================================================
import { getStrapiURL } from "./api"

export function getStrapiMedia(media) {
  const { url } = media.data.attributes
  const imageUrl = url.startsWith("/") ? getStrapiURL(url) : url
  return imageUrl
}


================================================
FILE: packages/starters/next-blog/starter/next.config.js
================================================
/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  images: {
    loader: "default",
    domains: ["localhost"],
  },
}

module.exports = nextConfig


================================================
FILE: packages/starters/next-blog/starter/package.json
================================================
{
  "name": "my-next-blog",
  "version": "1.0.3",
  "private": true,
  "scripts": {
    "develop": "next dev",
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "deploy": "next build && next export",
    "lint": "next lint",
    "lint:fix": "next lint --fix"
  },
  "dependencies": {
    "moment": "^2.24.0",
    "next": "^11.0.0",
    "qs": "^6.10.1",
    "react": "17.0.0",
    "react-dom": "17.0.0",
    "react-markdown": "^4.2.2",
    "react-moment": "^0.9.6"
  },
  "license": "MIT",
  "devDependencies": {
    "eslint": "^7.30.0",
    "eslint-config-next": "^11.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^3.4.0",
    "prettier": "^2.3.1"
  }
}


================================================
FILE: packages/starters/next-blog/starter/pages/_app.js
================================================
import App from "next/app"
import Head from "next/head"
import "../assets/css/style.css"
import { createContext } from "react"
import { fetchAPI } from "../lib/api"
import { getStrapiMedia } from "../lib/media"

// Store Strapi Global object in context
export const GlobalContext = createContext({})

const MyApp = ({ Component, pageProps }) => {
  const { global } = pageProps

  return (
    <>
      <Head>
        <link
          rel="shortcut icon"
          href={getStrapiMedia(global.attributes.favicon)}
        />
      </Head>
      <GlobalContext.Provider value={global.attributes}>
        <Component {...pageProps} />
      </GlobalContext.Provider>
    </>
  )
}

// getInitialProps disables automatic static optimization for pages that don't
// have getStaticProps. So article, category and home pages still get SSG.
// Hopefully we can replace this with getStaticProps once this issue is fixed:
// https://github.com/vercel/next.js/discussions/10949
MyApp.getInitialProps = async (ctx) => {
  // Calls page's `getInitialProps` and fills `appProps.pageProps`
  const appProps = await App.getInitialProps(ctx)
  // Fetch global site settings from Strapi
  const globalRes = await fetchAPI("/global", {
    populate: {
      favicon: "*",
      defaultSeo: {
        populate: "*",
      },
    },
  })
  // Pass the data to our page via props
  return { ...appProps, pageProps: { global: globalRes.data } }
}

export default MyApp


================================================
FILE: packages/starters/next-blog/starter/pages/_document.js
================================================
import Document, { Html, Head, Main, NextScript } from "next/document"

class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head>
          {/* eslint-disable-next-line */}
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css?family=Staatliches"
          />
          <link
            rel="stylesheet"
            href="https://cdn.jsdelivr.net/npm/uikit@3.2.3/dist/css/uikit.min.css"
          />
          <script
            async
            src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.min.js"
          />
          <script
            async
            src="https://cdn.jsdelivr.net/npm/uikit@3.2.3/dist/js/uikit-icons.min.js"
          />
          <script
            async
            src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.js"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument


================================================
FILE: packages/starters/next-blog/starter/pages/article/[slug].js
================================================
import ReactMarkdown from "react-markdown"
import Moment from "react-moment"
import { fetchAPI } from "../../lib/api"
import Layout from "../../components/layout"
import NextImage from "../../components/image"
import Seo from "../../components/seo"
import { getStrapiMedia } from "../../lib/media"

const Article = ({ article, categories }) => {
  const imageUrl = getStrapiMedia(article.attributes.image)

  const seo = {
    metaTitle: article.attributes.title,
    metaDescription: article.attributes.description,
    shareImage: article.attributes.image,
    article: true,
  }

  return (
    <Layout categories={categories.data}>
      <Seo seo={seo} />
      <div
        id="banner"
        className="uk-height-medium uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light uk-padding uk-margin"
        data-src={imageUrl}
        data-srcset={imageUrl}
        data-uk-img
      >
        <h1>{article.attributes.title}</h1>
      </div>
      <div className="uk-section">
        <div className="uk-container uk-container-small">
          <ReactMarkdown
            source={article.attributes.content}
            escapeHtml={false}
          />
          <hr className="uk-divider-small" />
          <div className="uk-grid-small uk-flex-left" data-uk-grid="true">
            <div>
              {article.attributes.author.picture && (
                <NextImage image={article.attributes.author.picture} />
              )}
            </div>
            <div className="uk-width-expand">
              <p className="uk-margin-remove-bottom">
                By {article.attributes.author.name}
              </p>
              <p className="uk-text-meta uk-margin-remove-top">
                <Moment format="MMM Do YYYY">
                  {article.attributes.published_at}
                </Moment>
              </p>
            </div>
          </div>
        </div>
      </div>
    </Layout>
  )
}

export async function getStaticPaths() {
  const articlesRes = await fetchAPI("/articles", { fields: ["slug"] })

  return {
    paths: articlesRes.data.map((article) => ({
      params: {
        slug: article.attributes.slug,
      },
    })),
    fallback: false,
  }
}

export async function getStaticProps({ params }) {
  const articlesRes = await fetchAPI("/articles", {
    filters: {
      slug: params.slug,
    },
    populate: "*",
  })
  const categoriesRes = await fetchAPI("/categories")

  return {
    props: { article: articlesRes.data[0], categories: categoriesRes },
    revalidate: 1,
  }
}

export default Article


================================================
FILE: packages/starters/next-blog/starter/pages/category/[slug].js
================================================
import Articles from "../../components/articles"
import { fetchAPI } from "../../lib/api"
import Layout from "../../components/layout"
import Seo from "../../components/seo"

const Category = ({ category, categories }) => {
  const seo = {
    metaTitle: category.attributes.name,
    metaDescription: `All ${category.attributes.name} articles`,
  }

  return (
    <Layout categories={categories.data}>
      <Seo seo={seo} />
      <div className="uk-section">
        <div className="uk-container uk-container-large">
          <h1>{category.attributes.name}</h1>
          <Articles articles={category.attributes.articles.data} />
        </div>
      </div>
    </Layout>
  )
}

export async function getStaticPaths() {
  const categoriesRes = await fetchAPI("/categories", { fields: ["slug"] })

  return {
    paths: categoriesRes.data.map((category) => ({
      params: {
        slug: category.attributes.slug,
      },
    })),
    fallback: false,
  }
}

export async function getStaticProps({ params }) {
  const matchingCategories = await fetchAPI("/categories", {
    filters: { slug: params.slug },
    populate: {
      articles: {
        populate: "*",
      },
    },
  })
  const allCategories = await fetchAPI("/categories")

  return {
    props: {
      category: matchingCategories.data[0],
      categories: allCategories,
    },
    revalidate: 1,
  }
}

export default Category


================================================
FILE: packages/starters/next-blog/starter/pages/index.js
================================================
import React from "react"
import Articles from "../components/articles"
import Layout from "../components/layout"
import Seo from "../components/seo"
import { fetchAPI } from "../lib/api"

const Home = ({ articles, categories, homepage }) => {
  return (
    <Layout categories={categories}>
      <Seo seo={homepage.attributes.seo} />
      <div className="uk-section">
        <div className="uk-container uk-container-large">
          <h1>{homepage.attributes.hero.title}</h1>
          <Articles articles={articles} />
        </div>
      </div>
    </Layout>
  )
}

export async function getStaticProps() {
  // Run API calls in parallel
  const [articlesRes, categoriesRes, homepageRes] = await Promise.all([
    fetchAPI("/articles", { populate: "*" }),
    fetchAPI("/categories", { populate: "*" }),
    fetchAPI("/homepage", {
      populate: {
        hero: "*",
        seo: { populate: "*" },
      },
    }),
  ])

  return {
    props: {
      articles: articlesRes.data,
      categories: categoriesRes.data,
      homepage: homepageRes.data,
    },
    revalidate: 1,
  }
}

export default Home


================================================
FILE: packages/starters/next-blog/starter.json
================================================
{
  "template": {
    "name": "@strapi/template-blog",
    "version": "^1.0.0"
  }
}


================================================
FILE: packages/starters/next-corporate/README.md
================================================
# Strapi Starter Next Corporate Site

Next starter for creating a corporate site with Strapi.

[View the live demo](https://strapi-starter-next-corporate.vercel.app/) • [Read the blog post](https://strapi.io/blog/strapi-starter-next-corporate-site)

![screen-website](./screenshot.png)

This starter is designed for flexibility. Using it, you'll be able to manage your website content entirely in Strapi, and get a Next app automatically generated. Marketing teams will be able to create pages and design their layout without help from developers.

This starter features:

- Pages creation within Strapi, no code necessary
- Fully flexible page structure: design the pages you want using UI Sections
- 8 UI Sections out of the box: Hero, RichText, LargeVideo, Testimonials, Pricing, BottomActions, FeatureRows, FeatureColumns
- Easy to theme with Tailwind
- Static site generation with Next
- An integrated Preview Mode, to view your pages on a private URL before publishing them
- Content in multiple languages using i18n

This starter uses the [Strapi corporate template](https://github.com/strapi/strapi-template-corporate)

Check out all of our starters [here](https://strapi.io/starters)

## Getting started

Use our `create-strapi-starter` CLI to create your project.

```sh
# Using Yarn
yarn create strapi-starter my-site next-corporate

# Or using NPM
npx create-strapi-starter my-site next-corporate
```

The CLI will create a monorepo, install dependencies, and run your project automatically.

The Next frontend server will run here => [http://localhost:3000](http://localhost:3000)

The Strapi backend server will run here => [http://localhost:1337](http://localhost:1337)

## Preview Mode

You can turn preview mode on with a URL like this:

`http://localhost:3000/api/preview?secret=<preview-secret>&slug=<slug>`

`<preview-secret>` is the secret token defined in your .env config,
`<slug>` is the slug you entered in Strapi for your page.

While preview mode is on you can access `draft` pages just like you would `published` pages.

For example [http://localhost:3000/secret](http://localhost:3000/secret) would be available in preview mode.

A banner will remain under the navigation to let you know preview mode is on and it will also allow you to turn it off.

## Customize your corporate site

To edit this website, you'll need to run both the frontend and the backend in your development environment.

### Adding Sections

We have built sections for you, but you will likely want to add more to fit your needs. Follow these steps:

- Create a new component in Strapi in the "sections" category
- In the Content-Types Builder, open the Pages collection and check your new section on the `contentSections` field.
- Create a React component that takes a `data` prop in `/frontend/components/sections`
- To link your Strapi section to this React component, open `/frontend/components/sections.js`, and add an entry to the `sectionComponents` object.

### Custom theme

We use Tailwind CSS for styling. To modify your page's look, you can edit the theme in `/front/tailwind.config.js`. Read the [Tailwind docs](https://v1.tailwindcss.com/docs/theme) to view all the changes you can make. For example, you can change the primary color like this:

```js
const { colors } = require(`tailwindcss/defaultTheme`);

module.exports = {
  theme: {
    extend: {
      colors: {
        primary: colors.green,
      },
    },
  },
};
```

## Deploying to production

You will need to deploy the `frontend` and `backend` projects separately. Here are the docs to deploy each one:

- [Deploy Strapi](https://strapi.io/documentation/v3.x/admin-panel/deploy.html#deployment)
- [Deploy Next.js](https://nextjs.org/docs/deployment)

Don't forget to set up your environment variables on your production apps.

Here are the required ones for the frontend:

- `NEXT_PUBLIC_STRAPI_API_URL`: URL of your Strapi backend, without trailing slash
- `PREVIEW_SECRET`: a random string used to protect your preview pages

And for the backend:

- `FRONTEND_URL`: URL of your frontend, without trailing slash
- `FRONTEND_PREVIEW_SECRET`: token of Next.js preview mode defined on the frontend

Have fun using this starter!


================================================
FILE: packages/starters/next-corporate/package.json
================================================
{
  "name": "@strapi/starter-next-corporate",
  "version": "1.0.4",
  "description": "Strapi corporate starter with Next.js",
  "keywords": [
    "strapi",
    "starter",
    "nextjs",
    "corporate"
  ],
  "homepage": "https://github.com/strapi/starters-and-templates/tree/main/packages/starters/next-corporate#readme",
  "bugs": {
    "url": "https://github.com/strapi/starters-and-templates/issues"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/strapi/starters-and-templates.git"
  },
  "license": "MIT",
  "author": {
    "name": "Strapi team",
    "email": "hi@strapi.io",
    "url": "https://strapi.io"
  },
  "maintainers": [
    {
      "name": "Strapi team",
      "email": "hi@strapi.io",
      "url": "https://strapi.io"
    }
  ]
}


================================================
FILE: packages/starters/next-corporate/starter/.eslintrc
================================================
{
  "extends": [
    "next",
    "prettier"
  ],
  "plugins": [
    "prettier"
  ],
  "rules": {
    "prettier/prettier": [
      "error",
      {
        "printWidth": 80,
        "singleQuote": false,
        "trailingComma": "es5",
        "semi": false,
        "tabWidth": 2
      }
    ]
  }
}


================================================
FILE: packages/starters/next-corporate/starter/.gitignore
================================================
.vscode

# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local


================================================
FILE: packages/starters/next-corporate/starter/README.md
================================================
# Next frontend

This frontend relies on Next's [Static Generation](https://nextjs.org/docs/basic-features/pages) using [Strapi](https://strapi.io/) as the data source. Make sure Strapi is running in parallel when you run this app.

## Routes

**pages/[[...slug]].js**

This file generates all the app's route. First, it fetches all the pages entries in Strapi. Then, it creates one route per page found. These routes can look like this:

* yoursite.com
* yoursite.com/page
* yoursite.com/page/nested/route

Notice that the path of the page can be several layers deep, or it can be the root of the site. This is possible thanks to Next's [optional catch-all routes](https://nextjs.org/docs/routing/dynamic-routes#optional-catch-all-routes).

To see how to build these nested routes, see [the Strapi project's Readme](../backend/README.md).

## Available Scripts

In the project directory, you can run:

**`yarn dev`**

Runs the app in the development mode.  
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

The page will reload if you make edits.  
You will also see any errors in the console.

**`yarn build`**

Builds the app for production to the `.next` folder.<br>
It correctly bundles React in production mode and optimizes the build for the best performance.

**`yarn start`**

Starts the application in production mode.
The application should be compiled with \`next build\` first.

See the section in Next docs about [deployment](https://nextjs.org/docs/deployment) for more
information.


================================================
FILE: packages/starters/next-corporate/starter/components/elements/button-link.js
================================================
import classNames from "classnames"
import PropTypes from "prop-types"
import { buttonLinkPropTypes } from "utils/types"
import CustomLink from "./custom-link"

const ButtonContent = ({ button, appearance, compact }) => {
  return (
    <div
      className={classNames(
        // Common classes
        "block w-full lg:w-auto text-center uppercase tracking-wide font-semibold text-base md:text-sm border-2 rounded-md",
        // Full-size button
        {
          "px-8 py-4": compact === false,
        },
        // Compact button
        {
          "px-6 py-2": compact === true,
        },
        // Specific to when the button is fully dark
        {
          "bg-primary-600 text-white border-primary-600": appearance === "dark",
        },
        // Specific to when the button is dark outlines
        {
          "text-primary-600 border-primary-600": appearance === "dark-outline",
        },
        // Specific to when the button is fully white
        {
          "bg-white text-primary-600 border-white": appearance === "white",
        },
        // Specific to when the button is white outlines
        {
          "text-white border-white": appearance === "white-outline",
        }
      )}
    >
      {button.text}
    </div>
  )
}

const ButtonLink = ({ button, appearance, compact = false }) => {
  return (
    <CustomLink link={button}>
      <ButtonContent
        button={button}
        appearance={appearance}
        compact={compact}
      />
    </CustomLink>
  )
}

ButtonLink.propTypes = {
  button: buttonLinkPropTypes,
  appearance: PropTypes.oneOf([
    "dark",
    "white-outline",
    "white",
    "dark-outline",
  ]),
  compact: PropTypes.bool,
}

export default ButtonLink


================================================
FILE: packages/starters/next-corporate/starter/components/elements/button.js
================================================
import classNames from "classnames"
import PropTypes from "prop-types"
import { buttonLinkPropTypes } from "utils/types"
import Loader from "./loader"

const Button = ({
  button,
  appearance,
  compact = false,
  handleClick,
  loading = false,
  type,
}) => {
  return (
    <button link={button} onClick={handleClick} type={type}>
      <div
        className={classNames(
          // Common classes
          "flex w-full justify-center lg:w-auto text-center uppercase tracking-wide font-semibold text-base md:text-sm border-2 rounded-md",
          // Full-size button
          {
            "px-8 py-4": compact === false,
          },
          // Compact button
          {
            "px-6 py-2": compact === true,
          },
          // Specific to when the button is fully dark
          {
            "bg-primary-600 text-white border-primary-600":
              appearance === "dark",
          },
          // Specific to when the button is dark outlines
          {
            "text-primary-600 border-primary-600":
              appearance === "dark-outline",
          },
          // Specific to when the button is fully white
          {
            "bg-white text-primary-600 border-white": appearance === "white",
          },
          // Specific to when the button is white outlines
          {
            "text-white border-white": appearance === "white-outline",
          }
        )}
      >
        {loading && <Loader />}
        {button.text}
      </div>
    </button>
  )
}

Button.propTypes = {
  button: buttonLinkPropTypes,
  appearance: PropTypes.oneOf([
    "dark",
    "white-outline",
    "white",
    "dark-outline",
  ]),
  compact: PropTypes.bool,
}

export default Button


================================================
FILE: packages/starters/next-corporate/starter/components/elements/custom-link.js
================================================
import Link from "next/link"
import PropTypes from "prop-types"
import { linkPropTypes } from "utils/types"

const CustomLink = ({ link, children }) => {
  const isInternalLink = link.url.startsWith("/")

  // For internal links, use the Next.js Link component
  if (isInternalLink) {
    return (
      <Link href={link.url}>
        <a>{children}</a>
      </Link>
    )
  }

  // Plain <a> tags for external links
  if (link.newTab) {
    return (
      <a href={link.url} target="_blank" rel="noopener noreferrer">
        {children}
      </a>
    )
  }

  return (
    <a href={link.url} target="_self">
      {children}
    </a>
  )
}

CustomLink.propTypes = {
  link: linkPropTypes,
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]).isRequired,
}

export default CustomLink


================================================
FILE: packages/starters/next-corporate/starter/components/elements/footer.js
================================================
import PropTypes from "prop-types"
import { linkPropTypes, mediaPropTypes } from "utils/types"
import NextImage from "./image"
import CustomLink from "./custom-link"

const Footer = ({ footer }) => {
  return (
    <footer className="pt-12 bg-gray-100">
      <div className="container flex flex-col lg:flex-row lg:justify-between">
        <div>
          {footer.logo && (
            <NextImage width="120" height="33" media={footer.logo} />
          )}
        </div>
        <nav className="flex flex-wrap flex-row lg:gap-20 items-start lg:justify-end mb-10">
          {footer.columns.map((footerColumn) => (
            <div
              key={footerColumn.id}
              className="mt-10 lg:mt-0 w-6/12 lg:w-auto"
            >
              <p className="uppercase tracking-wide font-semibold">
                {footerColumn.title}
              </p>
              <ul className="mt-2">
                {footerColumn.links.map((link) => (
                  <li
                    key={link.id}
                    className="text-gray-700 py-1 px-1 -mx-1 hover:text-gray-900"
                  >
                    <CustomLink link={link}>{link.text}</CustomLink>
                  </li>
                ))}
              </ul>
            </div>
          ))}
        </nav>
      </div>
      <div className="text-sm bg-gray-200 py-6 text-gray-700">
        <div className="container">{footer.smallText}</div>
      </div>
    </footer>
  )
}

Footer.propTypes = {
  footer: PropTypes.shape({
    logo: mediaPropTypes.isRequired,
    columns: PropTypes.arrayOf(
      PropTypes.shape({
        id: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
          .isRequired,
        title: PropTypes.string.isRequired,
        links: PropTypes.arrayOf(linkPropTypes),
      })
    ),
    smallText: PropTypes.string.isRequired,
  }),
}

export default Footer


================================================
FILE: packages/starters/next-corporate/starter/components/elements/image.js
================================================
import { getStrapiMedia } from "utils/media"
import Image from "next/image"
import PropTypes from "prop-types"
import { mediaPropTypes } from "utils/types"

const NextImage = ({ media, ...props }) => {
  const { url, alternativeText, width, height } = media.data.attributes

  const loader = ({ src, width }) => {
    return getStrapiMedia(src)
  }

  // The image has a fixed width and height
  if (props.width && props.height) {
    return (
      <Image loader={loader} src={url} alt={alternativeText || ""} {...props} />
    )
  }

  // The image is responsive
  return (
    <Image
      loader={loader}
      layout="responsive"
      width={width || "100%"}
      height={height || "100%"}
      objectFit="contain"
      src={url}
      alt={alternativeText || ""}
    />
  )
}

Image.propTypes = {
  media: mediaPropTypes.isRequired,
  className: PropTypes.string,
}

export default NextImage


================================================
FILE: packages/starters/next-corporate/starter/components/elements/loader.js
================================================
import React from "react"

const Loader = () => {
  return (
    <svg
      viewBox="0 0 38 38"
      className="animate-spin h-5 w-5 stroke-current text-black-600 mr-2"
      xmlns="http://www.w3.org/2000/svg"
    >
      <g fill="none" fillRule="evenodd">
        <g transform="translate(1 1)" strokeWidth="2">
          <circle strokeOpacity=".5" cx="18" cy="18" r="18" />
          <path d="M36 18c0-9.94-8.06-18-18-18">
            <animateTransform
              attributeName="transform"
              type="rotate"
              from="0 18 18"
              to="360 18 18"
              dur="1s"
              repeatCount="indefinite"
            />
          </path>
        </g>
      </g>
    </svg>
  )
}

export default Loader


================================================
FILE: packages/starters/next-corporate/starter/components/elements/mobile-nav-menu.js
================================================
import PropTypes from "prop-types"
import { MdClose, MdChevronRight } from "react-icons/md"
import { mediaPropTypes, linkPropTypes, buttonLinkPropTypes } from "utils/types"
import { useLockBodyScroll } from "utils/hooks"
import { getButtonAppearance } from "utils/button"
import ButtonLink from "./button-link"
import NextImage from "./image"
import CustomLink from "./custom-link"

const MobileNavMenu = ({ navbar, closeSelf }) => {
  // Prevent window scroll while mobile nav menu is open
  useLockBodyScroll()

  return (
    <div className="w-screen h-screen fixed top-0 left-0 overflow-y-scroll bg-white z-10 pb-6">
      <div className="container h-full flex flex-col justify-between">
        {/* Top section */}
        <div className="flex flex-row justify-between py-2 items-center">
          {/* Company logo */}
          <NextImage width="120" height="33" media={navbar.logo} />
          {/* Close button */}
          <button onClick={closeSelf} className="py-1 px-1">
            <MdClose className="h-8 w-auto" />
          </button>
        </div>
        {/* Bottom section */}
        <div className="flex flex-col justify-end w-9/12 mx-auto">
          <ul className="flex flex-col list-none gap-6 items-baseline text-xl mb-10">
            {navbar.links.map((navLink) => (
              <li key={navLink.id} className="block w-full">
                <CustomLink link={navLink}>
                  <div className="hover:text-gray-900 py-6 flex flex-row justify-between items-center">
                    <span>{navLink.text}</span>
                    <MdChevronRight className="h-8 w-auto" />
                  </div>
                </CustomLink>
              </li>
            ))}
          </ul>
          <ButtonLink
            button={navbar.button}
            appearance={getButtonAppearance(navbar.button.type, "light")}
          />
        </div>
      </div>
    </div>
  )
}

MobileNavMenu.propTypes = {
  navbar: PropTypes.shape({
    logo: mediaPropTypes,
    links: PropTypes.arrayOf(linkPropTypes),
    button: buttonLinkPropTypes,
  }),
  closeSelf: PropTypes.func,
}

export default MobileNavMenu


================================================
FILE: packages/starters/next-corporate/starter/components/elements/navbar.js
================================================
import { useState } from "react"
import PropTypes from "prop-types"
import Link from "next/link"
import { useRouter } from "next/router"

import { getButtonAppearance } from "utils/button"
import { mediaPropTypes, linkPropTypes, buttonLinkPropTypes } from "utils/types"
import { MdMenu } from "react-icons/md"
import MobileNavMenu from "./mobile-nav-menu"
import ButtonLink from "./button-link"
import NextImage from "./image"
import CustomLink from "./custom-link"
import LocaleSwitch from "../locale-switch"

const Navbar = ({ navbar, pageContext }) => {
  const router = useRouter()
  const [mobileMenuIsShown, setMobileMenuIsShown] = useState(false)

  return (
    <>
      {/* The actual navbar */}
      <nav className="border-gray-200 border-b-2 py-6 sm:py-2">
        <div className="container flex flex-row items-center justify-between">
          {/* Content aligned to the left */}
          <div className="flex flex-row items-center">
            <Link href="/">
              <a className="h-8 w-32">
                <NextImage width="120" height="33" media={navbar.logo} />
              </a>
            </Link>
            {/* List of links on desktop */}
            <ul className="hidden list-none md:flex flex-row gap-4 items-baseline ml-10">
              {navbar.links.map((navLink) => (
                <li key={navLink.id}>
                  <CustomLink link={navLink} locale={router.locale}>
                    <div className="hover:text-gray-900 px-2 py-1">
                      {navLink.text}
                    </div>
                  </CustomLink>
                </li>
              ))}
            </ul>
          </div>
          <div className="flex">
            {/* Locale Switch Mobile */}
            {pageContext.localizedPaths && (
              <div className="md:hidden">
                <LocaleSwitch pageContext={pageContext} />
              </div>
            )}
            {/* Hamburger menu on mobile */}
            <button
              onClick={() => setMobileMenuIsShown(true)}
              className="p-1 block md:hidden"
            >
              <MdMenu className="h-8 w-auto" />
            </button>
            {/* CTA button on desktop */}
            {navbar.button && (
              <div className="hidden md:block">
                <ButtonLink
                  button={navbar.button}
                  appearance={getButtonAppearance(navbar.button.type, "light")}
                  compact
                />
              </div>
            )}
            {/* Locale Switch Desktop */}
            {pageContext.localizedPaths && (
              <div className="hidden md:block">
                <LocaleSwitch pageContext={pageContext} />
              </div>
            )}
          </div>
        </div>
      </nav>

      {/* Mobile navigation menu panel */}
      {mobileMenuIsShown && (
        <MobileNavMenu
          navbar={navbar}
          closeSelf={() => setMobileMenuIsShown(false)}
        />
      )}
    </>
  )
}

Navbar.propTypes = {
  navbar: PropTypes.shape({
    logo: PropTypes.shape({
      image: mediaPropTypes,
      url: PropTypes.string,
    }),
    links: PropTypes.arrayOf(linkPropTypes),
    button: buttonLinkPropTypes,
  }),
  initialLocale: PropTypes.string,
}

export default Navbar


================================================
FILE: packages/starters/next-corporate/starter/components/elements/notification-banner.js
================================================
import Markdown from "react-markdown"
import classNames from "classnames"
import { MdClose } from "react-icons/md"

const NotificationBanner = ({ data: { text, type }, closeSelf }) => {
  return (
    <div
      className={classNames(
        // Common classes
        "text-white px-2 py-2",
        {
          // Apply theme based on notification type
          "bg-blue-600": type === "info",
          "bg-orange-600": type === "warning",
          "bg-red-600": type === "alert",
        }
      )}
    >
      <div className="container flex flex-row justify-between items-center ">
        <div className="rich-text-banner flex-1">
          <Markdown>{text}</Markdown>
        </div>
        <button onClick={closeSelf} className="px-1 py-1 flex-shrink-0">
          <MdClose className="h-6 w-auto" color="#fff" />
        </button>
      </div>
    </div>
  )
}

export default NotificationBanner


================================================
FILE: packages/starters/next-corporate/starter/components/elements/seo.js
================================================
import { NextSeo } from "next-seo"
import PropTypes from "prop-types"
import { getStrapiMedia } from "utils/media"
import { mediaPropTypes } from "utils/types"

const Seo = ({ metadata }) => {
  // Prevent errors if no metadata was set
  if (!metadata) return null

  return (
    <NextSeo
      title={metadata.metaTitle}
      description={metadata.metaDescription}
      openGraph={{
        // Title and description are mandatory
        title: metadata.metaTitle,
        description: metadata.metaDescription,
        // Only include OG image if we have it
        // Careful: if you disable image optimization in Strapi, this will break
        ...(metadata.shareImage && {
          images: Object.values(
            metadata.shareImage.data.attributes.formats
          ).map((image) => {
            return {
              url: getStrapiMedia(image.url),
              width: image.width,
              height: image.height,
            }
          }),
        }),
      }}
      // Only included Twitter data if we have it
      twitter={{
        ...(metadata.twitterCardType && { cardType: metadata.twitterCardType }),
        // Handle is the twitter username of the content creator
        ...(metadata.twitterUsername && { handle: metadata.twitterUsername }),
      }}
    />
  )
}

Seo.propTypes = {
  metadata: PropTypes.shape({
    metaTitle: PropTypes.string.isRequired,
    metaDescription: PropTypes.string.isRequired,
    shareImage: mediaPropTypes,
    twitterCardType: PropTypes.string,
    twitterUsername: PropTypes.string,
  }),
}

export default Seo


================================================
FILE: packages/starters/next-corporate/starter/components/elements/video.js
================================================
import PropTypes from "prop-types"
import { getStrapiMedia } from "utils/media"
import { mediaPropTypes } from "utils/types"

const Video = ({
  media,
  poster,
  className,
  controls = true,
  autoPlay = false,
}) => {
  const fullVideoUrl = getStrapiMedia(media.url)
  const fullPosterUrl = getStrapiMedia(poster?.url)

  return (
    <video
      className={className}
      poster={fullPosterUrl}
      controls={controls}
      autoPlay={autoPlay}
    >
      <source src={fullVideoUrl} type={media.mime} />
    </video>
  )
}

Video.propTypes = {
  media: mediaPropTypes.isRequired,
  poster: mediaPropTypes,
  className: PropTypes.string,
  controls: PropTypes.bool,
  autoPlay: PropTypes.bool,
}

export default Video


================================================
FILE: packages/starters/next-corporate/starter/components/icons/world.js
================================================
import React from "react"

const WorldIcon = () => {
  return (
    <div className="w-4 h-4 mr-2 ">
      <svg
        className="fill-current text-primary-600"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 490 490"
      >
        <path d="M490 245C490 109.915 380.089 0 245 0S0 109.915 0 245c0 135.085 109.911 245 245 245s245-109.915 245-245zM263.846 380.696c11.096.548 21.781 1.361 31.996 2.43-11.076 17.053-22.316 31.807-31.996 43.387v-45.817zm0-38.711v-81.591h80.86c-4.208 31.012-14.804 60.245-27.914 86.267-16.352-2.171-34.078-3.82-52.946-4.676zm0-119.946v-80.36c19.587-.4 39.945-1.888 60.783-4.753 11.631 24.771 20.063 53.417 21.66 85.113h-82.443zm0-118.966v-51.29c11.357 11.26 26.119 27.703 40.158 48.699-13.635 1.373-27.106 2.33-40.158 2.591zm-37.692-.673c-16.318-.805-31.757-2.205-46.078-4.046 16.965-24.888 34.774-43.291 46.078-53.774v57.82zm0 38.825v80.815h-89.986c1.658-32.662 10.587-62.206 22.834-87.553a619.247 619.247 0 0067.152 6.738zm0 119.17v81.003c-19.581.4-39.939 1.851-60.768 4.712-12.983-25.886-23.46-54.922-27.638-85.716h88.406zm0 119.628v55.272c-11.131-12.632-25.648-30.714-39.886-52.708 13.541-1.356 26.922-2.304 39.886-2.564zm111.038 8.844c18.508 3.238 34.063 6.762 45.881 9.837-23.907 21.36-52.737 37.222-84.641 45.727 12.172-15.038 25.844-33.717 38.76-55.564zm18.791-35.812c12.927-28.029 23.045-59.309 26.832-92.66h68.71c-2.959 39.704-17.194 76.236-39.557 106.571-10.45-3.268-29.932-8.767-55.985-13.911zm28.019-131.016c-1.427-34.133-9.499-64.953-20.987-91.989a444.866 444.866 0 0044.872-12.453c23.245 29.466 38.694 65.279 43.062 104.441h-66.947zM345.135 94.558a341.42 341.42 0 00-30.991-44.13c23.562 8.348 45.226 20.672 64.008 36.41-11.037 3.104-22.05 5.585-33.017 7.72zm-206.091-2.866c-9.782-1.944-18.654-3.915-26.181-5.776a207.72 207.72 0 0152.147-31.524c-8.691 10.813-17.559 23.385-25.966 37.3zM120.62 127.3c-12.104 27.687-20.691 59.444-22.168 94.739H39.051c4.376-39.236 19.87-75.112 43.187-104.609 8.84 2.654 21.899 6.232 38.382 9.87zM99.638 260.395c3.796 33.422 13.951 64.76 26.918 92.833-16.081 3.579-32.278 8.175-48.492 13.78-22.381-30.344-36.629-66.891-39.589-106.614h61.163zm45.423 128.115c12.212 20.697 25.116 38.605 36.803 53.259-28.391-9.075-54.009-24.2-75.627-43.689 12.978-3.859 25.933-7.066 38.824-9.57z" />
      </svg>
    </div>
  )
}

export default WorldIcon


================================================
FILE: packages/starters/next-corporate/starter/components/layout.js
================================================
import { useState } from "react"
import Navbar from "./elements/navbar"
import Footer from "./elements/footer"
import NotificationBanner from "./elements/notification-banner"

const Layout = ({ children, global, pageContext }) => {
  const { navbar, footer, notificationBanner } = global.attributes

  const [bannerIsShown, setBannerIsShown] = useState(true)
  return (
    <div className="flex flex-col justify-between min-h-screen">
      {/* Aligned to the top */}
      <div className="flex-1">
        {notificationBanner && bannerIsShown && (
          <NotificationBanner
            data={notificationBanner}
            closeSelf={() => setBannerIsShown(false)}
          />
        )}
        <Navbar navbar={navbar} pageContext={pageContext} />
        <div>{children}</div>
      </div>
      {/* Aligned to the bottom */}
      <Footer footer={footer} />
    </div>
  )
}

export default Layout


================================================
FILE: packages/starters/next-corporate/starter/components/locale-switch.js
================================================
import { useEffect, useState, useRef } from "react"
import { useRouter } from "next/router"
import PropTypes from "prop-types"
import Link from "next/link"

import Cookies from "js-cookie"
import { MdExpandMore } from "react-icons/md"
import WorldIcon from "./icons/world"

import { useOnClickOutside } from "../utils/hooks"

const LocaleSwitch = ({ pageContext }) => {
  const isMounted = useRef(false)
  const select = useRef()
  const router = useRouter()
  const [locale, setLocale] = useState()
  const [showing, setShowing] = useState(false)

  const handleLocaleChange = async (selectedLocale) => {
    // Persist the user's language preference
    // https://nextjs.org/docs/advanced-features/i18n-routing#leveraging-the-next_locale-cookie
    Cookies.set("NEXT_LOCALE", selectedLocale)
    setLocale(selectedLocale)
  }

  const handleLocaleChangeRef = useRef(handleLocaleChange)
  useOnClickOutside(select, () => setShowing(false))

  useEffect(() => {
    const localeCookie = Cookies.get("NEXT_LOCALE")
    if (!localeCookie) {
      handleLocaleChangeRef.current(router.locale)
    }

    const checkLocaleMismatch = async () => {
      if (
        !isMounted.current &&
        localeCookie &&
        localeCookie !== pageContext.locale
      ) {
        // Redirect to locale page if locale mismatch
        const localePage = getLocalizedPage(localeCookie, pageContext)

        router.push(
          `${localizePath({ ...pageContext, ...localePage })}`,
          `${localizePath({ ...pageContext, ...localePage })}`,
          { locale: localePage.locale }
        )
      }
      setShowing(false)
    }

    setLocale(localeCookie || router.locale)
    checkLocaleMismatch()

    return () => {
      isMounted.current = true
    }
  }, [locale, router, pageContext])

  return (
    <div ref={select} className="relative ml-4 ">
      <button
        type="button"
        className="hover:bg-primary-50 hover:text-primary-600 focus:bg-primary-50 focus:text-primary-600 focus:outline-none flex items-center justify-between px-2 py-2 cursor-pointer h-full rounded-md w-20"
        onClick={() => setShowing(!showing)}
      >
        <WorldIcon />
        <span className="capitalize">{locale}</span>
        <MdExpandMore className="ml-1 text-primary-600" />
      </button>
      <div
        className={`w-full bg-white p-1 mt-1 shadow-lg rounded-md ${
          showing ? "absolute" : "hidden"
        }`}
      >
        {pageContext.localizedPaths &&
          pageContext.localizedPaths.map(({ href, locale }) => {
            return (
              <Link
                href={href}
                key={locale}
                locale={locale}
                role="option"
                passHref
              >
                <p
                  onClick={() => handleLocaleChange(locale)}
                  className="capitalize hover:bg-primary-50 hover:text-primary-600  cursor-pointer p-2 rounded-md text-center hover:text-primary-600"
                >
                  {locale}
                </p>
              </Link>
            )
          })}
      </div>
    </div>
  )
}

LocaleSwitch.propTypes = {
  initialLocale: PropTypes.string,
}

export default LocaleSwitch


================================================
FILE: packages/starters/next-corporate/starter/components/sections/bottom-actions.js
================================================
import ButtonLink from "@/components/elements/button-link"
import { getButtonAppearance } from "utils/button"

const BottomActions = ({ data }) => {
  return (
    <section className="bg-primary-800 py-20 text-center">
      <h2 className="title text-white mb-10">{data.title}</h2>
      {/* Buttons row */}
      <div className="container flex flex-row justify-center flex-wrap gap-4">
        {data.buttons.map((button) => (
          <ButtonLink
            button={button}
            appearance={getButtonAppearance(button.type, "dark")}
            key={button.id}
          />
        ))}
      </div>
    </section>
  )
}

export default BottomActions


================================================
FILE: packages/starters/next-corporate/starter/components/sections/feature-columns-group.js
================================================
import NextImage from "../elements/image"

const FeatureColumnsGroup = ({ data }) => {
  return (
    <div className="container flex flex-col lg:flex-row lg:flex-wrap gap-12 align-top py-12">
      {data.features.map((feature) => (
        <div className="flex-1 text-lg" key={feature.id}>
          <div className="w-10 h-10">
            <NextImage media={feature.icon} />
          </div>
          <h3 className="font-bold mt-4 mb-4">{feature.title}</h3>
          <p>{feature.description}</p>
        </div>
      ))}
    </div>
  )
}

export default FeatureColumnsGroup


================================================
FILE: packages/starters/next-corporate/starter/components/sections/feature-rows-group.js
================================================
import classNames from "classnames"
import NextImage from "../elements/image"
import Video from "../elements/video"
import CustomLink from "../elements/custom-link"

const FeatureRowsGroup = ({ data }) => {
  return (
    <div className="container flex flex-col gap-12 py-12">
      {data.features.map((feature, index) => (
        <div
          className={classNames(
            // Common classes
            "flex flex-col justify-start md:justify-between md:items-center gap-10",
            {
              "lg:flex-row": index % 2 === 0,
              "lg:flex-row-reverse": index % 2 === 1,
            }
          )}
          key={feature.id}
        >
          {/* Text section */}
          <div className="w-full lg:w-6/12 lg:pr-6 text-lg">
            <h3 className="title">{feature.title}</h3>
            <p className="my-6">{feature.description}</p>
            <CustomLink link={feature.link}>
              <div className="text-blue-600 with-arrow hover:underline">
                {feature.link.text}
              </div>
            </CustomLink>
          </div>
          {/* Media section */}
          <div className="w-full sm:9/12 lg:w-4/12 max-h-full">
            {/* Images */}
            {feature.media.data.attributes.mime.startsWith("image") && (
              <div className="w-full h-auto">
                <NextImage media={feature.media} />
              </div>
            )}
            {/* Videos */}
            {feature.media.data.attributes.mime.startsWith("video") && (
              <Video
                media={feature.media}
                className="w-full h-auto"
                autoPlay
                controls={false}
              />
            )}
          </div>
        </div>
      ))}
    </div>
  )
}

export default FeatureRowsGroup


================================================
FILE: packages/starters/next-corporate/starter/components/sections/hero.js
================================================
import Markdown from "react-markdown"
import { getButtonAppearance } from "utils/button"
import ButtonLink from "../elements/button-link"
import NextImage from "../elements/image"

const Hero = ({ data }) => {
  return (
    <main className="container flex flex-col md:flex-row items-center justify-between py-12">
      {/* Left column for content */}
      <div className="flex-1 sm:pr-8">
        {/* Hero section label */}
        <p className="uppercase tracking-wide font-semibold">{data.label}</p>
        {/* Big title */}
        <h1 className="title mt-2 sm:mt-0 mb-4 sm:mb-2">{data.title}</h1>
        {/* Description paragraph */}
        <p className="text-xl mb-6">{data.description}</p>
        {/* Buttons row */}
        <div className="flex flex-row flex-wrap gap-4">
          {data.buttons.map((button) => (
            <ButtonLink
              button={button}
              appearance={getButtonAppearance(button.type, "light")}
              key={button.id}
            />
          ))}
        </div>
        {/* Small rich text */}
        <div className="text-base md:text-sm mt-4 sm:mt-3 rich-text-hero">
          <Markdown>{data.smallTextWithLink}</Markdown>
        </div>
      </div>
      {/* Right column for the image */}
      <div className="flex-shrink-0 w-full md:w-6/12 mt-6 md:mt-0">
        <NextImage media={data.picture} />
      </div>
    </main>
  )
}

export default Hero


================================================
FILE: packages/starters/next-corporate/starter/components/sections/large-video.js
================================================
import Video from "../elements/video"

const LargeVideo = ({ data }) => {
  return (
    <section className="container flex flex-col align-middle text-center pt-12 pb-16">
      <h2 className="title mb-6">{data.title}</h2>
      <p className="text-lg mb-10">{data.description}</p>
      {/* Video wrapper */}
      <div className="w-full lg:w-9/12 mx-auto overflow-hidden shadow-2xl">
        <Video
          media={data.video}
          poster={data.poster}
          className="w-full max-h-full"
        />
      </div>
    </section>
  )
}

export default LargeVideo


================================================
FILE: packages/starters/next-corporate/starter/components/sections/lead-form.js
================================================
import { useState } from "react"
import { fetchAPI } from "utils/api"
import * as yup from "yup"
import { Formik, Form, Field } from "formik"
import Button from "../elements/button"

const LeadForm = ({ data }) => {
  const [loading, setLoading] = useState(false)

  const LeadSchema = yup.object().shape({
    email: yup.string().email().required(),
  })

  return (
    <div className="py-10 text-center">
      <h1 className="text-3xl mb-10 font-bold mb-2">{data.title}</h1>
      <div className="flex flex-col items-center">
        <Formik
          initialValues={{ email: "" }}
          validationSchema={LeadSchema}
          onSubmit={async (values, { setSubmitting, setErrors }) => {
            setLoading(true)

            try {
              setErrors({ api: null })
              await fetchAPI(
                "/lead-form-submissions",
                {},
                {
                  method: "POST",
                  body: JSON.stringify({
                    data: {
                      email: values.email,
                      location: data.location,
                    },
                  }),
                }
              )
            } catch (err) {
              setErrors({ api: err.message })
            }

            setLoading(false)
            setSubmitting(false)
          }}
        >
          {({ errors, touched, isSubmitting }) => (
            <div>
              <Form className="flex flex-col md:flex-row gap-4">
                <Field
                  className="text-base focus:outline-none py-4 md:py-0 px-4 border-2 rounded-md"
                  type="email"
                  name="email"
                  placeholder={data.emailPlaceholder}
                />
                <Button
                  type="submit"
                  button={data.submitButton}
                  disabled={isSubmitting}
                  loading={loading}
                />
              </Form>
              <p className="text-red-500 h-12 text-sm mt-1 ml-2 text-left">
                {(errors.email && touched.email && errors.email) || errors.api}
              </p>
            </div>
          )}
        </Formik>
      </div>
    </div>
  )
}

export default LeadForm


================================================
FILE: packages/starters/next-corporate/starter/components/sections/pricing.js
================================================
import { MdCheckBox } from "react-icons/md"
import classNames from "classnames"

const Pricing = ({ data }) => {
  return (
    <div className="container py-12">
      <h1 className="text-4xl text-center">{data.title}</h1>
      <div className="flex flex-col lg:flex-row gap-4 lg:justify-center mt-6">
        {data.plans.map((plan) => (
          <div
            className={classNames(
              // Common classes
              "rounded-md border-2 py-4 px-4 flex-1 md:w-lg",
              // Normal plan
              {
                "bg-gray-100 text-gray-900 border-gray-300":
                  !plan.isRecommended,
              },
              // Recommended plan
              {
                "bg-primary-100 text-primary-900 border-primary-300":
                  plan.isRecommended,
              }
            )}
            key={plan.id}
          >
            <h2 className="text-2xl">{plan.name}</h2>
            <p
              className={classNames("mt-4 text-lg", {
                "text-primary-700": plan.isRecommended,
                "text-gray-700": !plan.isRecommended,
              })}
            >
              {plan.description}
            </p>
            <p className="text-3xl mt-4">
              {plan.price === 0 ? "Free " : `$${plan.price} `}
              <span className="text-base font-medium">{plan.pricePeriod}</span>
            </p>
            <ul className="mt-4 flex flex-col gap-3">
              {plan.features.map((feature) => (
                <li
                  className="flex flex-row justify-between items-center"
                  key={feature.id}
                >
                  <span>{feature.name}</span>
                  <MdCheckBox className="h-6 w-auto text-gray-900" />
                </li>
              ))}
            </ul>
          </div>
        ))}
      </div>
    </div>
  )
}

export default Pricing


================================================
FILE: packages/starters/next-corporate/starter/components/sections/rich-text.js
================================================
import PropTypes from "prop-types"
import Markdown from "react-markdown"

const RichText = ({ data }) => {
  return (
    <div className="prose prose-lg container py-12">
      <Markdown>{data.content}</Markdown>
    </div>
  )
}

RichText.propTypes = {
  data: PropTypes.shape({
    content: PropTypes.string,
  }),
}

export default RichText


================================================
FILE: packages/starters/next-corporate/starter/components/sections/testimonials-group.js
================================================
import classNames from "classnames"
import { useState } from "react"
import NextImage from "../elements/image"
import CustomLink from "../elements/custom-link"

const TestimonialsGroup = ({ data }) => {
  // Only show one testimonial at a time
  const [selectedTestimonialIndex, setSelectedTestimonialIndex] = useState(0)
  const selectedTestimonial = data.testimonials[selectedTestimonialIndex]

  return (
    <section className="text-center text-lg bg-gray-200 pt-12 pb-16">
      <h2 className="title mb-4">{data.title}</h2>
      <p className="text-gray-700 mb-4">{data.description}</p>
      <CustomLink link={data.link}>
        <span className="with-arrow text-blue-700 hover:underline">
          {data.link.text}
        </span>
      </CustomLink>
      {/* Current testimonial card */}
      <div className="max-w-5xl w-8/12 sm:w-8/12 bg-white shadow-md sm:shadow-xl mx-auto flex flex-col sm:flex-row mt-10 text-left">
        <div className="w-full md:w-4/12 flex-shrink-0">
          <NextImage media={selectedTestimonial.picture} />
        </div>
        <div className="px-4 py-4 sm:px-12 sm:pt-12 sm:pb-4 flex flex-col justify-between">
          <div>
            <NextImage
              width="120"
              height="33"
              media={selectedTestimonial.logo}
            />
            <p className="italic mb-6">
              &quot;{selectedTestimonial.text}&quot;
            </p>
            <p className="font-bold text-base sm:text-sm">
              {selectedTestimonial.authorName}
            </p>
            <p className="text-base sm:text-sm">
              {selectedTestimonial.authorTitle}
            </p>
          </div>
          <CustomLink
            link={{
              url: selectedTestimonial.link,
              text: "",
              newTab: false,
              id: 0,
            }}
          >
            <span className="uppercase tracking-wide text-blue-700 hover:underline  with-arrow sm:self-end mt-6 sm:mt-0">
              Read story
            </span>
          </CustomLink>
        </div>
      </div>
      {/* Change selected testimonial (only if there is more than one) */}
      {data.testimonials.length > 1 && (
        <div className="flex flex-row gap-4 mt-10 justify-center">
          {data.testimonials.map((testimonial, index) => (
            <button
              onClick={() => setSelectedTestimonialIndex(index)}
              className={classNames(
                // Common classes
                "rounded-full h-3 w-3",
                {
                  "bg-gray-500": index !== selectedTestimonialIndex,
                  "bg-primary-600": index === selectedTestimonialIndex,
                }
              )}
              key={testimonial.id}
            />
          ))}
        </div>
      )}
      {/* Logos list */}
      <div className="flex flex-row flex-wrap items-center gap-6 sm:gap-20 justify-center mt-10 px-6 sm:px-0 ">
        {data.logos.map((logo) => (
          <NextImage key={logo.id} width="120" height="33" media={logo.logo} />
        ))}
      </div>
    </section>
  )
}

export default TestimonialsGroup


================================================
FILE: packages/starters/next-corporate/starter/components/sections.js
================================================
import { useRouter } from "next/router"
import Hero from "@/components/sections/hero"
import LargeVideo from "@/components/sections/large-video"
import FeatureColumnsGroup from "@/components/sections/feature-columns-group"
import FeatureRowsGroup from "@/components/sections/feature-rows-group"
import BottomActions from "@/components/sections/bottom-actions"
import TestimonialsGroup from "@/components/sections/testimonials-group"
import RichText from "./sections/rich-text"
import Pricing from "./sections/pricing"
import LeadForm from "./sections/lead-form"

// Map Strapi sections to section components
const sectionComponents = {
  ComponentSectionsHero: Hero,
  ComponentSectionsLargeVideo: LargeVideo,
  ComponentSectionsFeatureColumnsGroup: FeatureColumnsGroup,
  ComponentSectionsFeatureRowsGroup: FeatureRowsGroup,
  ComponentSectionsBottomActions: BottomActions,
  ComponentSectionsTestimonialsGroup: TestimonialsGroup,
  ComponentSectionsRichText: RichText,
  ComponentSectionsPricing: Pricing,
  ComponentSectionsLeadForm: LeadForm,
}

// Display a section individually
const Section = ({ sectionData }) => {
  // Prepare the component
  const SectionComponent = sectionComponents[sectionData.__typename]

  if (!SectionComponent) {
    return null
  }

  // Display the section
  return <SectionComponent data={sectionData} />
}

const PreviewModeBanner = () => {
  const router = useRouter()
  const exitURL = `/api/exit-preview?redirect=${encodeURIComponent(
    router.asPath
  )}`

  return (
    <div className="py-4 bg-red-600 text-red-100 font-semibold uppercase tracking-wide">
      <div className="container">
        Preview mode is on.{" "}
        <a
          className="underline"
          href={`/api/exit-preview?redirect=${router.asPath}`}
        >
          Turn off
        </a>
      </div>
    </div>
  )
}

// Display the list of sections
const Sections = ({ sections, preview }) => {
  return (
    <div className="flex flex-col">
      {/* Show a banner if preview mode is on */}
      {preview && <PreviewModeBanner />}
      {/* Show the actual sections */}
      {sections.map((section) => (
        <Section
          sectionData={section}
          key={`${section.__typename}${section.id}`}
        />
      ))}
    </div>
  )
}

export default Sections


================================================
FILE: packages/starters/next-corporate/starter/jsconfig.json
================================================
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/components/*": [
        "components/*"
      ],
      "@/lib/*": [
        "lib/*"
      ],
      "@/styles/*": [
        "styles/*"
      ]
    }
  }
}


================================================
FILE: packages/starters/next-corporate/starter/next.config.js
================================================
module.exports = {
  i18n: {
    locales: ['en', 'fr'],
    defaultLocale: 'en',
  },
}


================================================
FILE: packages/starters/next-corporate/starter/package.json
================================================
{
  "name": "my-next-corporate",
  "version": "1.0.7",
  "private": true,
  "scripts": {
    "dev": "next",
    "develop": "next",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "lint:fix": "next lint --fix"
  },
  "dependencies": {
    "@tailwindcss/typography": "^0.4.1",
    "classnames": "^2.2.6",
    "cookie": "^0.4.1",
    "date-fns": "2.14.0",
    "formik": "^2.2.6",
    "js-cookie": "3.0.0-rc.4",
    "next": "^11.0.0",
    "next-seo": "^4.7.1",
    "postcss-import": "^14.0.2",
    "prop-types": "^15.7.2",
    "qs": "^6.10.1",
    "react": "^17.0.0",
    "react-dom": "^17.0.0",
    "react-icons": "^3.10.0",
    "react-markdown": "^6.0.2",
    "tailwindcss": "^2.2.6",
    "yup": "^0.32.8"
  },
  "devDependencies": {
    "autoprefixer": "^10.3.1",
    "eslint": "^7.30.0",
    "eslint-config-next": "^11.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^3.4.0",
    "postcss": "8.3.6",
    "postcss-flexbugs-fixes": "^5.0.2",
    "postcss-nested": "^5.0.5",
    "postcss-preset-env": "^6.7.0",
    "prettier": "^2.3.1"
  }
}


================================================
FILE: packages/starters/next-corporate/starter/pages/[[...slug]].js
================================================
import ErrorPage from "next/error"
import { getPageData, fetchAPI, getGlobalData } from "utils/api"
import Sections from "@/components/sections"
import Seo from "@/components/elements/seo"
import { useRouter } from "next/router"
import Layout from "@/components/layout"
import { getLocalizedPaths } from "utils/localize"

// The file is called [[...slug]].js because we're using Next's
// optional catch all routes feature. See the related docs:
// https://nextjs.org/docs/routing/dynamic-routes#optional-catch-all-routes

const DynamicPage = ({ sections, metadata, preview, global, pageContext }) => {
  const router = useRouter()

  // Check if the required data was provided
  if (!router.isFallback && !sections?.length) {
    return <ErrorPage statusCode={404} />
  }

  // Loading screen (only possible in preview mode)
  if (router.isFallback) {
    return <div className="container">Loading...</div>
  }

  // Merge default site SEO settings with page specific SEO settings
  if (metadata.shareImage?.data == null) {
    delete metadata.shareImage
  }
  const metadataWithDefaults = {
    ...global.attributes.metadata,
    ...metadata,
  }

  return (
    <Layout global={global} pageContext={pageContext}>
      {/* Add meta tags for SEO*/}
      <Seo metadata={metadataWithDefaults} />
      {/* Display content sections */}
      <Sections sections={sections} preview={preview} />
    </Layout>
  )
}

export async function getStaticPaths(context) {
  // Get all pages from Strapi
  const pages = await context.locales.reduce(
    async (currentPagesPromise, locale) => {
      const currentPages = await currentPagesPromise
      const localePages = await fetchAPI("/pages", {
        locale,
        fields: ["slug", "locale"],
      })
      return [...currentPages, ...localePages.data]
    },
    Promise.resolve([])
  )

  const paths = pages.map((page) => {
    const { slug, locale } = page.attributes
    // Decompose the slug that was saved in Strapi
    const slugArray = !slug ? false : slug.split("/")

    return {
      params: { slug: slugArray },
      // Specify the locale to render
      locale,
    }
  })

  return { paths, fallback: true }
}

export async function getStaticProps(context) {
  const { params, locale, locales, defaultLocale, preview = null } = context

  const globalLocale = await getGlobalData(locale)
  // Fetch pages. Include drafts if preview mode is on
  const pageData = await getPageData({
    slug: (!params.slug ? [""] : params.slug).join("/"),
    locale,
    preview,
  })

  if (pageData == null) {
    // Giving the page no props will trigger a 404 page
    return { props: {} }
  }

  // We have the required page data, pass it to the page component
  const { contentSections, metadata, localizations, slug } = pageData.attributes

  const pageContext = {
    locale,
    locales,
    defaultLocale,
    slug,
    localizations,
  }

  const localizedPaths = getLocalizedPaths(pageContext)

  return {
    props: {
      preview,
      sections: contentSections,
      metadata,
      global: globalLocale.data,
      pageContext: {
        ...pageContext,
        localizedPaths,
      },
    },
  }
}

export default DynamicPage


================================================
FILE: packages/starters/next-corporate/starter/pages/_app.js
================================================
import App from "next/app"
import Head from "next/head"
import ErrorPage from "next/error"
import { useRouter } from "next/router"
import { DefaultSeo } from "next-seo"
import { getStrapiMedia } from "utils/media"
import { getGlobalData } from "utils/api"
import "@/styles/index.css"

const MyApp = ({ Component, pageProps }) => {
  // Extract the data we need
  const { global } = pageProps
  if (global == null) {
    return <ErrorPage statusCode={404} />
  }

  const { metadata, favicon, metaTitleSuffix } = global.attributes

  return (
    <>
      {/* Favicon */}
      <Head>
        <link
          rel="shortcut icon"
          href={getStrapiMedia(favicon.data.attributes.url)}
        />
      </Head>
      {/* Global site metadata */}
      <DefaultSeo
        titleTemplate={`%s | ${metaTitleSuffix}`}
        title="Page"
        description={metadata.metaDescription}
        openGraph={{
          images: Object.values(
            metadata.shareImage.data.attributes.formats
          ).map((image) => {
            return {
              url: getStrapiMedia(image.url),
              width: image.width,
              height: image.height,
            }
          }),
        }}
        twitter={{
          cardType: metadata.twitterCardType,
          handle: metadata.twitterUsername,
        }}
      />
      {/* Display the content */}
      <Component {...pageProps} />
    </>
  )
}

// getInitialProps disables automatic static optimization for pages that don't
// have getStaticProps. So [[...slug]] pages still get SSG.
// Hopefully we can replace this with getStaticProps once this issue is fixed:
// https://github.com/vercel/next.js/discussions/10949
MyApp.getInitialProps = async (appContext) => {
  // Calls page's `getInitialProps` and fills `appProps.pageProps`
  const appProps = await App.getInitialProps(appContext)
  const globalLocale = await getGlobalData(appContext.router.locale)

  return {
    ...appProps,
    pageProps: {
      global: globalLocale,
    },
  }
}

export default MyApp


================================================
FILE: packages/starters/next-corporate/starter/pages/_document.js
================================================
import Document, { Html, Head, Main, NextScript } from "next/document"

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}


================================================
FILE: packages/starters/next-corporate/starter/pages/api/exit-preview.js
================================================
import { redirect } from "next/dist/next-server/server/api-utils"

export default async function exit(req, res) {
  // Exit the current user from "Preview Mode". This function accepts no args.
  res.clearPreviewData()

  // Redirect the user back to a provided redirect path or the index page
  res.writeHead(307, { Location: "/" })
  res.end()
}


================================================
FILE: packages/starters/next-corporate/starter/pages/api/preview.js
================================================
import { getPageData } from "utils/api"
import { parseCookies } from "utils/parse-cookies"

const preview = async (req, res) => {
  // Check the secret and next parameters
  // This secret should only be known to this API route and the CMS
  if (req.query.secret !== (process.env.PREVIEW_SECRET || "secret-token")) {
    return res.status(401).json({ message: "Invalid token" })
  }

  const cookies = parseCookies(req)
  const slugArray = req.query.slug.split("/")
  // Fetch the headless CMS to check if the provided `slug` exists
  const pageData = await getPageData({
    locale,
    slug: slugArray.join("/"),
    preview: true,
  })

  // If the slug doesn't exist prevent preview mode from being enabled
  if (!pageData) {
    return res.status(401).json({ message: "Invalid slug" })
  }

  // Enable Preview Mode by setting the cookies
  res.setPreviewData({})

  // Redirect to the path from the fetched post
  // We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
  // Prefix with locale so previews are available in all languages
  res.writeHead(307, {
    Location: `/${pageData.locale}/${pageData.slug}`,
  })
  res.end()
}

export default preview

// You can view Preview pages with URLs like this:
// http://localhost:3000/api/preview?secret=<preview-secret>&slug=<slug>
// where <preview-secret> is the secret token defined in your .env config
// and where <slug> is the slug you entered in Strapi for your page
// The slug must match the current locale


================================================
FILE: packages/starters/next-corporate/starter/postcss.config.js
================================================
module.exports = {
  plugins: [
    "postcss-import",
    "tailwindcss",
    "postcss-flexbugs-fixes",
    "postcss-nesting",
    "postcss-custom-properties",
    "autoprefixer",
  ],
}


================================================
FILE: packages/starters/next-corporate/starter/public/.gitkeep
================================================


================================================
FILE: packages/starters/next-corporate/starter/styles/index.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;

html {
  font-size: 13px;
  @apply text-gray-900;
}

@media screen and (min-width: 640px) {
  html {
    font-size: 14px;
  }
}

@media screen and (min-width: 768px) {
  html {
    font-size: 15px;
  }
}

.rich-text-hero a {
  @apply text-blue-600 underline;
}

.rich-text-banner {
  @apply whitespace-pre-line;
  a {
    @apply underline;
  }
}

.title {
  @apply text-4xl leading-snug font-semibold;
}

@media (min-width: 768px) {
  .title {
    @apply text-5xl;
  }
}

.with-arrow:after {
  background-image: url(data:image/svg+xml;charset=utf-8,%3Csvg%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M1%206a.5.5%200%200%200%200%201V6zM12.854.646a.5.5%200%200%200-.708.708l.708-.708zM18%206.5l.354.354a.5.5%200%200%200%200-.708L18%206.5zm-5.854%205.146a.5.5%200%200%200%20.708.708l-.708-.708zM1%207h16.5V6H1v1zm16.646-.854l-5.5%205.5.708.708%205.5-5.5-.708-.708zm-5.5-4.792l2.75%202.75.708-.708-2.75-2.75-.708.708zm2.75%202.75l2.75%202.75.708-.708-2.75-2.75-.708.708z%22%20fill%3D%22%231264A3%22%2F%3E%3C%2Fsvg%3E);
  content: "";
  width: 19px;
  height: 13px;
  display: inline-block;
  margin-left: 0.5em;
}


================================================
FILE: packages/starters/next-corporate/starter/tailwind.config.js
================================================
const { colors } = require(`tailwindcss/defaultTheme`)

module.exports = {
  mode: "jit", // see https://tailwindcss.com/docs/just-in-time-mode
  purge: ["./components/**/*.js", "./pages/**/*.js"],
  darkMode: false, // or "media" or "class"
  theme: {
    extend: {
      colors: {
        primary: colors.indigo,
      },
      container: {
        center: true,
        padding: {
          DEFAULT: "1rem",
          md: "2rem",
        },
      },
    },
    screens: {
      sm: "640px",
      md: "768px",
      lg: "1024px",
      xl: "1280px",
    },
  },
  variants: {
    extend: {},
  },
  plugins: [require("@tailwindcss/typography")],
}


================================================
FILE: packages/starters/next-corporate/starter/utils/api.js
================================================
import qs from "qs"

export function getStrapiURL(path) {
  return `${
    process.env.NEXT_PUBLIC_STRAPI_API_URL || "http://localhost:1337"
  }${path}`
}

/**
 * Helper to make GET requests to Strapi API endpoints
 * @param {string} path Path of the API route
 * @param {Object} urlParamsObject URL params object, will be stringified
 * @param {RequestInit} options Options passed to fetch
 * @returns Parsed API call response
 */
export async function fetchAPI(path, urlParamsObject = {}, options = {}) {
  // Merge default and user options
  const mergedOptions = {
    headers: {
      "Content-Type": "application/json",
    },
    ...options,
  }

  // Build request URL
  const queryString = qs.stringify(urlParamsObject)
  const requestUrl = `${getStrapiURL(
    `/api${path}${queryString ? `?${queryString}` : ""}`
  )}`

  // Trigger API call
  const response = await fetch(requestUrl, mergedOptions)

  // Handle response
  if (!response.ok) {
    console.error(response.statusText)
    throw new Error(`An error occurred please try again`)
  }
  const data = await response.json()
  return data
}

/**
 *
 * @param {Object} options
 * @param {string} options.slug The page's slug
 * @param {string} options.locale The current locale specified in router.locale
 * @param {boolean} options.preview router isPreview value
 */
export async function getPageData({ slug, locale, preview }) {
  // Find the pages that match this slug
  const gqlEndpoint = getStrapiURL("/graphql")
  const pagesRes = await fetch(gqlEndpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: `
        fragment FileParts on UploadFileEntityResponse {
          data {
            id
            attributes {
              alternativeText
              width
              height
              mime
              url
              formats
            }
          }
        }
        query GetPages(
          $slug: String!
          $publicationState: PublicationState!
          $locale: I18NLocaleCode!
        ) {        
          pages(
            filters: { slug: { eq: $slug } }
            publicationState: $publicationState
            locale: $locale
          ) {
            data {
              id
              attributes {
                locale
                localizations {
                  data {
                    id
                    attributes {
                      locale
                    }
                  }
                }
                slug
                metadata {
                  metaTitle
                  metaDescription
                  shareImage {
                    ...FileParts
                  }
                  twitterCardType
                  twitterUsername
                }
                contentSections {
                  __typename
                  ... on ComponentSectionsBottomActions {
                    id
                    title
                    buttons {
                      id
                      newTab
                      text
                      type
                      url
                    }
                  }
                  ... on ComponentSectionsHero {
                    id
                    buttons {
                      id
                      newTab
                      text
                      type
                      url
                    }
                    title
                    description
                    label
                    picture {
                      ...FileParts
                    }
                  }
                  ... on ComponentSectionsFeatureColumnsGroup {
                    id
                    features {
                      id
                      description
                      icon {
                        ...FileParts
                      }
                      title
                    }
                  }
                  ... on ComponentSectionsFeatureRowsGroup {
                    id
                    features {
                      id
                      description
                      link {
                        id
                        newTab
                        text
                        url
                      }
                      media {
                        ...FileParts
                      }
                      title
                    }
                  }
                  ... on ComponentSectionsTestimonialsGroup {
                    id
                    description
                    link {
                      id
                      newTab
                      text
                      url
                    }
                    logos {
                      id
                      title
                      logo {
                        ...FileParts
                      }
                    }
                    testimonials {
                      id
                      logo {
                        ...FileParts
                      }
                      picture {
                        ...FileParts
                      }
                      text
                      authorName
                      authorTitle
                      link
                    }
                    title
                  }
                  ... on ComponentSectionsLargeVideo {
                    id
                    description
                    title
                    poster {
                      ...FileParts
                    }
                    video {
                      ...FileParts
                    }
                  }
                  ... on ComponentSectionsRichText {
                    id
                    content
                  }
                  ... on ComponentSectionsPricing {
                    id
                    title
                    plans {
                      description
                      features {
                        id
                        name
                      }
                      id
                      isRecommended
                      name
                      price
                      pricePeriod
                    }
                  }
                  ... on ComponentSectionsLeadForm {
                    id
                    emailPlaceholder
                    location
                    submitButton {
                      id
                      text
                      type
                    }
                    title
                  }
                }
              }
            }
          }
        }      
      `,
      variables: {
        slug,
        publicationState: preview ? "PREVIEW" : "LIVE",
        locale,
      },
    }),
  })

  const pagesData = await pagesRes.json()
  // Make sure we found something, otherwise return null
  if (pagesData.data?.pages == null || pagesData.data.pages.length === 0) {
    return null
  }

  // Return the first item since there should only be one result per slug
  return pagesData.data.pages.data[0]
}

// Get site data from Strapi (metadata, navbar, footer...)
export async function getGlobalData(locale) {
  const gqlEndpoint = getStrapiURL("/graphql")
  const globalRes = await fetch(gqlEndpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: `
        fragment FileParts on UploadFileEntityResponse {
          data {
            id
            attributes {
              alternativeText
              width
              height
              mime
              url
              formats
            }
          }
        }
        query GetGlobal($locale: I18NLocaleCode!) {
          global(locale: $locale) {
            data {
              id
              attributes {
                favicon {
                  ...FileParts
                }
                metadata {
                  metaTitle
                  metaDescription
                  shareImage {
                    ...FileParts
                  }
                  twitterCardType
                  twitterUsername
                }
                metaTitleSuffix
                notificationBanner {
                  type
                  text
                }
                navbar {
                  logo {
                    ...FileParts
                  }
                  links {
                    id
                    url
                    newTab
                    text
                  }
                  button {
                    id
                    url
                    newTab
                    text
                    type
                  }
                }
                footer {
                  logo {
                    ...FileParts
                  }
                  smallText
                  columns {
                    id
                    title
                    links {
                      id
                      url
                      newTab
                      text
                    }
                  }
                }
              }
            }
          }
        }      
      `,
      variables: {
        locale,
      },
    }),
  })

  const global = await globalRes.json()
  return global.data.global
}


================================================
FILE: packages/starters/next-corporate/starter/utils/button.js
================================================
// Decide what the button will look like based on its type (primary or secondary)
// and on its background (light or dark).
export function getButtonAppearance(type, background) {
  if (type === 'primary') {
    if (background === 'light') {
      // Dark primary button on a light background
      return 'dark'
    }
    // Fully white primary button on a dark background
    return 'white'
  }
  if (type === 'secondary') {
    if (background === 'light') {
      // Dark outline primary button on a light background
      return 'dark-outline'
    }
    // White outline primary button on a dark background
    return 'white-outline'
  }

  // Shouldn't happen, but default to dark button just in case
  return 'dark'
}


================================================
FILE: packages/starters/next-corporate/starter/utils/hooks.js
================================================
import { useEffect } from 'react'

// Got from https://usehooks.com/useLockBodyScroll/
export function useLockBodyScroll() {
  useEffect(() => {
    // Get original body overflow
    const originalStyle = window.getComputedStyle(document.body).overflow

    // Prevent scrolling on mount
    document.body.style.overflow = 'hidden'

    // Re-enable scrolling when component unmounts
    return () => (document.body.style.overflow = originalStyle)
  }, []) // Empty array ensures effect is only run on mount and unmount
}

export function useOnClickOutside(ref, handler) {
  useEffect(() => {
    const listener = (event) => {
      // Do nothing if clicking ref's element or descendent elements
      if (!ref.current || ref.current.contains(event.target)) {
        return
      }

      handler(event)
    }

    document.addEventListener('mousedown', listener)
    document.addEventListener('touchstart', listener)

    return () => {
      document.removeEventListener('mousedown', listener)
      document.removeEventListener('touchstart', listener)
    }
  }, [ref, handler])
}


================================================
FILE: packages/starters/next-corporate/starter/utils/localize.js
================================================
import { fetchAPI } from "./api"

export async function getLocalizedPage(targetLocale, pageContext) {
  const localization = pageContext.localizations.data.find(
    (localization) => localization.attributes.locale === targetLocale
  )
  const localePage = await fetchAPI(`/pages/${localization.id}`)
  return localePage
}

export function localizePath(page) {
  const { locale, defaultLocale, slug } = page

  if (locale === defaultLocale) {
    // The default locale is not prefixed
    return `/${slug}`
  }

  // The slug should have a localePrefix
  return `/${locale}/${slug}`
}

export function getLocalizedPaths(page) {
  const paths = page.locales.map((locale) => {
    return {
      locale: locale,
      href: localizePath({ ...page, locale }),
    }
  })

  return paths
}


================================================
FILE: packages/starters/next-corporate/starter/utils/media.js
================================================
export function getStrapiMedia(url) {
  if (url == null) {
    return null
  }

  // Return the full URL if the media is hosted on an external provider
  if (url.startsWith("http") || url.startsWith("//")) {
    return url
  }

  // Otherwise prepend the URL path with the Strapi URL
  return `${
    process.env.NEXT_PUBLIC_STRAPI_API_URL || "http://localhost:1337"
  }${url}`
}


================================================
FILE: packages/starters/next-corporate/starter/utils/parse-cookies.js
================================================
import cookie from "cookie"

export function parseCookies(req) {
  return cookie.parse(req ? req.headers.cookie || '' : document.cookie)
}


================================================
FILE: packages/starters/next-corporate/starter/utils/types.js
================================================
import PropTypes from "prop-types"

export const linkPropTypes = PropTypes.shape({
  id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  url: PropTypes.string.isRequired,
  text: PropTypes.string.isRequired,
  newTab: PropTypes.bool,
})

export const mediaPropTypes = PropTypes.shape({
  data: PropTypes.shape({
    id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
    attributes: PropTypes.shape({
      alternativeText: PropTypes.string,
      mime: PropTypes.string.isRequired,
      url: PropTypes.string.isRequired,
    }),
  }),
})

export const buttonLinkPropTypes = PropTypes.shape({
  theme: PropTypes.string,
  text: PropTypes.string.isRequired,
  newTab: PropTypes.bool,
})


================================================
FILE: packages/starters/next-corporate/starter.json
================================================
{
  "template": {
    "name": "@strapi/template-corporate",
    "version": "^1.0.0"
  }
}


================================================
FILE: packages/templates/.gitkeep
================================================


================================================
FILE: packages/templates/blog/README.md
================================================
# strapi-template-blog

A Strapi template to create Strapi projects pre-configured for blog apps.

## Usage

```bash
# Using Yarn
yarn create strapi-app my-app-name --template blog

# Or using NPM
npx create-strapi-app my-app-name --template blog
```

## Starters

This template is used by the following starters:

* [strapi-starter-next-blog](https://github.com/strapi/strapi-starter-next-blog)
* [strapi-starter-nuxt-blog](https://github.com/strapi/strapi-starter-nuxt-blog)
* [strapi-starter-gatsby-blog](https://github.com/strapi/strapi-starter-gatsby-blog)
* [strapi-starter-gridsome-blog](https://github.com/strapi/strapi-starter-gridsome-blog)


================================================
FILE: packages/templates/blog/package.json
================================================
{
  "name": "@strapi/template-blog",
  "version": "2.0.5",
  "description": "Strapi blog template",
  "keywords": [
    "strapi",
    "template",
    "blog"
  ],
  "homepage": "https://github.com/strapi/starters-and-templates#readme",
  "bugs": {
    "url": "https://github.com/strapi/starters-and-templates/issues"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/strapi/starters-and-templates.git"
  },
  "license": "MIT",
  "author": {
    "name": "Strapi team",
    "email": "hi@strapi.io",
    "url": "https://strapi.io"
  },
  "maintainers": [
    {
      "name": "Strapi team",
      "email": "hi@strapi.io",
      "url": "https://strapi.io"
    }
  ],
  "gitHead": "d6d5bd264d1df0a0f23b5234d84348f8d78882e3"
}


================================================
FILE: packages/templates/blog/template/data/data.json
================================================
{
  "global": {
    "siteName": "Strapi Blog",
    "defaultSeo": {
      "metaTitle": "Page",
      "metaDescription": "A blog made with Strapi",
      "shareImage": null
    },
    "siteDescription": "A Blog made with Strapi",
    "favicon": null
  },
  "about": {
    "title": "About the strapi blog",
    "blocks": [
      {
        "__component": "shared.quote",
        "title": "Thelonius Monk",
        "body": "You've got to dig it to dig it, you dig?"
      },
      {
        "__component": "shared.rich-text",
        "body": "## Dedit imago conspicuus cum capillis totidem inhibere\n\nLorem markdownum **rerum**, est limine: columbas: ab infelix hostem arbore nudis\ncrudelis. Videtur reliquit ambo ferrum dote sub amne fatis **illuc**, in magis,\nnec."
      },
      {
        "__component": "shared.media",
        "file": "coffee-art.jpg"
      }
    ]
  },
  "categories": [
    {
      "name": "news",
      "slug": "news"
    },
    {
      "name": "tech",
      "slug": "tech"
    },
    {
      "name": "food",
      "slug": "food"
    },
    {
      "name": "nature",
      "slug": "nature"
    },
    {
      "name": "story",
      "slug": "story"
    }
  ],
  "authors": [
    {
      "name": "David Doe",
      "email": "daviddoe@strapi.io",
      "avatar": "daviddoe@strapi.io.jpg"
    },
    {
      "name": "Sarah Baker",
      "email": "sarahbaker@strapi.io",
      "avatar": "sarahbaker@strapi.io.jpg"
    }
  ],
  "articles": [
    {
      "title": "The internet's Own boy",
      "slug": "the-internet-s-own-boy",
      "category": {
        "id": 5
      },
      "author": {
        "id": 1
      },
      "description": "Follow the story of Aaron Swartz, the boy who could change the world",
      "cover": null,
      "blocks": [
        {
          "__component": "shared.rich-text",
          "body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
        },
        {
          "__component": "shared.quote",
          "title": "Thelonius Monk",
          "body": "You've got to dig it to dig it, you dig?"
        },
        {
          "__component": "shared.media",
          "file": "coffee-art.jpg"
        },
        {
          "__component": "shared.rich-text",
          "body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
        },
        {
          "__component": "shared.slider",
          "files": [
            "coffee-art.jpg",
            "coffee-beans.jpg"
          ]
        }
      ]
    },
    {
      "title": "This shrimp is awesome",
      "slug": "this-shrimp-is-awesome",
      "category": {
        "id": 4
      },
      "author": {
        "id": 1
      },
      "description": "Mantis shrimps, or stomatopods, are marine crustaceans of the order Stomatopoda.",
      "cover": null,
      "blocks": [
        {
          "__component": "shared.rich-text",
          "body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
        },
        {
          "__component": "shared.quote",
          "title": "Thelonius Monk",
          "body": "You've got to dig it to dig it, you dig?"
        },
        {
          "__component": "shared.media",
          "file": "coffee-art.jpg"
        },
        {
          "__component": "shared.rich-text",
          "body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
        },
        {
          "__component": "shared.slider",
          "files": [
            "coffee-art.jpg",
            "coffee-beans.jpg"
          ]
        }
      ]
    },
    {
      "title": "A bug is becoming a meme on the internet",
      "slug": "a-bug-is-becoming-a-meme-on-the-internet",
      "category": {
        "id": 2
      },
      "author": {
        "id": 2
      },
      "description": "How a bug on MySQL is becoming a meme on the internet",
      "cover": null,
      "blocks": [
        {
          "__component": "shared.rich-text",
          "body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
        },
        {
          "__component": "shared.quote",
          "title": "Thelonius Monk",
          "body": "You've got to dig it to dig it, you dig?"
        },
        {
          "__component": "shared.media",
          "file": "coffee-art.jpg"
        },
        {
          "__component": "shared.rich-text",
          "body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
        },
        {
          "__component": "shared.slider",
          "files": [
            "coffee-art.jpg",
            "coffee-beans.jpg"
          ]
        }
      ]
    },
    {
      "title": "Beautiful picture",
      "slug": "beautiful-picture",
      "category": {
        "id": 4
      },
      "author": {
        "id": 2
      },
      "description": "Description of a beautiful picture",
      "cover": null,
      "blocks": [
        {
          "__component": "shared.rich-text",
          "body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
        },
        {
          "__component": "shared.quote",
          "title": "Thelonius Monk",
          "body": "You've got to dig it to dig it, you dig?"
        },
        {
          "__component": "shared.media",
          "file": "coffee-art.jpg"
        },
        {
          "__component": "shared.rich-text",
          "body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
        },
        {
          "__component": "shared.slider",
          "files": [
            "coffee-art.jpg",
            "coffee-beans.jpg"
          ]
        }
      ]
    },
    {
      "title": "What's inside a Black Hole",
      "slug": "what-s-inside-a-black-hole",
      "category": {
        "id": 1
      },
      "author": {
        "id": 2
      },
      "description": "Maybe the answer is in this article, or not...",
      "cover": null,
      "blocks": [
        {
          "__component": "shared.rich-text",
          "body": "## Probant \n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. \n\n## Abit sua\n\nse Lorem markdownum negat. Argo *saxa* videnda cornuaque hunc qui tanta spes teneas! Obliquis est dicenti est salutat ille tamen iuvenum nostrae dolore. - Colores nocituraque comitata eripiunt - Addit quodcunque solum cui et dextram illis - Nulli meus nec extemplo ille ferebat pressit Se blandita fulvae vox gravem Pittheus cesserunt sanguine herbis tu comitum tenuit. Sui in ruunt; Doridaque maculosae fuissem! Et loqui. "
        },
        {
          "__component": "shared.quote",
          "title": "Thelonius Monk",
          "body": "You've got to dig it to dig it, you dig?"
        },
        {
          "__component": "shared.media",
          "file": "coffee-art.jpg"
        },
        {
          "__component": "shared.rich-text",
          "body": "## Spatiantia astra \n\nFoeda, medio silva *errandum*: onus formam munere. Mutata bibulis est auxiliare arces etiamnunc verbis virgineo Priamidas illa Thescelus, nam fit locis lucis auras. Exitus hospes gratulor ut pondere [speslimite](http://www.curas.io/figuram); quid habent, Avernales faciente de. Pervenit Ino sonabile supplex cognoscenti vires, Bacchumque errat miserarum venandi dignabere dedisti. Discrimina iuncosaque virgaque tot sine superest [fissus](http://quos.org/sitet.aspx). Non color esset potest non sumit, sed vix arserat. Nisi immo silva tantum pectusque quos pennis quisquam artus!"
        },
        {
          "__component": "shared.slider",
          "files": [
            "coffee-art.jpg",
            "coffee-beans.jpg"
          ]
        }
      ]
    }
  ]
}


================================================
FILE: packages/templates/blog/template/src/api/.gitkeep
================================================


================================================
FILE: packages/templates/blog/template/src/api/about/content-types/about/schema.json
================================================
{
  "kind": "singleType",
  "collectionName": "abouts",
  "info": {
    "singularName": "about",
    "pluralName": "abouts",
    "displayName": "About",
    "description": "Write about yourself and the content you create"
  },
  "options": {
    "draftAndPublish": false
  },
  "pluginOptions": {},
  "attributes": {
    "title": {
      "type": "string"
    },
    "blocks": {
      "type": "dynamiczone",
      "components": [
        "shared.media",
        "shared.quote",
        "shared.rich-text",
        "shared.slider"
      ]
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/api/about/controllers/about.js
================================================
'use strict';

/**
 *  about controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::about.about');


================================================
FILE: packages/templates/blog/template/src/api/about/routes/about.js
================================================
'use strict';

/**
 * about router.
 */

const { createCoreRouter } = require('@strapi/strapi').factories;

module.exports = createCoreRouter('api::about.about');


================================================
FILE: packages/templates/blog/template/src/api/about/services/about.js
================================================
'use strict';

/**
 * about service.
 */

const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::about.about');


================================================
FILE: packages/templates/blog/template/src/api/article/content-types/article/schema.json
================================================
{
  "kind": "collectionType",
  "collectionName": "articles",
  "info": {
    "singularName": "article",
    "pluralName": "articles",
    "displayName": "Article",
    "description": "Create your blog content"
  },
  "options": {
    "draftAndPublish": true
  },
  "pluginOptions": {},
  "attributes": {
    "title": {
      "type": "string"
    },
    "description": {
      "type": "text",
      "maxLength": 80
    },
    "slug": {
      "type": "uid",
      "targetField": "title"
    },
    "cover": {
      "type": "media",
      "multiple": false,
      "required": false,
      "allowedTypes": [
        "images",
        "files",
        "videos"
      ]
    },
    "author": {
      "type": "relation",
      "relation": "manyToOne",
      "target": "api::author.author",
      "inversedBy": "articles"
    },
    "category": {
      "type": "relation",
      "relation": "manyToOne",
      "target": "api::category.category",
      "inversedBy": "articles"
    },
    "blocks": {
      "type": "dynamiczone",
      "components": [
        "shared.media",
        "shared.quote",
        "shared.rich-text",
        "shared.slider"
      ]
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/api/article/controllers/article.js
================================================
'use strict';

/**
 *  article controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::article.article');


================================================
FILE: packages/templates/blog/template/src/api/article/routes/article.js
================================================
'use strict';

/**
 * article router.
 */

const { createCoreRouter } = require('@strapi/strapi').factories;

module.exports = createCoreRouter('api::article.article');


================================================
FILE: packages/templates/blog/template/src/api/article/services/article.js
================================================
'use strict';

/**
 * article service.
 */

const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::article.article');


================================================
FILE: packages/templates/blog/template/src/api/author/content-types/author/schema.json
================================================
{
  "kind": "collectionType",
  "collectionName": "authors",
  "info": {
    "singularName": "author",
    "pluralName": "authors",
    "displayName": "Author",
    "description": "Create authors for your content"
  },
  "options": {
    "draftAndPublish": false
  },
  "pluginOptions": {},
  "attributes": {
    "name": {
      "type": "string"
    },
    "avatar": {
      "type": "media",
      "multiple": false,
      "required": false,
      "allowedTypes": [
        "images",
        "files",
        "videos"
      ]
    },
    "email": {
      "type": "string"
    },
    "articles": {
      "type": "relation",
      "relation": "oneToMany",
      "target": "api::article.article",
      "mappedBy": "author"
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/api/author/controllers/author.js
================================================
'use strict';

/**
 *  author controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::author.author');


================================================
FILE: packages/templates/blog/template/src/api/author/routes/author.js
================================================
'use strict';

/**
 * author router.
 */

const { createCoreRouter } = require('@strapi/strapi').factories;

module.exports = createCoreRouter('api::author.author');


================================================
FILE: packages/templates/blog/template/src/api/author/services/author.js
================================================
'use strict';

/**
 * author service.
 */

const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::author.author');


================================================
FILE: packages/templates/blog/template/src/api/category/content-types/category/schema.json
================================================
{
  "kind": "collectionType",
  "collectionName": "categories",
  "info": {
    "singularName": "category",
    "pluralName": "categories",
    "displayName": "Category",
    "description": "Organize your content into categories"
  },
  "options": {
    "draftAndPublish": false
  },
  "pluginOptions": {},
  "attributes": {
    "name": {
      "type": "string"
    },
    "slug": {
      "type": "uid"
    },
    "articles": {
      "type": "relation",
      "relation": "oneToMany",
      "target": "api::article.article",
      "mappedBy": "category"
    },
    "description": {
      "type": "text"
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/api/category/controllers/category.js
================================================
'use strict';

/**
 *  category controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::category.category');


================================================
FILE: packages/templates/blog/template/src/api/category/routes/category.js
================================================
'use strict';

/**
 * category router.
 */

const { createCoreRouter } = require('@strapi/strapi').factories;

module.exports = createCoreRouter('api::category.category');


================================================
FILE: packages/templates/blog/template/src/api/category/services/category.js
================================================
'use strict';

/**
 * category service.
 */

const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::category.category');


================================================
FILE: packages/templates/blog/template/src/api/global/content-types/global/schema.json
================================================
{
  "kind": "singleType",
  "collectionName": "globals",
  "info": {
    "singularName": "global",
    "pluralName": "globals",
    "displayName": "Global",
    "description": "Define global settings"
  },
  "options": {
    "draftAndPublish": false
  },
  "pluginOptions": {},
  "attributes": {
    "siteName": {
      "type": "string",
      "required": true
    },
    "favicon": {
      "type": "media",
      "multiple": false,
      "required": false,
      "allowedTypes": [
        "images",
        "files",
        "videos"
      ]
    },
    "siteDescription": {
      "type": "text",
      "required": true
    },
    "defaultSeo": {
      "type": "component",
      "repeatable": false,
      "component": "shared.seo"
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/api/global/controllers/global.js
================================================
'use strict';

/**
 *  global controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::global.global');


================================================
FILE: packages/templates/blog/template/src/api/global/routes/global.js
================================================
'use strict';

/**
 * global router.
 */

const { createCoreRouter } = require('@strapi/strapi').factories;

module.exports = createCoreRouter('api::global.global');


================================================
FILE: packages/templates/blog/template/src/api/global/services/global.js
================================================
'use strict';

/**
 * global service.
 */

const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::global.global');


================================================
FILE: packages/templates/blog/template/src/bootstrap.js
================================================
"use strict";

const fs = require("fs-extra");
const path = require("path");
const mime = require("mime-types");
const set = require("lodash.set");
const {
  categories,
  authors,
  articles,
  global,
  about,
} = require("../data/data.json");

async function isFirstRun() {
  const pluginStore = strapi.store({
    environment: strapi.config.environment,
    type: "type",
    name: "setup",
  });
  const initHasRun = await pluginStore.get({ key: "initHasRun" });
  await pluginStore.set({ key: "initHasRun", value: true });
  return !initHasRun;
}

async function setPublicPermissions(newPermissions) {
  // Find the ID of the public role
  const publicRole = await strapi
    .query("plugin::users-permissions.role")
    .findOne({
      where: {
        type: "public",
      },
    });

  // Create the new permissions and link them to the public role
  const allPermissionsToCreate = [];
  Object.keys(newPermissions).map((controller) => {
    const actions = newPermissions[controller];
    const permissionsToCreate = actions.map((action) => {
      return strapi.query("plugin::users-permissions.permission").create({
        data: {
          action: `api::${controller}.${controller}.${action}`,
          role: publicRole.id,
        },
      });
    });
    allPermissionsToCreate.push(...permissionsToCreate);
  });
  await Promise.all(allPermissionsToCreate);
}

function getFileSizeInBytes(filePath) {
  const stats = fs.statSync(filePath);
  const fileSizeInBytes = stats["size"];
  return fileSizeInBytes;
}

function getFileData(fileName) {
  const filePath = path.join("data", "uploads", fileName);
  // Parse the file metadata
  const size = getFileSizeInBytes(filePath);
  const ext = fileName.split(".").pop();
  const mimeType = mime.lookup(ext);

  return {
    path: filePath,
    name: fileName,
    size,
    type: mimeType,
  };
}

async function uploadFile(file, name) {
  return strapi
    .plugin("upload")
    .service("upload")
    .upload({
      files: file,
      data: {
        fileInfo: {
          alternativeText: `An image uploaded to Strapi called ${name}`,
          caption: name,
          name,
        },
      },
    });
}

// Create an entry and attach files if there are any
async function createEntry({ model, entry }) {
  try {
    // Actually create the entry in Strapi
    await strapi.entityService.create(`api::${model}.${model}`, {
      data: entry,
    });
  } catch (error) {
    console.error({ model, entry, error });
  }
}

async function checkFileExistsBeforeUpload(files) {
  const existingFiles = [];
  const uploadedFiles = [];
  const filesCopy = [...files];

  for (const fileName of filesCopy) {
    // Check if the file already exists in Strapi
    const fileWhereName = await strapi.query("plugin::upload.file").findOne({
      where: {
        name: fileName,
      },
    });

    if (fileWhereName) {
      // File exists, don't upload it
      existingFiles.push(fileWhereName);
    } else {
      // File doesn't exist, upload it
      const fileData = getFileData(fileName);
      const fileNameNoExtension = fileName.split('.').shift()
      const [file] = await uploadFile(fileData, fileNameNoExtension);
      uploadedFiles.push(file);
    }
  }
  const allFiles = [...existingFiles, ...uploadedFiles];
  // If only one file then return only that file
  return allFiles.length === 1 ? allFiles[0] : allFiles;
}

async function updateBlocks(blocks) {
  const updatedBlocks = [];
  for (const block of blocks) {
    if (block.__component === "shared.media") {
      const uploadedFiles = await checkFileExistsBeforeUpload([block.file]);
      // Copy the block to not mutate directly
      const blockCopy = { ...block };
      // Replace the file name on the block with the actual file
      blockCopy.file = uploadedFiles;
      updatedBlocks.push(blockCopy);
    } else if (block.__component === "shared.slider") {
      // Get files already uploaded to Strapi or upload new files
      const existingAndUploadedFiles = await checkFileExistsBeforeUpload(
        block.files
      );
      // Copy the block to not mutate directly
      const blockCopy = { ...block };
      // Replace the file names on the block with the actual files
      blockCopy.files = existingAndUploadedFiles;
      // Push the updated block
      updatedBlocks.push(blockCopy);
    } else {
      // Just push the block as is
      updatedBlocks.push(block);
    }
  }

  return updatedBlocks;
}

async function importArticles() {
  for (const article of articles) {
    const cover = await checkFileExistsBeforeUpload([`${article.slug}.jpg`]);
    const updatedBlocks = await updateBlocks(article.blocks);

    await createEntry({
      model: "article",
      entry: {
        ...article,
        cover,
        blocks: updatedBlocks,
        // Make sure it's not a draft
        publishedAt: Date.now(),
      },
    });
  }
}

async function importGlobal() {
  const favicon = await checkFileExistsBeforeUpload(["favicon.png"]);
  const shareImage = await checkFileExistsBeforeUpload(["default-image.png"])
  return createEntry({
    model: "global",
    entry: {
      ...global,
      favicon,
      // Make sure it's not a draft
      publishedAt: Date.now(),
      defaultSeo: {
        ...global.defaultSeo,
        shareImage
      }
    },
  });
}

async function importAbout() {
  const updatedBlocks = await updateBlocks(about.blocks);

  await createEntry({
    model: "about",
    entry: {
      ...about,
      blocks: updatedBlocks,
      // Make sure it's not a draft
      publishedAt: Date.now(),
    },
  });
}

async function importCategories() {
  for (const category of categories) {
    await createEntry({ model: "category", entry: category });
  }
}

async function importAuthors() {
  for (const author of authors) {
    const avatar = await checkFileExistsBeforeUpload([author.avatar]);

    await createEntry({
      model: "author",
      entry: {
        ...author,
        avatar,
      },
    });
  }
}

async function importSeedData() {
  // Allow read of application content types
  await setPublicPermissions({
    article: ["find", "findOne"],
    category: ["find", "findOne"],
    author: ["find", "findOne"],
    global: ["find", "findOne"],
    about: ["find", "findOne"],
  });

  // Create all entries
  await importCategories();
  await importAuthors();
  await importArticles();
  await importGlobal();
  await importAbout();
}

module.exports = async () => {
  const shouldImportSeedData = await isFirstRun();

  if (shouldImportSeedData) {
    try {
      console.log("Setting up the template...");
      await importSeedData();
      console.log("Ready to go");
    } catch (error) {
      console.log("Could not import seed data");
      console.error(error);
    }
  }
};


================================================
FILE: packages/templates/blog/template/src/components/shared/media.json
================================================
{
  "collectionName": "components_shared_media",
  "info": {
    "displayName": "Media",
    "icon": "file-video"
  },
  "options": {},
  "attributes": {
    "file": {
      "allowedTypes": [
        "images",
        "files",
        "videos"
      ],
      "type": "media",
      "multiple": false
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/components/shared/quote.json
================================================
{
  "collectionName": "components_shared_quotes",
  "info": {
    "displayName": "Quote",
    "icon": "indent"
  },
  "options": {},
  "attributes": {
    "title": {
      "type": "string"
    },
    "body": {
      "type": "text"
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/components/shared/rich-text.json
================================================
{
  "collectionName": "components_shared_rich_texts",
  "info": {
    "displayName": "Rich text",
    "icon": "align-justify",
    "description": ""
  },
  "options": {},
  "attributes": {
    "body": {
      "type": "richtext"
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/components/shared/seo.json
================================================
{
  "collectionName": "components_shared_seos",
  "info": {
    "name": "Seo",
    "icon": "allergies",
    "displayName": "Seo",
    "description": ""
  },
  "options": {},
  "attributes": {
    "metaTitle": {
      "type": "string",
      "required": true
    },
    "metaDescription": {
      "type": "text",
      "required": true
    },
    "shareImage": {
      "type": "media",
      "multiple": false,
      "required": false,
      "allowedTypes": [
        "images"
      ]
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/components/shared/slider.json
================================================
{
  "collectionName": "components_shared_sliders",
  "info": {
    "displayName": "Slider",
    "icon": "address-book",
    "description": ""
  },
  "options": {},
  "attributes": {
    "files": {
      "type": "media",
      "multiple": true,
      "required": false,
      "allowedTypes": [
        "images"
      ]
    }
  }
}


================================================
FILE: packages/templates/blog/template/src/extensions/.gitkeep
================================================


================================================
FILE: packages/templates/blog/template/src/index.js
================================================
"use strict";
const bootstrap = require("./bootstrap");

module.exports = {
  /**
   * An asynchronous register function that runs before
   * your application is initialized.
   *
   * This gives you an opportunity to extend code.
   */
  register(/*{ strapi }*/) {},

  /**
   * An asynchronous bootstrap function that runs before
   * your application gets started.
   *
   * This gives you an opportunity to set up your data model,
   * run jobs, or perform some special logic.
   */
  bootstrap,
};


================================================
FILE: packages/templates/blog/template.json
================================================
{
  "package": {
    "dependencies": {
      "@strapi/plugin-graphql": "^4.0.5",
      "fs-extra": "^10.0.0",
      "lodash.set": "^4.3.2",
      "mime-types": "^2.1.27"
    }
  }
}


================================================
FILE: packages/templates/corporate/README.md
================================================
# strapi-template-corporate

A Strapi template to create Strapi projects pre-configured for corporate apps.

## Usage

```bash
# Using Yarn
yarn create strapi-app my-app-name --template corporate

# Or using NPM
npx create-strapi-app my-app-name --template corporate
```

## Starters

This template is used by the following starters:

* [Strapi Starter Next Corporate Site](https://github.com/strapi/strapi-starter-next-corporate)
* [Strapi Starter Gatsby Corporate Site](https://github.com/strapi/strapi-starter-gatsby-corporate)


================================================
FILE: packages/templates/corporate/package.json
================================================
{
  "name": "@strapi/template-corporate",
  "version": "1.0.0",
  "description": "Strapi corporate template",
  "keywords": [
    "strapi",
    "template",
    "corporate"
  ],
  "homepage": "https://github.com/strapi/starters-and-templates#readme",
  "bugs": {
    "url": "https://github.com/strapi/starters-and-templates/issues"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/strapi/starters-and-templates.git"
  },
  "license": "MIT",
  "author": {
    "name": "Strapi team",
    "email": "hi@strapi.io",
    "url": "https://strapi.io"
  },
  "maintainers": [
    {
      "name": "Strapi team",
      "email": "hi@strapi.io",
      "url": "https://strapi.io"
    }
  ],
  "gitHead": "d6d5bd264d1df0a0f23b5234d84348f8d78882e3"
}


================================================
FILE: packages/templates/corporate/template/data/data.js
================================================
const { global, pages } = require("./en");
const { globalFR, pagesFR } = require("./fr");
const { leadFormSubmissions } = require("./lead-form-submissions.json");

module.exports = {
  globals: [global, globalFR],
  pages: [...pages, ...pagesFR],
  leadFormSubmissions,
};


================================================
FILE: packages/templates/corporate/template/data/en/global.json
================================================
{
  "global": {
    "id": 1,
    "locale": "en",
    "metaTitleSuffix": "Strapi Corporate",
    "metadata": {
      "id": 1,
      "metaTitle": "Strapi starter for Corporate Sites",
      "metaDescription": "Build your corporate site with Strapi",
      "twitterCardType": "summary",
      "twitterUsername": "strapijs",
      "shareImage": null
    },
    "notificationBanner": {
      "id": 1,
      "text": "This page was built using the Strapi starter for Corporate Sites.\n[View other Strapi starters](https://strapi.io/starters)",
      "type": "info"
    },
    "navbar": {
      "id": 1,
      "links": [
        {
          "id": 1,
          "url": "/pricing",
          "newTab": false,
          "text": "Pricing"
        },
        {
          "id": 3,
          "url": "/contact",
          "newTab": false,
          "text": "Contact"
        }
      ],
      "button": {
        "id": 13,
        "url": "#",
        "newTab": false,
        "text": "Sign up",
        "type": "secondary"
      },
      "logo" : null
    },
    "footer": {
      "id": 1,
      "smallText": "© Copyright My Company™",
      "columns": [
        {
          "id": 1,
          "title": "Product",
          "links": [
            {
              "id": 11,
              "url": "#",
              "newTab": false,
              "text": "Features"
            },
            {
              "id": 13,
              "url": "#",
              "newTab": false,
              "text": "Sign up"
            }
          ]
        },
        {
          "id": 2,
          "title": "Legal",
          "links": [
            {
              "id": 15,
              "url": "#",
              "newTab": false,
              "text": "Privacy policy"
            },
            {
              "id": 16,
              "url": "#",
              "newTab": false,
              "text": "Terms & conditions"
            }
          ]
        },
        {
          "id": 5,
          "title": "Company",
          "links": [
            {
              "id": 18,
              "url": "#",
              "newTab": false,
              "text": "Careers"
            },
            {
              "id": 21,
              "url": "#",
              "newTab": false,
              "text": "Team"
            }
          ]
        },
        {
          "id": 7,
          "title": "Social",
          "links": [
            {
              "id": 24,
              "url": "#",
              "newTab": false,
              "text": "Twitter"
            },
            {
              "id": 25,
              "url": "#",
              "newTab": false,
              "text": "LinkedIn"
            }
          ]
        }
      ],
      "logo": null
    },
    "favicon": null,
    "localizations": [
      {
        "id": 2,
        "locale": "fr"
      }
    ]
  }
}


================================================
FILE: packages/templates/corporate/template/data/en/index.js
================================================
const { global } = require("./global.json");
const { pages } = require("./pages.json");

module.exports = {
  global,
  pages
}

================================================
FILE: packages/templates/corporate/template/data/en/pages.json
================================================
{
  "pages": [
    {
      "id": 1,
      "slug": "",
      "locale": "en",
      "localizations": [
        {
          "id": 5,
          "locale": "fr"
        }
      ],
      "shortName": "Home",
      "publishedAt": "2021-10-22T08:11:55.490Z",
      "metadata": {
        "id": 2,
        "metaTitle": "Strapi corporate site starter",
        "metaDescription": "Build a fully editable site with Strapi",
        "twitterCardType": "summary",
        "twitterUsername": null,
        "shareImage": null
      },
      "contentSections": [
        {
          "id": 1,
          "__component": "sections.hero",
          "title": "The best way to build your Corporate Site",
          "label": "New Strapi starter",
          "description": "Get started with your Strapi business website in seconds.",
          "smallTextWithLink": "Want to build your own from scratch? Tutorial coming soon",
          "buttons": [
            {
              "id": 2,
              "url": "https://github.com/strapi/strapi-template-corporate",
              "newTab": false,
              "text": "Get started",
              "type": "primary"
            },
            {
              "id": 4,
              "url": "https://github.com/strapi/strapi-template-corporate",
              "newTab": true,
              "text": "See the code",
              "type": "secondary"
            }
          ],
          "picture": null
        },
        {
          "id": 1,
          "__component": "sections.feature-rows-group",
          "features": [
            {
              "id": 1,
              "title": "Let marketing teams build their pages",
              "description": "Thanks to a pre-built list of UI sections, marketers can design exactly the pages they want.",
              "link": {
                "id": 7,
                "url": "#",
                "newTab": false,
                "text": "View the list of UI sections"
              },
              "media": null
            },
            {
              "id": 2,
              "title": "Leave your developers alone",
              "description": "You can publish, edit and delete pages without help from developers. Your technical team can finally focus on their tasks.",
              "link": {
                "id": 8,
                "url": "#",
                "newTab": false,
                "text": "View how to create a page"
              },
              "media": null
            }
          ]
        },
        {
          "id": 1,
          "__component": "sections.feature-columns-group",
          "features": [
            {
              "id": 1,
              "title": "Preview your changes",
              "description": "Thanks to an integrated Preview Mode, you can visualize your pages before publishing them.",
              "icon": null
            },
            {
              "id": 2,
              "title": "Fully responsive",
              "description": "This starter works well on all screens, whether it's mobile, tablet or desktop.",
              "icon": null
            },
            {
              "id": 3,
              "title": "Easy to customize",
              "description": "We use Tailwind for styling. You can change your site's theme without digging through the code.",
              "icon": null
            }
          ]
        },
        {
          "id": 1,
          "__component": "sections.testimonials-group",
          "title": "Your customer testimonials here",
          "description": "This section is where you can showcase your customers. Insert quotes, and show the logos of companies who like your product",
          "link": {
            "id": 2,
            "url": "#",
            "newTab": false,
            "text": "All testimonials"
          },
          "logos": [
            {
              "id": 1,
              "title": "Strapi",
              "logo": null
            },
            {
              "id": 2,
              "title": "Strapi 2",
              "logo": null
            },
            {
              "id": 3,
              "title": "Strapi 3",
              "logo": null
            }
          ],
          "testimonials": [
            {
              "id": 1,
              "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
              "authorName": "Your Customer Name",
              "authorTitle": "A happy customer",
              "link": "#",
              "logo": null,
              "picture": null
            }
          ]
        },
        {
          "id": 1,
          "__component": "sections.lead-form",
          "title": "Subscribe To Our Newsletter",
          "emailPlaceholder": "email@company.com",
          "submitButton": {
            "id": 1,
            "__component": "links.button",
            "text": "Subscribe",
            "type": "primary"
          },
          "location": "Home Page Bottom"
        },
        {
          "id": 2,
          "__component": "sections.bottom-actions",
          "title": "Start building your website",
          "buttons": [
            {
              "id": 7,
              "url": "https://github.com/strapi/strapi-template-corporate",
              "newTab": false,
              "text": "Get started",
              "type": "primary"
            },
            {
              "id": 8,
              "url": "https://github.com/strapi/strapi-template-corporate",
              "newTab": false,
              "text": "See the code",
              "type": "secondary"
            }
          ]
        }
      ]
    },
    {
      "id": 2,
      "slug": "pricing",
      "locale": "en",
      "localizations": [
        {
          "id": 6,
          "locale": "fr"
        }
      ],
      "shortName": "Pricing",
      "publishedAt": "2021-10-22T08:11:55.490Z",
      "metadata": {
        "id": 3,
        "metaTitle": "Pricing",
        "metaDescription": "The different plans",
        "twitterCardType": "summary",
        "twitterUsername": null,
        "shareImage": null
      },
      "contentSections": [
        {
          "id": 1,
          "__component": "sections.pricing",
          "title": "Clear pricing table",
          "plans": [
            {
              "id": 1,
              "name": "Hobby",
              "description": "Perfect for side projects",
              "isRecommended": null,
              "price": 0,
              "pricePeriod": "forever",
              "features": [
                {
                  "id": 1,
                  "name": "A cool feature"
                },
                {
                  "id": 2,
                  "name": "Another cool feature"
                },
                {
                  "id": 3,
                  "name": "Some other cool feature"
                }
              ]
            },
            {
              "id": 2,
              "name": "Premium",
              "description": "A more advanced plan for SMBs",
              "isRecommended": true,
              "price": 20,
              "pricePeriod": "per month",
              "features": [
                {
                  "id": 4,
                  "name": "The coolest feature"
                },
                {
                  "id": 5,
                  "name": "Nice feature"
                },
                {
                  "id": 6,
                  "name": "Fun feature"
                }
              ]
            },
            {
              "id": 3,
              "name": "Enterprise",
              "description": "For large companies needs",
              "isRecommended": null,
              "price": 299,
              "pricePeriod": "per month",
              "features": [
                {
                  "id": 7,
                  "name": "Amazing feature"
                },
                {
                  "id": 8,
                  "name": "Wow effect feature"
                },
                {
                  "id": 9,
                  "name": "Mesmerizing feature"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "id": 3,
      "slug": "secret",
      "locale": "en",
      "localizations": [
        {
          "id": 7,
          "locale": "fr"
        }
      ],
      "shortName": "Secret",
      "metadata": {
        "id": 7,
        "metaTitle": "Secret page",
        "metaDescription": "Preview-only page",
        "twitterCardType": "summary",
        "twitterUsername": null,
        "shareImage": null
      },
      "contentSections": [
        {
          "id": 2,
          "__component": "sections.rich-text",
          "content": "## Secret page\n\nYou can only view this page in Preview Mode."
        }
      ]
    },
    {
      "id": 4,
      "slug": "contact",
      "locale": "en",
      "localizations": [
        {
          "id": 8,
          "locale": "fr"
        }
      ],
      "shortName": "Contact",
      "publishedAt": "2021-10-22T08:11:55.490Z",
      "metadata": {
        "id": 4,
        "metaTitle": "Contact",
        "metaDescription": "Get in touch with our team",
        "twitterCardType": "summary",
        "twitterUsername": null,
        "shareImage": null
      },
      "contentSections": [
        {
          "id": 1,
          "__component": "sections.rich-text",
          "content": "# Get in touch\n\n> This is an example of a page that relies almost entirely on the RichText section. It's useful for blog articles, or content-heavy pages like legal terms.\n\nWe'd love to hear from you.\n\n## Social media\n\n* [Twitter](#)\n* [Twitter](#)\n* [Twitter](#)\n\n## Postal address\n\n404 Headless Street\n__92210__ **Saint Cloud**, *France*\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
        },
        {
          "id": 1,
          "__component": "sections.bottom-actions",
          "title": "Get in touch",
          "buttons": [
            {
              "id": 1,
              "url": "#",
              "newTab": false,
              "text": "Send an email",
              "type": "primary"
            },
            {
              "id": 3,
              "url": "#",
              "newTab": false,
              "text": "DM us on Twitter",
              "type": "secondary"
            }
          ]
        }
      ]
    }
  ]
}


================================================
FILE: packages/templates/corporate/template/data/fr/global.json
================================================
{
  "globalFR": {
    "id": 2,
    "locale": "fr",
    "metaTitleSuffix": "Strapi Corporate",
    "metadata": {
      "id": 5,
      "metaTitle": "Strapi starter for Corporate Sites",
      "metaDescription": "Créer votre site corporate avec Strapi",
      "twitterCardType": "summary",
      "twitterUsername": "strapijs",
      "shareImage": null
    },
    "notificationBanner": {
      "id": 2,
      "text": "Cette page a été crée avec le Strapi starter pour les sites Corporate.\n [Voir les autres starters Strapi](https://strapi.io/starters)",
      "type": "info"
    },
    "navbar": {
      "id": 2,
      "links": [
        {
          "id": 4,
          "url": "/pricing",
          "newTab": false,
          "text": "tarifs"
        },
        {
          "id": 5,
          "url": "/contact",
          "newTab": false,
          "text": "nous contacter"
        }
      ],
      "button": {
        "id": 14,
        "url": "#",
        "newTab": false,
        "text": "S'inscrire",
        "type": "secondary"
      },
      "logo" : null
    },
    "footer": {
      "id": 2,
      "smallText": "© Copyright Mon Entreprise™",
      "columns": [
        {
          "id": 3,
          "title": "Produit",
          "links": [
            {
              "id": 12,
              "url": "#",
              "newTab": false,
              "text": "Fonctionnalités"
            },
            {
              "id": 14,
              "url": "#",
              "newTab": false,
              "text": "S'inscrire"
            }
          ]
        },
        {
          "id": 4,
          "title": "Légal",
          "links": [
            {
              "id": 17,
              "url": "#",
              "newTab": false,
              "text": "Confidentialité"
            },
            {
              "id": 19,
              "url": "#",
              "newTab": false,
              "text": "Mentions légales"
            }
          ]
        },
        {
          "id": 6,
          "title": "Entreprise",
          "links": [
            {
              "id": 20,
              "url": "#",
              "newTab": false,
              "text": "Nous rejoindre"
            },
            {
              "id": 22,
              "url": "#",
              "newTab": false,
              "text": "L'équipe"
            }
          ]
        },
        {
          "id": 8,
          "title": "Réseaux sociaux",
          "links": [
            {
              "id": 23,
              "url": "#",
              "newTab": false,
              "text": "Twitter"
            },
            {
              "id": 26,
              "url": "#",
              "newTab": false,
              "text": "LinkedIn"
            }
          ]
        }
      ],
      "logo": null
    },
    "favicon": null,
    "localizations": [
      {
        "id": 1,
        "locale": "en"
      }
    ]
  }
}


================================================
FILE: packages/templates/corporate/template/data/fr/index.js
================================================
const { globalFR } = require("./global.json");
const { pagesFR } = require("./pages.json");

module.exports = {
  globalFR,
  pagesFR
}

================================================
FILE: packages/templates/corporate/template/data/fr/pages.json
================================================
{
  "pagesFR": [
    {
      "id": 5,
      "slug": "",
      "locale": "fr",
      "localizations": [
        {
          "id": 1,
          "locale": "en"
        }
      ],
      "shortName": "Home",
      "publishedAt":"2021-10-22T08:11:55.490Z",
      "metadata": {
        "id": 6,
        "metaTitle": "Strapi corporate site starter",
        "metaDescription": "Construire un site modifiable avec Strapi",
        "twitterCardType": "summary",
        "twitterUsername": null,
        "shareImage": null
      },
      "contentSections": [
        {
          "id": 2,
          "__component": "sections.hero",
          "title": "La meilleure façon de faire votre site Corporate",
          "label": "Nouveau starter Strapi",
          "description": "Commencer vite avec votre site corporate",
          "smallTextWithLink": "Vous voulez construire votre propre starter? Guide à venir",
          "buttons": [
            {
              "id": 5,
              "url": "https://github.com/strapi/strapi-template-corporate",
              "newTab": false,
              "text": "Commencer",
              "type": "primary"
            },
            {
              "id": 6,
              "url": "https://github.com/strapi/strapi-template-corporate",
              "newTab": true,
              "text": "Voir le code",
              "type": "secondary"
            }
          ],
          "picture": null
        },
        {
          "id": 2,
          "__component": "sections.feature-rows-group",
          "features": [
            {
              "id": 3,
              "title": "Les équipes marketing peuvent maintenant faire leurs propres pages",
              "description": "Grace à une liste pré-construite de blocs UI, les équipes marketing peuvent faire la mise en page exactement comme elles veulent",
              "link": {
                "id": 9,
                "url": "#",
                "newTab": false,
                "text": "Voir la liste de blocs UI"
              },
              "media": null
            },
            {
              "id": 4,
              "title": "Laissez vos développeurs tranquilles",
              "description": "Vous pouvez publier, modifier, et supprimer des pages sans l'aide d'un développeur.  Votre équipe technique peut enfin se concentrer sur d'autre tâches.",
              "link": {
                "id": 10,
                "url": "#",
                "newTab": false,
                "text": "Voir comment créer une page"
              },
              "media": null
            }
          ]
        },
        {
          "id": 2,
          "__component": "sections.feature-columns-group",
          "features": [
            {
              "id": 4,
              "title": "Visualisez vos changments",
              "description": "Grace à un mode preview, vous pouvez voir vos pages avant de les publier.",
              "icon": null
            },
            {
              "id": 5,
              "title": "100% responsive",
              "description": "Ce starter marche sur toutes les tailles d'écrans.",
              "icon": null
            },
            {
              "id": 6,
              "title": "Facile à personnaliser",
              "description": "On utilise Tailwind pour les styles. Vous pouvez changez le thème de votre site sans avoir besoin d'aller dans le code.",
              "icon": null
            }
          ]
        },
        {
          "id": 2,
          "__component": "sections.testimonials-group",
          "title": "Ici, les témoignages des vos clients.",
          "description": "Dans cette partie, vous pouvez mettre en avant vos clients.  Mettez des citations, et montrez les logos des entreprises qui aiment votre produit.",
          "link": {
            "id": 6,
            "url": "#",
            "newTab": false,
            "text": "All testimonials"
          },
          "logos": [
            {
              "id": 4,
              "title": "Strapi",
              "logo": null
            },
            {
              "id": 5,
              "title": "Strapi 2",
              "logo": null
            },
            {
              "id": 6,
              "title": "Strapi 3",
              "logo": null
            }
          ],
          "testimonials": [
            {
              "id": 2,
              "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
              "authorName": "Nom d'un(e) Client(e) ici",
              "authorTitle": "Un(e) Client(e) Satisfait(e)",
              "link": "#",
              "logo": null,
              "picture": null
            }
          ]
        },
        {
          "id": 2,
          "__component": "sections.lead-form",
          "title": "S'inscrire à notre Newsletter",
          "emailPlaceholder": "email@company.com",
          "submitButton": {
            "id": 2,
            "__component": "links.button",
            "text": "S'inscrire",
            "type": "primary"
          },
          "location": "Home Page Bottom"
        },
        {
          "id": 3,
          "__component": "sections.bottom-actions",
          "title": "Start building your website",
          "buttons": [
            {
              "id": 10,
              "url": "https://github.com/strapi/strapi-template-corporate",
              "newTab": false,
              "text": "Commencer",
              "type": "primary"
            },
            {
              "id": 12,
              "url": "https://github.com/strapi/strapi-template-corporate",
              "newTab": false,
              "text": "Voir le code",
              "type": "secondary"
            }
          ]
        }
      ]
    },
    {
      "id": 6,
      "slug": "pricing",
      "locale": "fr",
      "localizations": [
        {
          "id": 2,
          "locale": "en"
        }
      ],
      "shortName": "Pricing",
      "publishedAt":"2021-10-22T08:11:55.490Z",
      "metadata": {
        "id": 8,
        "metaTitle": "Pricing",
        "metaDescription": "Les différentes offres",
        "twitterCardType": "summary",
        "twitterUsername": null,
        "shareImage": null
      },
      "contentSections": [
        {
          "id": 2,
          "__component": "sections.pricing",
          "title": "Tableau de tarifs",
          "plans": [
            {
              "id": 4,
              "name": "Hobby",
              "description": "Parfait pour des projets personnels",
              "isRecommended": null,
              "price": 0,
              "pricePeriod": "toujours",
              "features": [
                {
                  "id": 10,
                  "name": "Voilà une feature"
                },
                {
                  "id": 11,
                  "name": "Une autre"
                },
                {
                  "id": 12,
                  "name": "Encore une autre"
                }
              ]
            },
            {
              "id": 5,
              "name": "Premium",
              "description": "Un plan plus avancé",
              "isRecommended": true,
              "price": 20,
              "pricePeriod": "par mois",
              "features": [
                {
                  "id": 13,
                  "name": "Fonctionnalité 1"
                },
                {
                  "id": 14,
                  "name": "Fonctionnalité 2"
                },
                {
                  "id": 15,
                  "name": "Fonctionnalité 3"
                }
              ]
            },
            {
              "id": 6,
              "name": "Entreprise",
              "description": "Pour les besoin des grands entreprises",
              "isRecommended": null,
              "price": 299,
              "pricePeriod": "par mois",
              "features": [
                {
                  "id": 16,
                  "name": "Fonctionnalité 1"
                },
                {
                  "id": 17,
                  "name": "Fonctionnalité 2"
                },
                {
                  "id": 18,
                  "name": "Fonctionnalité 3"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "id": 7,
      "slug": "secret",
      "locale": "fr",
      "localizations": [
        {
          "id": 3,
          "locale": "en"
        }
      ],
      "shortName": "Secret",
      "metadata": {
        "id": 9,
        "metaTitle": "Page secrète",
        "metaDescription": "Preview-only page",
        "twitterCardType": "summary",
        "twitterUsername": null,
        "shareImage": null
      },
      "contentSections": [
        {
          "id": 3,
          "__component": "sections.rich-text",
          "content": "## Page secrète. \n\n Vous seul pouvez voir cette page en Preview Mode"
        }
      ]
    },
    {
      "id": 8,
      "slug": "contact",
      "locale": "fr",
      "localizations": [
        {
          "id": 4,
          "locale": "en"
        }
      ],
      "shortName": "Contact",
      "publishedAt":"2021-10-22T08:11:55.490Z",
      "metadata": {
        "id": 10,
        "metaTitle": "Nous Contacter",
        "metaDescription": "Contactez notre équipe",
        "twitterCardType": "summary",
        "twitterUsername": null,
        "shareImage": null
      },
      "contentSections": [
        {
          "id": 4,
          "__component": "sections.rich-text",
          "content": "# Contactez nous\n\n> Ceci est un exemple d'une page qui repose presque entièrement sur le composant RichText. Vous pouvez l'utiliser pour des articles de blog, ou pour des pages comportant beaucoup de texte, comme par exemple les conditions d'utilisation.\n\nNous aimerions beaucoup avoir vos retours.\n\n## Social media\n\n* [Twitter](#)\n* [Twitter](#)\n* [Twitter](#)\n\n## Postal address\n\n404 Headless Street\n__92210__ **Saint Cloud**, *France*\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
        },
        {
          "id": 4,
          "__component": "sections.bottom-actions",
          "title": "Get in touch",
          "buttons": [
            {
              "id": 9,
              "url": "#",
              "newTab": false,
              "text": "Envoyer un mail",
              "type": "primary"
            },
            {
              "id": 11,
              "url": "#",
              "newTab": false,
              "text": "DM nous sur Twitter",
              "type": "secondary"
            }
          ]
        }
      ]
    }
  ]
}


================================================
FILE: packages/templates/corporate/template/data/lead-form-submissions.json
================================================
{
  "leadFormSubmissions": [
    {
      "email": "johne@thebeatles.com",
      "status": "seen",
      "location": "Home Page Bottom"
    },
    {
      "email": "paul@thebeatles.com",
      "status": "contacted",
      "location": "Home Page Bottom"
    },
    {
      "email": "george@thebeatles.com",
      "status": "ignored",
      "location": "Home Page Bottom"
    }
  ]
}

================================================
FILE: packages/templates/corporate/template/src/api/.gitkeep
================================================


================================================
FILE: packages/templates/corporate/template/src/api/global/content-types/global/schema.json
================================================
{
  "kind": "singleType",
  "collectionName": "globals",
  "info": {
    "singularName": "global",
    "pluralN
Download .txt
gitextract_ipi637vq/

├── .gitignore
├── LICENSE.txt
├── README.md
├── lerna.json
├── package.json
└── packages/
    ├── starters/
    │   ├── .gitkeep
    │   ├── gatsby-blog/
    │   │   ├── README.md
    │   │   ├── package.json
    │   │   ├── starter/
    │   │   │   ├── .eslintrc.js
    │   │   │   ├── .gitignore
    │   │   │   ├── README.md
    │   │   │   ├── gatsby-browser.js
    │   │   │   ├── gatsby-config.js
    │   │   │   ├── gatsby-node.js
    │   │   │   ├── package.json
    │   │   │   ├── postcss.config.js
    │   │   │   ├── src/
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── article-card.js
    │   │   │   │   │   ├── articles-grid.js
    │   │   │   │   │   ├── block-media.js
    │   │   │   │   │   ├── block-quote.js
    │   │   │   │   │   ├── block-rich-text.js
    │   │   │   │   │   ├── block-slider.js
    │   │   │   │   │   ├── blocks-renderer.js
    │   │   │   │   │   ├── footer.js
    │   │   │   │   │   ├── headings.js
    │   │   │   │   │   ├── layout.js
    │   │   │   │   │   ├── navbar.js
    │   │   │   │   │   └── seo.js
    │   │   │   │   ├── pages/
    │   │   │   │   │   ├── about.js
    │   │   │   │   │   └── index.js
    │   │   │   │   ├── styles/
    │   │   │   │   │   └── global.css
    │   │   │   │   └── templates/
    │   │   │   │       └── article-post.js
    │   │   │   └── tailwind.config.js
    │   │   └── starter.json
    │   ├── gatsby-corporate/
    │   │   └── README.md
    │   ├── next-blog/
    │   │   ├── README.md
    │   │   ├── package.json
    │   │   ├── starter/
    │   │   │   ├── .eslintrc
    │   │   │   ├── .prettierrc
    │   │   │   ├── assets/
    │   │   │   │   └── css/
    │   │   │   │       └── style.css
    │   │   │   ├── components/
    │   │   │   │   ├── articles.js
    │   │   │   │   ├── card.js
    │   │   │   │   ├── image.js
    │   │   │   │   ├── layout.js
    │   │   │   │   ├── nav.js
    │   │   │   │   └── seo.js
    │   │   │   ├── lib/
    │   │   │   │   ├── api.js
    │   │   │   │   └── media.js
    │   │   │   ├── next.config.js
    │   │   │   ├── package.json
    │   │   │   └── pages/
    │   │   │       ├── _app.js
    │   │   │       ├── _document.js
    │   │   │       ├── article/
    │   │   │       │   └── [slug].js
    │   │   │       ├── category/
    │   │   │       │   └── [slug].js
    │   │   │       └── index.js
    │   │   └── starter.json
    │   └── next-corporate/
    │       ├── README.md
    │       ├── package.json
    │       ├── starter/
    │       │   ├── .eslintrc
    │       │   ├── .gitignore
    │       │   ├── README.md
    │       │   ├── components/
    │       │   │   ├── elements/
    │       │   │   │   ├── button-link.js
    │       │   │   │   ├── button.js
    │       │   │   │   ├── custom-link.js
    │       │   │   │   ├── footer.js
    │       │   │   │   ├── image.js
    │       │   │   │   ├── loader.js
    │       │   │   │   ├── mobile-nav-menu.js
    │       │   │   │   ├── navbar.js
    │       │   │   │   ├── notification-banner.js
    │       │   │   │   ├── seo.js
    │       │   │   │   └── video.js
    │       │   │   ├── icons/
    │       │   │   │   └── world.js
    │       │   │   ├── layout.js
    │       │   │   ├── locale-switch.js
    │       │   │   ├── sections/
    │       │   │   │   ├── bottom-actions.js
    │       │   │   │   ├── feature-columns-group.js
    │       │   │   │   ├── feature-rows-group.js
    │       │   │   │   ├── hero.js
    │       │   │   │   ├── large-video.js
    │       │   │   │   ├── lead-form.js
    │       │   │   │   ├── pricing.js
    │       │   │   │   ├── rich-text.js
    │       │   │   │   └── testimonials-group.js
    │       │   │   └── sections.js
    │       │   ├── jsconfig.json
    │       │   ├── next.config.js
    │       │   ├── package.json
    │       │   ├── pages/
    │       │   │   ├── [[...slug]].js
    │       │   │   ├── _app.js
    │       │   │   ├── _document.js
    │       │   │   └── api/
    │       │   │       ├── exit-preview.js
    │       │   │       └── preview.js
    │       │   ├── postcss.config.js
    │       │   ├── public/
    │       │   │   └── .gitkeep
    │       │   ├── styles/
    │       │   │   └── index.css
    │       │   ├── tailwind.config.js
    │       │   └── utils/
    │       │       ├── api.js
    │       │       ├── button.js
    │       │       ├── hooks.js
    │       │       ├── localize.js
    │       │       ├── media.js
    │       │       ├── parse-cookies.js
    │       │       └── types.js
    │       └── starter.json
    └── templates/
        ├── .gitkeep
        ├── blog/
        │   ├── README.md
        │   ├── package.json
        │   ├── template/
        │   │   ├── data/
        │   │   │   └── data.json
        │   │   └── src/
        │   │       ├── api/
        │   │       │   ├── .gitkeep
        │   │       │   ├── about/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── about/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── about.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── about.js
        │   │       │   │   └── services/
        │   │       │   │       └── about.js
        │   │       │   ├── article/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── article/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── article.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── article.js
        │   │       │   │   └── services/
        │   │       │   │       └── article.js
        │   │       │   ├── author/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── author/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── author.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── author.js
        │   │       │   │   └── services/
        │   │       │   │       └── author.js
        │   │       │   ├── category/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── category/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── category.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── category.js
        │   │       │   │   └── services/
        │   │       │   │       └── category.js
        │   │       │   └── global/
        │   │       │       ├── content-types/
        │   │       │       │   └── global/
        │   │       │       │       └── schema.json
        │   │       │       ├── controllers/
        │   │       │       │   └── global.js
        │   │       │       ├── routes/
        │   │       │       │   └── global.js
        │   │       │       └── services/
        │   │       │           └── global.js
        │   │       ├── bootstrap.js
        │   │       ├── components/
        │   │       │   └── shared/
        │   │       │       ├── media.json
        │   │       │       ├── quote.json
        │   │       │       ├── rich-text.json
        │   │       │       ├── seo.json
        │   │       │       └── slider.json
        │   │       ├── extensions/
        │   │       │   └── .gitkeep
        │   │       └── index.js
        │   └── template.json
        ├── corporate/
        │   ├── README.md
        │   ├── package.json
        │   ├── template/
        │   │   ├── data/
        │   │   │   ├── data.js
        │   │   │   ├── en/
        │   │   │   │   ├── global.json
        │   │   │   │   ├── index.js
        │   │   │   │   └── pages.json
        │   │   │   ├── fr/
        │   │   │   │   ├── global.json
        │   │   │   │   ├── index.js
        │   │   │   │   └── pages.json
        │   │   │   └── lead-form-submissions.json
        │   │   └── src/
        │   │       ├── api/
        │   │       │   ├── .gitkeep
        │   │       │   ├── global/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── global/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── global.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── global.js
        │   │       │   │   └── services/
        │   │       │   │       └── global.js
        │   │       │   ├── lead-form-submission/
        │   │       │   │   ├── content-types/
        │   │       │   │   │   └── lead-form-submission/
        │   │       │   │   │       └── schema.json
        │   │       │   │   ├── controllers/
        │   │       │   │   │   └── lead-form-submission.js
        │   │       │   │   ├── routes/
        │   │       │   │   │   └── lead-form-submission.js
        │   │       │   │   └── services/
        │   │       │   │       └── lead-form-submission.js
        │   │       │   └── page/
        │   │       │       ├── content-types/
        │   │       │       │   └── page/
        │   │       │       │       └── schema.json
        │   │       │       ├── controllers/
        │   │       │       │   └── page.js
        │   │       │       ├── routes/
        │   │       │       │   └── page.js
        │   │       │       └── services/
        │   │       │           └── page.js
        │   │       ├── bootstrap.js
        │   │       ├── components/
        │   │       │   ├── elements/
        │   │       │   │   ├── feature-column.json
        │   │       │   │   ├── feature-row.json
        │   │       │   │   ├── feature.json
        │   │       │   │   ├── footer-section.json
        │   │       │   │   ├── logos.json
        │   │       │   │   ├── notification-banner.json
        │   │       │   │   ├── plan.json
        │   │       │   │   └── testimonial.json
        │   │       │   ├── layout/
        │   │       │   │   ├── footer.json
        │   │       │   │   └── navbar.json
        │   │       │   ├── links/
        │   │       │   │   ├── button-link.json
        │   │       │   │   ├── button.json
        │   │       │   │   └── link.json
        │   │       │   ├── meta/
        │   │       │   │   └── metadata.json
        │   │       │   └── sections/
        │   │       │       ├── bottom-actions.json
        │   │       │       ├── feature-columns-group.json
        │   │       │       ├── feature-rows-group.json
        │   │       │       ├── hero.json
        │   │       │       ├── large-video.json
        │   │       │       ├── lead-form.json
        │   │       │       ├── pricing.json
        │   │       │       ├── rich-text.json
        │   │       │       └── testimonials-group.json
        │   │       └── index.js
        │   └── template.json
        └── ecommerce/
            ├── README.md
            ├── package.json
            ├── template/
            │   ├── data/
            │   │   └── data.js
            │   └── src/
            │       ├── api/
            │       │   ├── .gitkeep
            │       │   ├── category/
            │       │   │   ├── content-types/
            │       │   │   │   └── category/
            │       │   │   │       └── schema.json
            │       │   │   ├── controllers/
            │       │   │   │   └── category.js
            │       │   │   ├── routes/
            │       │   │   │   └── category.js
            │       │   │   └── services/
            │       │   │       └── category.js
            │       │   └── product/
            │       │       ├── content-types/
            │       │       │   └── product/
            │       │       │       └── schema.json
            │       │       ├── controllers/
            │       │       │   └── product.js
            │       │       ├── routes/
            │       │       │   └── product.js
            │       │       └── services/
            │       │           └── product.js
            │       ├── bootstrap.js
            │       ├── components/
            │       │   └── custom/
            │       │       └── custom-field.json
            │       └── index.js
            └── template.json
Download .txt
SYMBOL INDEX (61 symbols across 21 files)

FILE: packages/starters/next-blog/starter/lib/api.js
  function getStrapiURL (line 8) | function getStrapiURL(path = "") {
  function fetchAPI (line 21) | async function fetchAPI(path, urlParamsObject = {}, options = {}) {

FILE: packages/starters/next-blog/starter/lib/media.js
  function getStrapiMedia (line 3) | function getStrapiMedia(media) {

FILE: packages/starters/next-blog/starter/pages/_document.js
  class MyDocument (line 3) | class MyDocument extends Document {
    method render (line 4) | render() {

FILE: packages/starters/next-blog/starter/pages/article/[slug].js
  function getStaticPaths (line 61) | async function getStaticPaths() {
  function getStaticProps (line 74) | async function getStaticProps({ params }) {

FILE: packages/starters/next-blog/starter/pages/category/[slug].js
  function getStaticPaths (line 25) | async function getStaticPaths() {
  function getStaticProps (line 38) | async function getStaticProps({ params }) {

FILE: packages/starters/next-blog/starter/pages/index.js
  function getStaticProps (line 21) | async function getStaticProps() {

FILE: packages/starters/next-corporate/starter/pages/[[...slug]].js
  function getStaticPaths (line 45) | async function getStaticPaths(context) {
  function getStaticProps (line 74) | async function getStaticProps(context) {

FILE: packages/starters/next-corporate/starter/pages/_document.js
  class MyDocument (line 3) | class MyDocument extends Document {
    method render (line 4) | render() {

FILE: packages/starters/next-corporate/starter/pages/api/exit-preview.js
  function exit (line 3) | async function exit(req, res) {

FILE: packages/starters/next-corporate/starter/utils/api.js
  function getStrapiURL (line 3) | function getStrapiURL(path) {
  function fetchAPI (line 16) | async function fetchAPI(path, urlParamsObject = {}, options = {}) {
  function getPageData (line 50) | async function getPageData({ slug, locale, preview }) {
  function getGlobalData (line 260) | async function getGlobalData(locale) {

FILE: packages/starters/next-corporate/starter/utils/button.js
  function getButtonAppearance (line 3) | function getButtonAppearance(type, background) {

FILE: packages/starters/next-corporate/starter/utils/hooks.js
  function useLockBodyScroll (line 4) | function useLockBodyScroll() {
  function useOnClickOutside (line 17) | function useOnClickOutside(ref, handler) {

FILE: packages/starters/next-corporate/starter/utils/localize.js
  function getLocalizedPage (line 3) | async function getLocalizedPage(targetLocale, pageContext) {
  function localizePath (line 11) | function localizePath(page) {
  function getLocalizedPaths (line 23) | function getLocalizedPaths(page) {

FILE: packages/starters/next-corporate/starter/utils/media.js
  function getStrapiMedia (line 1) | function getStrapiMedia(url) {

FILE: packages/starters/next-corporate/starter/utils/parse-cookies.js
  function parseCookies (line 3) | function parseCookies(req) {

FILE: packages/templates/blog/template/src/bootstrap.js
  function isFirstRun (line 15) | async function isFirstRun() {
  function setPublicPermissions (line 26) | async function setPublicPermissions(newPermissions) {
  function getFileSizeInBytes (line 53) | function getFileSizeInBytes(filePath) {
  function getFileData (line 59) | function getFileData(fileName) {
  function uploadFile (line 74) | async function uploadFile(file, name) {
  function createEntry (line 91) | async function createEntry({ model, entry }) {
  function checkFileExistsBeforeUpload (line 102) | async function checkFileExistsBeforeUpload(files) {
  function updateBlocks (line 131) | async function updateBlocks(blocks) {
  function importArticles (line 161) | async function importArticles() {
  function importGlobal (line 179) | async function importGlobal() {
  function importAbout (line 197) | async function importAbout() {
  function importCategories (line 211) | async function importCategories() {
  function importAuthors (line 217) | async function importAuthors() {
  function importSeedData (line 231) | async function importSeedData() {

FILE: packages/templates/blog/template/src/index.js
  method register (line 11) | register(/*{ strapi }*/) {}

FILE: packages/templates/corporate/template/src/bootstrap.js
  function isFirstRun (line 5) | async function isFirstRun() {
  function setPublicPermissions (line 16) | async function setPublicPermissions(newPermissions) {
  function getFileSizeInBytes (line 43) | function getFileSizeInBytes(filePath) {
  function getFileData (line 49) | function getFileData(fileName) {
  function createEntry (line 66) | async function createEntry(model, entry, files) {
  function importPages (line 104) | async function importPages(pages) {
  function importGlobal (line 178) | async function importGlobal() {
  function importLeadFormSubmissionData (line 193) | async function importLeadFormSubmissionData() {
  function importSeedData (line 199) | async function importSeedData() {

FILE: packages/templates/corporate/template/src/index.js
  method bootstrap (line 6) | async bootstrap() {

FILE: packages/templates/ecommerce/template/src/bootstrap.js
  function setPublicPermissions (line 10) | async function setPublicPermissions(newPermissions) {
  function isFirstRun (line 37) | async function isFirstRun() {
  function getFileSizeInBytes (line 48) | function getFileSizeInBytes(filePath) {
  function getFileData (line 54) | function getFileData(fileName) {
  function createEntry (line 71) | async function createEntry({ model, entry, files }) {
  function importCategories (line 109) | async function importCategories() {
  function importProducts (line 117) | async function importProducts() {
  function importSeedData (line 132) | async function importSeedData() {

FILE: packages/templates/ecommerce/template/src/index.js
  method bootstrap (line 6) | async bootstrap() {
Condensed preview — 204 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (255K chars).
[
  {
    "path": ".gitignore",
    "chars": 3180,
    "preview": "\n# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,visualstudiocode\n# Edit at https://www."
  },
  {
    "path": "LICENSE.txt",
    "chars": 1063,
    "preview": "MIT License\n\nCopyright (c) 2021 Strapi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "README.md",
    "chars": 859,
    "preview": "> [!WARNING]\n> This repository is only compatible with Strapi v4 version<br/>\n> The most recent information can be found"
  },
  {
    "path": "lerna.json",
    "chars": 154,
    "preview": "{\n  \"packages\": [\n    \"packages/templates/*\",\n    \"packages/starters/*\"\n  ],\n  \"npmClient\": \"yarn\",\n  \"useWorkspaces\": t"
  },
  {
    "path": "package.json",
    "chars": 549,
    "preview": "{\n  \"name\": \"@strapi/starters-and-templates\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"description\": \"All Strapi temp"
  },
  {
    "path": "packages/starters/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/starters/gatsby-blog/README.md",
    "chars": 1578,
    "preview": "# Strapi Starter Gatsby Blog\n\nGatsby starter for creating a blog with Strapi.\n\nThis starter allows you to try Strapi wit"
  },
  {
    "path": "packages/starters/gatsby-blog/package.json",
    "chars": 759,
    "preview": "{\n  \"name\": \"@strapi/starter-gatsby-blog\",\n  \"version\": \"1.0.7\",\n  \"description\": \"Strapi blog starter with Gatsby\",\n  \""
  },
  {
    "path": "packages/starters/gatsby-blog/starter/.eslintrc.js",
    "chars": 335,
    "preview": "module.exports = {\n  globals: {\n    __PATH_PREFIX__: true,\n  },\n  extends: [\"react-app\", \"prettier\"],\n  plugins: [\"prett"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/.gitignore",
    "chars": 78,
    "preview": "node_modules/\n.cache/\npublic\n.env\n.env.production\n.env.local\n.env.development\n"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/README.md",
    "chars": 1900,
    "preview": "<p align=\"center\">\n  <a href=\"https://www.gatsbyjs.com/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starte"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/gatsby-browser.js",
    "chars": 33,
    "preview": "import \"./src/styles/global.css\"\n"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/gatsby-config.js",
    "chars": 1529,
    "preview": "require(\"dotenv\").config({\n  path: `.env.${process.env.NODE_ENV}`,\n})\n\nmodule.exports = {\n  plugins: [\n    \"gatsby-plugi"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/gatsby-node.js",
    "chars": 850,
    "preview": "const path = require(\"path\")\n\nexports.createPages = async ({ graphql, actions, reporter }) => {\n  const { createPage } ="
  },
  {
    "path": "packages/starters/gatsby-blog/starter/package.json",
    "chars": 1283,
    "preview": "{\n  \"name\": \"my-gatsby-blog\",\n  \"version\": \"1.0.7\",\n  \"private\": true,\n  \"description\": \"Strapi Gatsby Blog\",\n  \"author\""
  },
  {
    "path": "packages/starters/gatsby-blog/starter/postcss.config.js",
    "chars": 82,
    "preview": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n}\n"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/article-card.js",
    "chars": 990,
    "preview": "import React from \"react\"\nimport { Link, graphql } from \"gatsby\"\nimport { GatsbyImage, getImage } from \"gatsby-plugin-im"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/articles-grid.js",
    "chars": 344,
    "preview": "import React from \"react\"\nimport ArticleCard from \"./article-card\"\n\nconst ArticlesGrid = ({ articles }) => {\n  return (\n"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/block-media.js",
    "chars": 446,
    "preview": "import React from \"react\"\nimport { GatsbyImage, getImage } from \"gatsby-plugin-image\"\n\nconst BlockMedia = ({ data }) => "
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/block-quote.js",
    "chars": 451,
    "preview": "import React from \"react\"\n\nconst BlockQuote = ({ data }) => {\n  return (\n    <div className=\"py-6\">\n      <blockquote cl"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/block-rich-text.js",
    "chars": 297,
    "preview": "import React from \"react\"\n\nconst BlockRichText = ({ data }) => {\n  return (\n    <div className=\"prose mx-auto py-8\">\n   "
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/block-slider.js",
    "chars": 736,
    "preview": "import React from \"react\"\nimport { GatsbyImage, getImage } from \"gatsby-plugin-image\"\nimport Slider from \"react-slick\"\ni"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/blocks-renderer.js",
    "chars": 1709,
    "preview": "import React from \"react\"\nimport { graphql } from \"gatsby\"\nimport BlockRichText from \"./block-rich-text\"\nimport BlockMed"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/footer.js",
    "chars": 306,
    "preview": "import React from \"react\"\n\nconst Footer = () => {\n  const currentYear = new Date().getFullYear()\n\n  return (\n    <footer"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/headings.js",
    "chars": 346,
    "preview": "import React from \"react\"\n\nconst Headings = ({ title, description }) => {\n  return (\n    <header className=\"container mt"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/layout.js",
    "chars": 349,
    "preview": "import React from \"react\"\nimport Footer from \"./footer\"\nimport Navbar from \"./navbar\"\n\nconst Layout = ({ children }) => "
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/navbar.js",
    "chars": 527,
    "preview": "import { Link } from \"gatsby\"\nimport React from \"react\"\n\nconst Navbar = () => {\n  return (\n    <header className=\"bg-pri"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/components/seo.js",
    "chars": 2230,
    "preview": "import React from \"react\"\nimport { Helmet } from \"react-helmet\"\nimport { useStaticQuery, graphql } from \"gatsby\"\n\nconst "
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/pages/about.js",
    "chars": 739,
    "preview": "import React from \"react\"\nimport { useStaticQuery, graphql } from \"gatsby\"\nimport Layout from \"../components/layout\"\nimp"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/pages/index.js",
    "chars": 840,
    "preview": "import React from \"react\"\nimport { useStaticQuery, graphql } from \"gatsby\"\nimport Layout from \"../components/layout\"\nimp"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/styles/global.css",
    "chars": 59,
    "preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/src/templates/article-post.js",
    "chars": 1418,
    "preview": "import React from \"react\"\nimport { graphql } from \"gatsby\"\nimport { GatsbyImage, getImage } from \"gatsby-plugin-image\"\ni"
  },
  {
    "path": "packages/starters/gatsby-blog/starter/tailwind.config.js",
    "chars": 510,
    "preview": "const colors = require(\"tailwindcss/colors\")\n\nmodule.exports = {\n  content: [\"./src/**/*.{js,jsx,ts,tsx}\"],\n  theme: {\n "
  },
  {
    "path": "packages/starters/gatsby-blog/starter.json",
    "chars": 85,
    "preview": "{\n  \"template\": {\n    \"name\": \"@strapi/template-blog\",\n    \"version\": \"^2.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/starters/gatsby-corporate/README.md",
    "chars": 489,
    "preview": "# Placeholder for Strapi Gatsby corporate starter\n\nThe Strapi team will build this starter soon.\n\nIn the meantime, you c"
  },
  {
    "path": "packages/starters/next-blog/README.md",
    "chars": 1843,
    "preview": "# Strapi Starter Next Blog\n\nNext starter for creating a blog with Strapi.\n\n![screenshot image](./screenshot.png)\n\nThis s"
  },
  {
    "path": "packages/starters/next-blog/package.json",
    "chars": 756,
    "preview": "{\n  \"name\": \"@strapi/starter-next-blog\",\n  \"version\": \"1.0.4\",\n  \"description\": \"Strapi blog starter with Next.js\",\n  \"k"
  },
  {
    "path": "packages/starters/next-blog/starter/.eslintrc",
    "chars": 136,
    "preview": "{\n  \"extends\": [\n    \"next\",\n    \"prettier\"\n  ],\n  \"plugins\": [\n    \"prettier\"\n  ],\n  \"rules\": {\n    \"prettier/prettier\""
  },
  {
    "path": "packages/starters/next-blog/starter/.prettierrc",
    "chars": 106,
    "preview": "{\n  \"printWidth\": 80,\n  \"singleQuote\": false,\n  \"trailingComma\": \"es5\",\n  \"semi\": false,\n  \"tabWidth\": 2\n}"
  },
  {
    "path": "packages/starters/next-blog/starter/assets/css/style.css",
    "chars": 550,
    "preview": "a {\n  text-decoration: none;\n}\n\nh1 {\n  font-family: Staatliches;\n  font-size: 120px;\n}\n\n#category {\n  font-family: Staat"
  },
  {
    "path": "packages/starters/next-blog/starter/components/articles.js",
    "chars": 1058,
    "preview": "import React from \"react\"\nimport Card from \"./card\"\n\nconst Articles = ({ articles }) => {\n  const leftArticlesCount = Ma"
  },
  {
    "path": "packages/starters/next-blog/starter/components/card.js",
    "chars": 753,
    "preview": "import React from \"react\"\nimport Link from \"next/link\"\nimport NextImage from \"./image\"\n\nconst Card = ({ article }) => {\n"
  },
  {
    "path": "packages/starters/next-blog/starter/components/image.js",
    "chars": 533,
    "preview": "import { getStrapiMedia } from \"../lib/media\"\nimport NextImage from \"next/image\"\n\nconst Image = ({ image, style }) => {\n"
  },
  {
    "path": "packages/starters/next-blog/starter/components/layout.js",
    "chars": 164,
    "preview": "import Nav from \"./nav\"\n\nconst Layout = ({ children, categories, seo }) => (\n  <>\n    <Nav categories={categories} />\n  "
  },
  {
    "path": "packages/starters/next-blog/starter/components/nav.js",
    "chars": 907,
    "preview": "import React from \"react\"\nimport Link from \"next/link\"\n\nconst Nav = ({ categories }) => {\n  return (\n    <div>\n      <na"
  },
  {
    "path": "packages/starters/next-blog/starter/components/seo.js",
    "chars": 1528,
    "preview": "import Head from \"next/head\"\nimport { useContext } from \"react\"\nimport { GlobalContext } from \"../pages/_app\"\nimport { g"
  },
  {
    "path": "packages/starters/next-blog/starter/lib/api.js",
    "chars": 1227,
    "preview": "import qs from \"qs\"\n\n/**\n * Get full Strapi URL from path\n * @param {string} path Path of the URL\n * @returns {string} F"
  },
  {
    "path": "packages/starters/next-blog/starter/lib/media.js",
    "chars": 203,
    "preview": "import { getStrapiURL } from \"./api\"\n\nexport function getStrapiMedia(media) {\n  const { url } = media.data.attributes\n  "
  },
  {
    "path": "packages/starters/next-blog/starter/next.config.js",
    "chars": 165,
    "preview": "/**\n * @type {import('next').NextConfig}\n */\nconst nextConfig = {\n  images: {\n    loader: \"default\",\n    domains: [\"loca"
  },
  {
    "path": "packages/starters/next-blog/starter/package.json",
    "chars": 716,
    "preview": "{\n  \"name\": \"my-next-blog\",\n  \"version\": \"1.0.3\",\n  \"private\": true,\n  \"scripts\": {\n    \"develop\": \"next dev\",\n    \"dev\""
  },
  {
    "path": "packages/starters/next-blog/starter/pages/_app.js",
    "chars": 1446,
    "preview": "import App from \"next/app\"\nimport Head from \"next/head\"\nimport \"../assets/css/style.css\"\nimport { createContext } from \""
  },
  {
    "path": "packages/starters/next-blog/starter/pages/_document.js",
    "chars": 1018,
    "preview": "import Document, { Html, Head, Main, NextScript } from \"next/document\"\n\nclass MyDocument extends Document {\n  render() {"
  },
  {
    "path": "packages/starters/next-blog/starter/pages/article/[slug].js",
    "chars": 2569,
    "preview": "import ReactMarkdown from \"react-markdown\"\nimport Moment from \"react-moment\"\nimport { fetchAPI } from \"../../lib/api\"\nim"
  },
  {
    "path": "packages/starters/next-blog/starter/pages/category/[slug].js",
    "chars": 1405,
    "preview": "import Articles from \"../../components/articles\"\nimport { fetchAPI } from \"../../lib/api\"\nimport Layout from \"../../comp"
  },
  {
    "path": "packages/starters/next-blog/starter/pages/index.js",
    "chars": 1114,
    "preview": "import React from \"react\"\nimport Articles from \"../components/articles\"\nimport Layout from \"../components/layout\"\nimport"
  },
  {
    "path": "packages/starters/next-blog/starter.json",
    "chars": 85,
    "preview": "{\n  \"template\": {\n    \"name\": \"@strapi/template-blog\",\n    \"version\": \"^1.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/starters/next-corporate/README.md",
    "chars": 4208,
    "preview": "# Strapi Starter Next Corporate Site\n\nNext starter for creating a corporate site with Strapi.\n\n[View the live demo](http"
  },
  {
    "path": "packages/starters/next-corporate/package.json",
    "chars": 776,
    "preview": "{\n  \"name\": \"@strapi/starter-next-corporate\",\n  \"version\": \"1.0.4\",\n  \"description\": \"Strapi corporate starter with Next"
  },
  {
    "path": "packages/starters/next-corporate/starter/.eslintrc",
    "chars": 300,
    "preview": "{\n  \"extends\": [\n    \"next\",\n    \"prettier\"\n  ],\n  \"plugins\": [\n    \"prettier\"\n  ],\n  \"rules\": {\n    \"prettier/prettier\""
  },
  {
    "path": "packages/starters/next-corporate/starter/.gitignore",
    "chars": 371,
    "preview": ".vscode\n\n# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_mod"
  },
  {
    "path": "packages/starters/next-corporate/starter/README.md",
    "chars": 1529,
    "preview": "# Next frontend\n\nThis frontend relies on Next's [Static Generation](https://nextjs.org/docs/basic-features/pages) using "
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/button-link.js",
    "chars": 1724,
    "preview": "import classNames from \"classnames\"\nimport PropTypes from \"prop-types\"\nimport { buttonLinkPropTypes } from \"utils/types\""
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/button.js",
    "chars": 1725,
    "preview": "import classNames from \"classnames\"\nimport PropTypes from \"prop-types\"\nimport { buttonLinkPropTypes } from \"utils/types\""
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/custom-link.js",
    "chars": 830,
    "preview": "import Link from \"next/link\"\nimport PropTypes from \"prop-types\"\nimport { linkPropTypes } from \"utils/types\"\n\nconst Custo"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/footer.js",
    "chars": 1880,
    "preview": "import PropTypes from \"prop-types\"\nimport { linkPropTypes, mediaPropTypes } from \"utils/types\"\nimport NextImage from \"./"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/image.js",
    "chars": 902,
    "preview": "import { getStrapiMedia } from \"utils/media\"\nimport Image from \"next/image\"\nimport PropTypes from \"prop-types\"\nimport { "
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/loader.js",
    "chars": 740,
    "preview": "import React from \"react\"\n\nconst Loader = () => {\n  return (\n    <svg\n      viewBox=\"0 0 38 38\"\n      className=\"animate"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/mobile-nav-menu.js",
    "chars": 2139,
    "preview": "import PropTypes from \"prop-types\"\nimport { MdClose, MdChevronRight } from \"react-icons/md\"\nimport { mediaPropTypes, lin"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/navbar.js",
    "chars": 3293,
    "preview": "import { useState } from \"react\"\nimport PropTypes from \"prop-types\"\nimport Link from \"next/link\"\nimport { useRouter } fr"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/notification-banner.js",
    "chars": 906,
    "preview": "import Markdown from \"react-markdown\"\nimport classNames from \"classnames\"\nimport { MdClose } from \"react-icons/md\"\n\ncons"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/seo.js",
    "chars": 1580,
    "preview": "import { NextSeo } from \"next-seo\"\nimport PropTypes from \"prop-types\"\nimport { getStrapiMedia } from \"utils/media\"\nimpor"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/elements/video.js",
    "chars": 728,
    "preview": "import PropTypes from \"prop-types\"\nimport { getStrapiMedia } from \"utils/media\"\nimport { mediaPropTypes } from \"utils/ty"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/icons/world.js",
    "chars": 2326,
    "preview": "import React from \"react\"\n\nconst WorldIcon = () => {\n  return (\n    <div className=\"w-4 h-4 mr-2 \">\n      <svg\n        c"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/layout.js",
    "chars": 908,
    "preview": "import { useState } from \"react\"\nimport Navbar from \"./elements/navbar\"\nimport Footer from \"./elements/footer\"\nimport No"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/locale-switch.js",
    "chars": 3216,
    "preview": "import { useEffect, useState, useRef } from \"react\"\nimport { useRouter } from \"next/router\"\nimport PropTypes from \"prop-"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/bottom-actions.js",
    "chars": 660,
    "preview": "import ButtonLink from \"@/components/elements/button-link\"\nimport { getButtonAppearance } from \"utils/button\"\n\nconst Bot"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/feature-columns-group.js",
    "chars": 576,
    "preview": "import NextImage from \"../elements/image\"\n\nconst FeatureColumnsGroup = ({ data }) => {\n  return (\n    <div className=\"co"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/feature-rows-group.js",
    "chars": 1799,
    "preview": "import classNames from \"classnames\"\nimport NextImage from \"../elements/image\"\nimport Video from \"../elements/video\"\nimpo"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/hero.js",
    "chars": 1420,
    "preview": "import Markdown from \"react-markdown\"\nimport { getButtonAppearance } from \"utils/button\"\nimport ButtonLink from \"../elem"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/large-video.js",
    "chars": 572,
    "preview": "import Video from \"../elements/video\"\n\nconst LargeVideo = ({ data }) => {\n  return (\n    <section className=\"container f"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/lead-form.js",
    "chars": 2229,
    "preview": "import { useState } from \"react\"\nimport { fetchAPI } from \"utils/api\"\nimport * as yup from \"yup\"\nimport { Formik, Form, "
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/pricing.js",
    "chars": 1893,
    "preview": "import { MdCheckBox } from \"react-icons/md\"\nimport classNames from \"classnames\"\n\nconst Pricing = ({ data }) => {\n  retur"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/rich-text.js",
    "chars": 344,
    "preview": "import PropTypes from \"prop-types\"\nimport Markdown from \"react-markdown\"\n\nconst RichText = ({ data }) => {\n  return (\n  "
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections/testimonials-group.js",
    "chars": 3132,
    "preview": "import classNames from \"classnames\"\nimport { useState } from \"react\"\nimport NextImage from \"../elements/image\"\nimport Cu"
  },
  {
    "path": "packages/starters/next-corporate/starter/components/sections.js",
    "chars": 2302,
    "preview": "import { useRouter } from \"next/router\"\nimport Hero from \"@/components/sections/hero\"\nimport LargeVideo from \"@/componen"
  },
  {
    "path": "packages/starters/next-corporate/starter/jsconfig.json",
    "chars": 223,
    "preview": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/components/*\": [\n        \"components/*\"\n      ],\n  "
  },
  {
    "path": "packages/starters/next-corporate/starter/next.config.js",
    "chars": 88,
    "preview": "module.exports = {\n  i18n: {\n    locales: ['en', 'fr'],\n    defaultLocale: 'en',\n  },\n}\n"
  },
  {
    "path": "packages/starters/next-corporate/starter/package.json",
    "chars": 1103,
    "preview": "{\n  \"name\": \"my-next-corporate\",\n  \"version\": \"1.0.7\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next\",\n    \"develop"
  },
  {
    "path": "packages/starters/next-corporate/starter/pages/[[...slug]].js",
    "chars": 3197,
    "preview": "import ErrorPage from \"next/error\"\nimport { getPageData, fetchAPI, getGlobalData } from \"utils/api\"\nimport Sections from"
  },
  {
    "path": "packages/starters/next-corporate/starter/pages/_app.js",
    "chars": 2036,
    "preview": "import App from \"next/app\"\nimport Head from \"next/head\"\nimport ErrorPage from \"next/error\"\nimport { useRouter } from \"ne"
  },
  {
    "path": "packages/starters/next-corporate/starter/pages/_document.js",
    "chars": 290,
    "preview": "import Document, { Html, Head, Main, NextScript } from \"next/document\"\n\nexport default class MyDocument extends Document"
  },
  {
    "path": "packages/starters/next-corporate/starter/pages/api/exit-preview.js",
    "chars": 347,
    "preview": "import { redirect } from \"next/dist/next-server/server/api-utils\"\n\nexport default async function exit(req, res) {\n  // E"
  },
  {
    "path": "packages/starters/next-corporate/starter/pages/api/preview.js",
    "chars": 1507,
    "preview": "import { getPageData } from \"utils/api\"\nimport { parseCookies } from \"utils/parse-cookies\"\n\nconst preview = async (req, "
  },
  {
    "path": "packages/starters/next-corporate/starter/postcss.config.js",
    "chars": 186,
    "preview": "module.exports = {\n  plugins: [\n    \"postcss-import\",\n    \"tailwindcss\",\n    \"postcss-flexbugs-fixes\",\n    \"postcss-nest"
  },
  {
    "path": "packages/starters/next-corporate/starter/public/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/starters/next-corporate/starter/styles/index.css",
    "chars": 1218,
    "preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nhtml {\n  font-size: 13px;\n  @apply text-gray-900;\n}\n\n@media "
  },
  {
    "path": "packages/starters/next-corporate/starter/tailwind.config.js",
    "chars": 651,
    "preview": "const { colors } = require(`tailwindcss/defaultTheme`)\n\nmodule.exports = {\n  mode: \"jit\", // see https://tailwindcss.com"
  },
  {
    "path": "packages/starters/next-corporate/starter/utils/api.js",
    "chars": 9397,
    "preview": "import qs from \"qs\"\n\nexport function getStrapiURL(path) {\n  return `${\n    process.env.NEXT_PUBLIC_STRAPI_API_URL || \"ht"
  },
  {
    "path": "packages/starters/next-corporate/starter/utils/button.js",
    "chars": 724,
    "preview": "// Decide what the button will look like based on its type (primary or secondary)\n// and on its background (light or dar"
  },
  {
    "path": "packages/starters/next-corporate/starter/utils/hooks.js",
    "chars": 1085,
    "preview": "import { useEffect } from 'react'\n\n// Got from https://usehooks.com/useLockBodyScroll/\nexport function useLockBodyScroll"
  },
  {
    "path": "packages/starters/next-corporate/starter/utils/localize.js",
    "chars": 786,
    "preview": "import { fetchAPI } from \"./api\"\n\nexport async function getLocalizedPage(targetLocale, pageContext) {\n  const localizati"
  },
  {
    "path": "packages/starters/next-corporate/starter/utils/media.js",
    "chars": 380,
    "preview": "export function getStrapiMedia(url) {\n  if (url == null) {\n    return null\n  }\n\n  // Return the full URL if the media is"
  },
  {
    "path": "packages/starters/next-corporate/starter/utils/parse-cookies.js",
    "chars": 139,
    "preview": "import cookie from \"cookie\"\n\nexport function parseCookies(req) {\n  return cookie.parse(req ? req.headers.cookie || '' : "
  },
  {
    "path": "packages/starters/next-corporate/starter/utils/types.js",
    "chars": 734,
    "preview": "import PropTypes from \"prop-types\"\n\nexport const linkPropTypes = PropTypes.shape({\n  id: PropTypes.oneOfType([PropTypes."
  },
  {
    "path": "packages/starters/next-corporate/starter.json",
    "chars": 90,
    "preview": "{\n  \"template\": {\n    \"name\": \"@strapi/template-corporate\",\n    \"version\": \"^1.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/templates/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/templates/blog/README.md",
    "chars": 651,
    "preview": "# strapi-template-blog\n\nA Strapi template to create Strapi projects pre-configured for blog apps.\n\n## Usage\n\n```bash\n# U"
  },
  {
    "path": "packages/templates/blog/package.json",
    "chars": 746,
    "preview": "{\n  \"name\": \"@strapi/template-blog\",\n  \"version\": \"2.0.5\",\n  \"description\": \"Strapi blog template\",\n  \"keywords\": [\n    "
  },
  {
    "path": "packages/templates/blog/template/data/data.json",
    "chars": 13399,
    "preview": "{\n  \"global\": {\n    \"siteName\": \"Strapi Blog\",\n    \"defaultSeo\": {\n      \"metaTitle\": \"Page\",\n      \"metaDescription\": \""
  },
  {
    "path": "packages/templates/blog/template/src/api/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/templates/blog/template/src/api/about/content-types/about/schema.json",
    "chars": 549,
    "preview": "{\n  \"kind\": \"singleType\",\n  \"collectionName\": \"abouts\",\n  \"info\": {\n    \"singularName\": \"about\",\n    \"pluralName\": \"abou"
  },
  {
    "path": "packages/templates/blog/template/src/api/about/controllers/about.js",
    "chars": 175,
    "preview": "'use strict';\n\n/**\n *  about controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nmodu"
  },
  {
    "path": "packages/templates/blog/template/src/api/about/routes/about.js",
    "chars": 163,
    "preview": "'use strict';\n\n/**\n * about router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.expor"
  },
  {
    "path": "packages/templates/blog/template/src/api/about/services/about.js",
    "chars": 166,
    "preview": "'use strict';\n\n/**\n * about service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule.exp"
  },
  {
    "path": "packages/templates/blog/template/src/api/article/content-types/article/schema.json",
    "chars": 1163,
    "preview": "{\n  \"kind\": \"collectionType\",\n  \"collectionName\": \"articles\",\n  \"info\": {\n    \"singularName\": \"article\",\n    \"pluralName"
  },
  {
    "path": "packages/templates/blog/template/src/api/article/controllers/article.js",
    "chars": 181,
    "preview": "'use strict';\n\n/**\n *  article controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nmo"
  },
  {
    "path": "packages/templates/blog/template/src/api/article/routes/article.js",
    "chars": 169,
    "preview": "'use strict';\n\n/**\n * article router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.exp"
  },
  {
    "path": "packages/templates/blog/template/src/api/article/services/article.js",
    "chars": 172,
    "preview": "'use strict';\n\n/**\n * article service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule.e"
  },
  {
    "path": "packages/templates/blog/template/src/api/author/content-types/author/schema.json",
    "chars": 732,
    "preview": "{\n  \"kind\": \"collectionType\",\n  \"collectionName\": \"authors\",\n  \"info\": {\n    \"singularName\": \"author\",\n    \"pluralName\":"
  },
  {
    "path": "packages/templates/blog/template/src/api/author/controllers/author.js",
    "chars": 178,
    "preview": "'use strict';\n\n/**\n *  author controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nmod"
  },
  {
    "path": "packages/templates/blog/template/src/api/author/routes/author.js",
    "chars": 166,
    "preview": "'use strict';\n\n/**\n * author router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.expo"
  },
  {
    "path": "packages/templates/blog/template/src/api/author/services/author.js",
    "chars": 169,
    "preview": "'use strict';\n\n/**\n * author service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule.ex"
  },
  {
    "path": "packages/templates/blog/template/src/api/category/content-types/category/schema.json",
    "chars": 615,
    "preview": "{\n  \"kind\": \"collectionType\",\n  \"collectionName\": \"categories\",\n  \"info\": {\n    \"singularName\": \"category\",\n    \"pluralN"
  },
  {
    "path": "packages/templates/blog/template/src/api/category/controllers/category.js",
    "chars": 184,
    "preview": "'use strict';\n\n/**\n *  category controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nm"
  },
  {
    "path": "packages/templates/blog/template/src/api/category/routes/category.js",
    "chars": 172,
    "preview": "'use strict';\n\n/**\n * category router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.ex"
  },
  {
    "path": "packages/templates/blog/template/src/api/category/services/category.js",
    "chars": 175,
    "preview": "'use strict';\n\n/**\n * category service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule."
  },
  {
    "path": "packages/templates/blog/template/src/api/global/content-types/global/schema.json",
    "chars": 744,
    "preview": "{\n  \"kind\": \"singleType\",\n  \"collectionName\": \"globals\",\n  \"info\": {\n    \"singularName\": \"global\",\n    \"pluralName\": \"gl"
  },
  {
    "path": "packages/templates/blog/template/src/api/global/controllers/global.js",
    "chars": 178,
    "preview": "'use strict';\n\n/**\n *  global controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nmod"
  },
  {
    "path": "packages/templates/blog/template/src/api/global/routes/global.js",
    "chars": 166,
    "preview": "'use strict';\n\n/**\n * global router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.expo"
  },
  {
    "path": "packages/templates/blog/template/src/api/global/services/global.js",
    "chars": 169,
    "preview": "'use strict';\n\n/**\n * global service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule.ex"
  },
  {
    "path": "packages/templates/blog/template/src/bootstrap.js",
    "chars": 6788,
    "preview": "\"use strict\";\n\nconst fs = require(\"fs-extra\");\nconst path = require(\"path\");\nconst mime = require(\"mime-types\");\nconst s"
  },
  {
    "path": "packages/templates/blog/template/src/components/shared/media.json",
    "chars": 312,
    "preview": "{\n  \"collectionName\": \"components_shared_media\",\n  \"info\": {\n    \"displayName\": \"Media\",\n    \"icon\": \"file-video\"\n  },\n "
  },
  {
    "path": "packages/templates/blog/template/src/components/shared/quote.json",
    "chars": 243,
    "preview": "{\n  \"collectionName\": \"components_shared_quotes\",\n  \"info\": {\n    \"displayName\": \"Quote\",\n    \"icon\": \"indent\"\n  },\n  \"o"
  },
  {
    "path": "packages/templates/blog/template/src/components/shared/rich-text.json",
    "chars": 240,
    "preview": "{\n  \"collectionName\": \"components_shared_rich_texts\",\n  \"info\": {\n    \"displayName\": \"Rich text\",\n    \"icon\": \"align-jus"
  },
  {
    "path": "packages/templates/blog/template/src/components/shared/seo.json",
    "chars": 496,
    "preview": "{\n  \"collectionName\": \"components_shared_seos\",\n  \"info\": {\n    \"name\": \"Seo\",\n    \"icon\": \"allergies\",\n    \"displayName"
  },
  {
    "path": "packages/templates/blog/template/src/components/shared/slider.json",
    "chars": 330,
    "preview": "{\n  \"collectionName\": \"components_shared_sliders\",\n  \"info\": {\n    \"displayName\": \"Slider\",\n    \"icon\": \"address-book\",\n"
  },
  {
    "path": "packages/templates/blog/template/src/extensions/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/templates/blog/template/src/index.js",
    "chars": 504,
    "preview": "\"use strict\";\nconst bootstrap = require(\"./bootstrap\");\n\nmodule.exports = {\n  /**\n   * An asynchronous register function"
  },
  {
    "path": "packages/templates/blog/template.json",
    "chars": 182,
    "preview": "{\n  \"package\": {\n    \"dependencies\": {\n      \"@strapi/plugin-graphql\": \"^4.0.5\",\n      \"fs-extra\": \"^10.0.0\",\n      \"lod"
  },
  {
    "path": "packages/templates/corporate/README.md",
    "chars": 531,
    "preview": "# strapi-template-corporate\n\nA Strapi template to create Strapi projects pre-configured for corporate apps.\n\n## Usage\n\n`"
  },
  {
    "path": "packages/templates/corporate/package.json",
    "chars": 761,
    "preview": "{\n  \"name\": \"@strapi/template-corporate\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Strapi corporate template\",\n  \"keyword"
  },
  {
    "path": "packages/templates/corporate/template/data/data.js",
    "chars": 273,
    "preview": "const { global, pages } = require(\"./en\");\nconst { globalFR, pagesFR } = require(\"./fr\");\nconst { leadFormSubmissions } "
  },
  {
    "path": "packages/templates/corporate/template/data/en/global.json",
    "chars": 2841,
    "preview": "{\n  \"global\": {\n    \"id\": 1,\n    \"locale\": \"en\",\n    \"metaTitleSuffix\": \"Strapi Corporate\",\n    \"metadata\": {\n      \"id\""
  },
  {
    "path": "packages/templates/corporate/template/data/en/index.js",
    "chars": 127,
    "preview": "const { global } = require(\"./global.json\");\nconst { pages } = require(\"./pages.json\");\n\nmodule.exports = {\n  global,\n  "
  },
  {
    "path": "packages/templates/corporate/template/data/en/pages.json",
    "chars": 10987,
    "preview": "{\n  \"pages\": [\n    {\n      \"id\": 1,\n      \"slug\": \"\",\n      \"locale\": \"en\",\n      \"localizations\": [\n        {\n         "
  },
  {
    "path": "packages/templates/corporate/template/data/fr/global.json",
    "chars": 2900,
    "preview": "{\n  \"globalFR\": {\n    \"id\": 2,\n    \"locale\": \"fr\",\n    \"metaTitleSuffix\": \"Strapi Corporate\",\n    \"metadata\": {\n      \"i"
  },
  {
    "path": "packages/templates/corporate/template/data/fr/index.js",
    "chars": 135,
    "preview": "const { globalFR } = require(\"./global.json\");\nconst { pagesFR } = require(\"./pages.json\");\n\nmodule.exports = {\n  global"
  },
  {
    "path": "packages/templates/corporate/template/data/fr/pages.json",
    "chars": 11248,
    "preview": "{\n  \"pagesFR\": [\n    {\n      \"id\": 5,\n      \"slug\": \"\",\n      \"locale\": \"fr\",\n      \"localizations\": [\n        {\n       "
  },
  {
    "path": "packages/templates/corporate/template/data/lead-form-submissions.json",
    "chars": 380,
    "preview": "{\n  \"leadFormSubmissions\": [\n    {\n      \"email\": \"johne@thebeatles.com\",\n      \"status\": \"seen\",\n      \"location\": \"Hom"
  },
  {
    "path": "packages/templates/corporate/template/src/api/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/templates/corporate/template/src/api/global/content-types/global/schema.json",
    "chars": 1590,
    "preview": "{\n  \"kind\": \"singleType\",\n  \"collectionName\": \"globals\",\n  \"info\": {\n    \"singularName\": \"global\",\n    \"pluralName\": \"gl"
  },
  {
    "path": "packages/templates/corporate/template/src/api/global/controllers/global.js",
    "chars": 178,
    "preview": "'use strict';\n\n/**\n *  global controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nmod"
  },
  {
    "path": "packages/templates/corporate/template/src/api/global/routes/global.js",
    "chars": 166,
    "preview": "'use strict';\n\n/**\n * global router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.expo"
  },
  {
    "path": "packages/templates/corporate/template/src/api/global/services/global.js",
    "chars": 169,
    "preview": "'use strict';\n\n/**\n * global service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule.ex"
  },
  {
    "path": "packages/templates/corporate/template/src/api/lead-form-submission/content-types/lead-form-submission/schema.json",
    "chars": 601,
    "preview": "{\n  \"kind\": \"collectionType\",\n  \"collectionName\": \"lead_form_submissions\",\n  \"info\": {\n    \"singularName\": \"lead-form-su"
  },
  {
    "path": "packages/templates/corporate/template/src/api/lead-form-submission/controllers/lead-form-submission.js",
    "chars": 220,
    "preview": "'use strict';\n\n/**\n *  lead-form-submission controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').f"
  },
  {
    "path": "packages/templates/corporate/template/src/api/lead-form-submission/routes/lead-form-submission.js",
    "chars": 208,
    "preview": "'use strict';\n\n/**\n * lead-form-submission router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories"
  },
  {
    "path": "packages/templates/corporate/template/src/api/lead-form-submission/services/lead-form-submission.js",
    "chars": 211,
    "preview": "'use strict';\n\n/**\n * lead-form-submission service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factori"
  },
  {
    "path": "packages/templates/corporate/template/src/api/page/content-types/page/schema.json",
    "chars": 1383,
    "preview": "{\n  \"kind\": \"collectionType\",\n  \"collectionName\": \"pages\",\n  \"info\": {\n    \"singularName\": \"page\",\n    \"pluralName\": \"pa"
  },
  {
    "path": "packages/templates/corporate/template/src/api/page/controllers/page.js",
    "chars": 172,
    "preview": "'use strict';\n\n/**\n *  page controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nmodul"
  },
  {
    "path": "packages/templates/corporate/template/src/api/page/routes/page.js",
    "chars": 160,
    "preview": "'use strict';\n\n/**\n * page router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.export"
  },
  {
    "path": "packages/templates/corporate/template/src/api/page/services/page.js",
    "chars": 163,
    "preview": "'use strict';\n\n/**\n * page service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule.expo"
  },
  {
    "path": "packages/templates/corporate/template/src/bootstrap.js",
    "chars": 6575,
    "preview": "const fs = require(\"fs\");\nconst { pages, globals, leadFormSubmissions } = require(\"../data/data\");\nconst set = require(\""
  },
  {
    "path": "packages/templates/corporate/template/src/components/elements/feature-column.json",
    "chars": 492,
    "preview": "{\n  \"collectionName\": \"components_slices_feature_columns\",\n  \"info\": {\n    \"name\": \"FeatureColumn\",\n    \"displayName\": \""
  },
  {
    "path": "packages/templates/corporate/template/src/components/elements/feature-row.json",
    "chars": 609,
    "preview": "{\n  \"collectionName\": \"components_slices_feature_rows\",\n  \"info\": {\n    \"name\": \"FeatureRow\",\n    \"displayName\": \"Featur"
  },
  {
    "path": "packages/templates/corporate/template/src/components/elements/feature.json",
    "chars": 236,
    "preview": "{\n  \"collectionName\": \"components_elements_features\",\n  \"info\": {\n    \"name\": \"feature\",\n    \"displayName\": \"Feature\",\n "
  },
  {
    "path": "packages/templates/corporate/template/src/components/elements/footer-section.json",
    "chars": 367,
    "preview": "{\n  \"collectionName\": \"components_links_footer_sections\",\n  \"info\": {\n    \"name\": \"FooterSection\",\n    \"displayName\": \"F"
  },
  {
    "path": "packages/templates/corporate/template/src/components/elements/logos.json",
    "chars": 369,
    "preview": "{\n  \"collectionName\": \"components_elements_logos\",\n  \"info\": {\n    \"name\": \"logos\",\n    \"displayName\": \"Logos\",\n    \"ico"
  },
  {
    "path": "packages/templates/corporate/template/src/components/elements/notification-banner.json",
    "chars": 420,
    "preview": "{\n  \"collectionName\": \"components_elements_notification_banners\",\n  \"info\": {\n    \"name\": \"NotificationBanner\",\n    \"dis"
  },
  {
    "path": "packages/templates/corporate/template/src/components/elements/plan.json",
    "chars": 551,
    "preview": "{\n  \"collectionName\": \"components_elements_plans\",\n  \"info\": {\n    \"name\": \"plan\",\n    \"displayName\": \"Pricing plan\",\n  "
  },
  {
    "path": "packages/templates/corporate/template/src/components/elements/testimonial.json",
    "chars": 675,
    "preview": "{\n  \"collectionName\": \"components_slices_testimonials\",\n  \"info\": {\n    \"name\": \"Testimonial\",\n    \"displayName\": \"Testi"
  },
  {
    "path": "packages/templates/corporate/template/src/components/layout/footer.json",
    "chars": 504,
    "preview": "{\n  \"collectionName\": \"components_layout_footers\",\n  \"info\": {\n    \"name\": \"Footer\",\n    \"displayName\": \"Footer\",\n    \"i"
  },
  {
    "path": "packages/templates/corporate/template/src/components/layout/navbar.json",
    "chars": 571,
    "preview": "{\n  \"collectionName\": \"components_layout_navbars\",\n  \"info\": {\n    \"name\": \"Navbar\",\n    \"displayName\": \"Navbar\",\n    \"i"
  },
  {
    "path": "packages/templates/corporate/template/src/components/links/button-link.json",
    "chars": 488,
    "preview": "{\n  \"collectionName\": \"components_links_buttons\",\n  \"info\": {\n    \"name\": \"Button-link\",\n    \"displayName\": \"Button link"
  },
  {
    "path": "packages/templates/corporate/template/src/components/links/button.json",
    "chars": 371,
    "preview": "{\n  \"collectionName\": \"components_links_simple_buttons\",\n  \"info\": {\n    \"name\": \"Button\",\n    \"displayName\": \"Button\",\n"
  },
  {
    "path": "packages/templates/corporate/template/src/components/links/link.json",
    "chars": 400,
    "preview": "{\n  \"collectionName\": \"components_links_links\",\n  \"info\": {\n    \"name\": \"Link\",\n    \"displayName\": \"Link\",\n    \"icon\": \""
  },
  {
    "path": "packages/templates/corporate/template/src/components/meta/metadata.json",
    "chars": 731,
    "preview": "{\n  \"collectionName\": \"components_meta_metadata\",\n  \"info\": {\n    \"name\": \"Metadata\",\n    \"displayName\": \"Metadata\",\n   "
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/bottom-actions.json",
    "chars": 375,
    "preview": "{\n  \"collectionName\": \"components_slices_bottom_actions\",\n  \"info\": {\n    \"name\": \"BottomActions\",\n    \"displayName\": \"B"
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/feature-columns-group.json",
    "chars": 352,
    "preview": "{\n  \"collectionName\": \"components_slices_feature_columns_groups\",\n  \"info\": {\n    \"name\": \"FeatureColumnsGroup\",\n    \"di"
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/feature-rows-group.json",
    "chars": 331,
    "preview": "{\n  \"collectionName\": \"components_slices_feature_rows_groups\",\n  \"info\": {\n    \"name\": \"FeatureRowsGroup\",\n    \"displayN"
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/hero.json",
    "chars": 638,
    "preview": "{\n  \"collectionName\": \"components_slices_heroes\",\n  \"info\": {\n    \"name\": \"Hero\",\n    \"displayName\": \"Hero\",\n    \"icon\":"
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/large-video.json",
    "chars": 583,
    "preview": "{\n  \"collectionName\": \"components_slices_large_videos\",\n  \"info\": {\n    \"name\": \"LargeVideo\",\n    \"displayName\": \"Large "
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/lead-form.json",
    "chars": 476,
    "preview": "{\n  \"collectionName\": \"components_sections_lead_forms\",\n  \"info\": {\n    \"name\": \"Lead form\",\n    \"displayName\": \"Lead fo"
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/pricing.json",
    "chars": 345,
    "preview": "{\n  \"collectionName\": \"components_sections_pricings\",\n  \"info\": {\n    \"name\": \"Pricing\",\n    \"displayName\": \"Pricing\",\n "
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/rich-text.json",
    "chars": 244,
    "preview": "{\n  \"collectionName\": \"components_sections_rich_texts\",\n  \"info\": {\n    \"name\": \"RichText\",\n    \"displayName\": \"Rich tex"
  },
  {
    "path": "packages/templates/corporate/template/src/components/sections/testimonials-group.json",
    "chars": 657,
    "preview": "{\n  \"collectionName\": \"components_slices_testimonials_groups\",\n  \"info\": {\n    \"name\": \"TestimonialsGroup\",\n    \"display"
  },
  {
    "path": "packages/templates/corporate/template/src/index.js",
    "chars": 127,
    "preview": "\"use strict\";\n\nconst boostrap = require('./bootstrap');\n\nmodule.exports = {\n  async bootstrap() {\n    await boostrap();\n"
  },
  {
    "path": "packages/templates/corporate/template.json",
    "chars": 122,
    "preview": "{\n  \"package\": {\n    \"dependencies\": {\n      \"@strapi/plugin-graphql\": \"^4.0.0\",\n      \"lodash.set\": \"^4.3.2\"\n    }\n  }\n"
  },
  {
    "path": "packages/templates/ecommerce/README.md",
    "chars": 527,
    "preview": "# strapi-template-ecommerce\n\nA Strapi template to create Strapi projects pre-configured for e-commerce apps.\n\n## Usage\n\n"
  },
  {
    "path": "packages/templates/ecommerce/package.json",
    "chars": 761,
    "preview": "{\n  \"name\": \"@strapi/template-ecommerce\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Strapi ecommerce template\",\n  \"keyword"
  },
  {
    "path": "packages/templates/ecommerce/template/data/data.js",
    "chars": 13494,
    "preview": "module.exports = {\n  categories: [\n    {\n      name: \"Back\",\n      slug: \"back\",\n    },\n    {\n      name: \"Front\",\n     "
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/category/content-types/category/schema.json",
    "chars": 559,
    "preview": "{\n  \"kind\": \"collectionType\",\n  \"collectionName\": \"categories\",\n  \"info\": {\n    \"singularName\": \"category\",\n    \"pluralN"
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/category/controllers/category.js",
    "chars": 184,
    "preview": "'use strict';\n\n/**\n *  category controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nm"
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/category/routes/category.js",
    "chars": 172,
    "preview": "'use strict';\n\n/**\n * category router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.ex"
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/category/services/category.js",
    "chars": 175,
    "preview": "'use strict';\n\n/**\n * category service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule."
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/product/content-types/product/schema.json",
    "chars": 1108,
    "preview": "{\n  \"kind\": \"collectionType\",\n  \"collectionName\": \"products\",\n  \"info\": {\n    \"singularName\": \"product\",\n    \"pluralName"
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/product/controllers/product.js",
    "chars": 181,
    "preview": "'use strict';\n\n/**\n *  product controller\n */\n\nconst { createCoreController } = require('@strapi/strapi').factories;\n\nmo"
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/product/routes/product.js",
    "chars": 169,
    "preview": "'use strict';\n\n/**\n * product router.\n */\n\nconst { createCoreRouter } = require('@strapi/strapi').factories;\n\nmodule.exp"
  },
  {
    "path": "packages/templates/ecommerce/template/src/api/product/services/product.js",
    "chars": 172,
    "preview": "'use strict';\n\n/**\n * product service.\n */\n\nconst { createCoreService } = require('@strapi/strapi').factories;\n\nmodule.e"
  }
]

// ... and 4 more files (download for full content)

About this extraction

This page contains the full source code of the strapi/starters-and-templates GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 204 files (214.7 KB), approximately 63.2k tokens, and a symbol index with 61 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!