diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.env.local.sample b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.env.local.sample
new file mode 100644
index 0000000000..04519cd4e1
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.env.local.sample
@@ -0,0 +1,25 @@
+
+#create environment file name as .env.local
+#and place following configuration data.
+
+CONTENTSTACK_API_KEY=YOUR_API_KEY
+CONTENTSTACK_DELIVERY_TOKEN=YOUR_DELIVERY_TOKEN
+CONTENTSTACK_ENVIRONMENT=YOUR_PUBLISHING_ENVIRONMENT
+
+# For live preview
+CONTENTSTACK_MANAGEMENT_TOKEN=
+CONTENTSTACK_API_HOST=api.contentstack.io
+CONTENTSTACK_APP_HOST=app.contentstack.com
+CONTENTSTACK_LIVE_PREVIEW=true
+CONTENTSTACK_LIVE_EDIT_TAGS=false
+
+#site-map
+NEXT_PUBLIC_HOSTED_URL=http://localhost:3000
+# Requires host url for sitemap. Localhost:3000 is set as default value
+
+# For Live preview default value is to true to disable live preview set CONTENTSTACK_LIVE_PREVIEW=false
+# For live edit tags default value is set to false to enable live edit tag set CONTENTSTACK_LIVE_EDIT_TAGS=true
+# For NA region add CONTENTSTACK_APP_HOST=app.contentstack.com
+# For EU region add CONTENTSTACK_APP_HOST=eu-app.contentstack.com
+
+# For setting custom host add CONTENTSTACK_API_HOST=for(NA: api.contentstack.io, EU: eu-api.contentstack.com)
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.eslintrc.json b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.eslintrc.json
new file mode 100644
index 0000000000..afdeb5bba3
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.eslintrc.json
@@ -0,0 +1,26 @@
+{
+ "env": {
+ "browser": true,
+ "es2021": true
+ },
+ "extends": [
+ "eslint:recommended",
+ "plugin:react/recommended",
+ "extends: next/core-web-vitals"
+ ],
+ "parserOptions": {
+ "ecmaFeatures": {
+ "jsx": true
+ },
+ "ecmaVersion": 12,
+ "sourceType": "module"
+ },
+ "plugins": [
+ "react"
+ ],
+ "rules": {
+ "react/prop-types":0,
+ "no-undef":"off",
+ "no-unused-vars": "off"
+ }
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/codeql-analysis.yml b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000000..61cd42c405
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,70 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: '*'
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: '*'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'javascript' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+
+ # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
+
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v2
+
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+
+ # If the Autobuild fails above, remove it and uncomment the following three lines.
+ # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
+
+ # - run: |
+ # echo "Run, Build Application using script"
+ # ./location_of_script_within_repo/buildscript.sh
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sast-scan.yml b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sast-scan.yml
new file mode 100644
index 0000000000..21f14859d3
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sast-scan.yml
@@ -0,0 +1,14 @@
+name: SAST Scan
+on:
+ push:
+ branches:
+ - '*'
+ pull_request:
+ types: [opened, synchronize, reopened]
+jobs:
+ security:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Horusec Scan
+ run: docker run -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd):/src horuszup/horusec-cli:latest horusec start -p /src -P $(pwd)
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sca-monitor.yml b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sca-monitor.yml
new file mode 100644
index 0000000000..294eab3e1d
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sca-monitor.yml
@@ -0,0 +1,13 @@
+name: Source Composition Analysis Monitor
+on: push
+jobs:
+ security:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Run Snyk to check for vulnerabilities
+ uses: snyk/actions/node@master
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
+ with:
+ command: monitor
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sca-scan.yml b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sca-scan.yml
new file mode 100644
index 0000000000..525e2860cc
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/sca-scan.yml
@@ -0,0 +1,16 @@
+name: Source Composition Analysis Scan
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ types: [opened, synchronize, reopened]
+jobs:
+ security:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Run Snyk to check for vulnerabilities
+ uses: snyk/actions/node@master
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/secrets-scan.yml b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/secrets-scan.yml
new file mode 100644
index 0000000000..71d6503763
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.github/workflows/secrets-scan.yml
@@ -0,0 +1,14 @@
+name: Secrets Scan
+on:
+ push:
+ branches:
+ - '*'
+ pull_request:
+ types: [opened, synchronize, reopened]
+jobs:
+ security:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Gittyleaks
+ uses: gupy-io/gittyleaks-action@v0.1
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.gitignore b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.gitignore
new file mode 100644
index 0000000000..737d872109
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/.gitignore
@@ -0,0 +1,35 @@
+# 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
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# local env files
+.env*.local
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/CODEOWNERS b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/CODEOWNERS
new file mode 100644
index 0000000000..ba5226b9a3
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/CODEOWNERS
@@ -0,0 +1,2 @@
+
+* @contentstack/security-admin @contentstack/ecosystem-admin
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/LICENSE b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/LICENSE
new file mode 100644
index 0000000000..2bba21a5aa
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Contentstack
+
+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.
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/README.md b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/README.md
new file mode 100644
index 0000000000..a380173a88
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/README.md
@@ -0,0 +1,32 @@
+[![Contentstack Logo](/public/contentstack-readme-logo.png)](https://www.contentstack.com/)
+
+
+# Build a Starter Website with Next.js and Contentstack
+
+About Contentstack: Contentstack is a headless CMS with an API-first approach that puts content at the centre. It is designed to simplify the process of publication by separating code from content.
+
+About this project: Next.js is a minimalistic framework for server-rendered React applications.This guide will help you create a starter website built on top of Next.js with minimal steps.
+
+
+
+![Contentstack-Nextjs-starter-app](/public/starter-app.png)
+
+## Live Demo
+
+You can check the [live demo](https://contentstack-nextjs-starter-app.vercel.app) to get first-hand experience of the website.
+
+
+## Tutorial
+
+We have created an in-depth tutorial on how you can create a Next.js starter website using Contentstack's Node.js SDK and its fetch content from Contentstack.
+
+[Build Website using Next.js and Contentstack](https://www.contentstack.com/docs/developers/sample-apps/build-a-starter-website-using-next-js-and-contentstack/)
+
+
+**More Resources**
+
+Read Contentstack [docs](https://www.contentstack.com/docs/)
+
+Region support [docs](https://www.contentstack.com/docs/developers/selecting-region-in-contentstack-starter-apps)
+
+Learn about [Next.js](https://learnnextjs.com/)
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/SECURITY.md b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/SECURITY.md
new file mode 100644
index 0000000000..b5fe070ed3
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/SECURITY.md
@@ -0,0 +1,27 @@
+## Security
+
+Contentstack takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations.
+
+If you believe you have found a security vulnerability in any Contentstack-owned repository, please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Send email to [security@contentstack.com](mailto:security@contentstack.com).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message.
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+ * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+ * Full paths of source file(s) related to the manifestation of the issue
+ * The location of the affected source code (tag/branch/commit or direct URL)
+ * Any special configuration required to reproduce the issue
+ * Step-by-step instructions to reproduce the issue
+ * Proof-of-concept or exploit code (if possible)
+ * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+[https://www.contentstack.com/trust/](https://www.contentstack.com/trust/)
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/about-section-bucket.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/about-section-bucket.tsx
new file mode 100644
index 0000000000..2ef308c75c
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/about-section-bucket.tsx
@@ -0,0 +1,82 @@
+import React from 'react';
+import parse from 'html-react-parser';
+import { Action,Image } from '../typescript/action';
+
+type AdditionalParam = {
+ title_h2?: string;
+ title_h3?: string;
+ description?: string;
+}
+
+type Bucket = {
+ title_h3: string;
+ description: string;
+ icon: Image;
+ $: AdditionalParam;
+ url: string;
+}
+
+type BucketsList = {
+ title_h3: string;
+ description: string;
+ url: string;
+ call_to_action: Action;
+ icon: Image;
+ $: AdditionalParam;
+}
+
+type BucketProps = {
+ title_h2: string;
+ buckets:[BucketsList];
+ $: AdditionalParam;
+}
+
+export default function AboutSectionBucket({ sectionWithBuckets }: {sectionWithBuckets:BucketProps}) {
+ function bucketContent(bucket: Bucket, index: number) {
+ return (
+
+ {bucket.icon && (
+
+ )}
+
+
+ {bucket.title_h3 && (
+
{bucket.title_h3}
+ )}
+ {typeof bucket.description === 'string' && (
+
{parse(bucket.description)}
+ )}
+
+
+ );
+ }
+
+ return (
+
+
+ {sectionWithBuckets.title_h2 && (
+
+ {sectionWithBuckets.title_h2}
+
+ )}
+
+
+
+ {sectionWithBuckets?.buckets.map(
+ (bucket, index) => index < 2 && bucketContent(bucket, index)
+ )}
+
+
+ {sectionWithBuckets.buckets.map(
+ (bucket, index) => index >= 2 && bucketContent(bucket, index)
+ )}
+
+
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/archive-relative.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/archive-relative.tsx
new file mode 100644
index 0000000000..682ec5b761
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/archive-relative.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import Link from 'next/link';
+import parse from 'html-react-parser';
+
+type AdditionalParam = {
+ title: string;
+ body: string;
+}
+
+type Blog = {
+ url: string;
+ body: string;
+ title: string;
+ $: AdditionalParam;
+}
+
+type BlogListProps = {
+ blogs: [Blog];
+}
+
+export default function ArchiveRelative({ blogs }: BlogListProps) {
+ return (
+ <>
+ {blogs?.map((blog, idx) => (
+
+
+
+
{blog.title}
+ {typeof blog.body === 'string' && (
+
{parse(blog.body.slice(0, 80))}
+ )}
+
+
+
+ ))}
+ >
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-banner.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-banner.tsx
new file mode 100644
index 0000000000..4cd98313ec
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-banner.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+
+type AdditionalParam = {
+ banner_title:string;
+ banner_description: string;
+ title: {};
+ title_h2: string;
+ body: string;
+ date: string;
+}
+
+type BannerProps = {
+ banner_title:string;
+ banner_description: string;
+ bg_color: string;
+ $: AdditionalParam;
+}
+
+export default function BlogBanner({ blogBanner }: {blogBanner : BannerProps}) {
+ return (
+
+
+ {blogBanner.banner_title && (
+
+ {blogBanner.banner_title}
+
+ )}
+
+ {blogBanner.banner_description && (
+
+ {blogBanner.banner_description}
+
+ )}
+
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-list.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-list.tsx
new file mode 100644
index 0000000000..cec2042e5f
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-list.tsx
@@ -0,0 +1,82 @@
+import React from 'react';
+import moment from 'moment';
+import parse from 'html-react-parser';
+import Link from 'next/link';
+import { Image } from "../typescript/action";
+
+type AdditionalParam = {
+ banner_title:string;
+ banner_description: string;
+ title: {};
+ title_h2: string;
+ body: string;
+ date: string;
+}
+
+type Author = {
+ title: string;
+ $: AdditionalParam;
+}
+
+
+type BloglistProps = {
+ body: string;
+ url: string;
+ featured_image: Image;
+ title: string;
+ date: string;
+ author: [Author];
+ $: AdditionalParam;
+}
+
+function BlogList({ bloglist }: { bloglist: BloglistProps }) {
+ let body: string = bloglist.body && bloglist.body.substr(0, 300);
+ const stringLength = body.lastIndexOf(' ');
+ body = `${body.substr(0, Math.min(body.length, stringLength))}...`;
+ return (
+
+ {bloglist.featured_image && (
+
+
+
+
+
+ )}
+
+ {bloglist.title && (
+
+
+ {bloglist.title}
+
+
+ )}
+
+
+ {moment(bloglist.date).format('ddd, MMM D YYYY')}
+
+ ,{" "}
+
+ {bloglist.author[0].title}
+
+
+
{parse(body)}
+ {bloglist.url ? (
+
+
+ {'Read more -->'}
+
+
+ ) : (
+ ''
+ )}
+
+
+ );
+}
+
+export default BlogList;
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-section.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-section.tsx
new file mode 100644
index 0000000000..4938e11e17
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/blog-section.tsx
@@ -0,0 +1,88 @@
+import React from 'react';
+import Link from 'next/link';
+import parse from 'html-react-parser';
+import { Image } from "../typescript/action";
+
+type AdditionalParam = {
+ banner_title:string;
+ banner_description: string;
+ title: {};
+ title_h2: string;
+ body: string;
+ date: string;
+}
+
+type Article = {
+ href: string;
+ title: string;
+ $: AdditionalParam;
+}
+
+type FeaturedBlog = {
+ title: string;
+ featured_image: Image;
+ body: string;
+ url: string;
+ $: AdditionalParam;
+}
+
+type FeaturedBlogData = {
+ title_h2: string;
+ view_articles: Article;
+ featured_blogs: [FeaturedBlog]
+ $: AdditionalParam;
+}
+
+type FeaturedBlogProps = {
+ fromBlog: FeaturedBlogData;
+ }
+
+export default function BlogSection(props: FeaturedBlogProps) {
+
+ const fromBlog = props.fromBlog;
+
+ return (
+
+
+
+ {fromBlog.featured_blogs.map((blog, index) => (
+
+ {blog.featured_image && (
+
+ )}
+
+ {blog.title &&
{blog.title} }
+ {typeof blog.body === 'string' && (
+
{parse(blog.body.slice(0, 300))}
+ )}
+ {blog.url && (
+
+
{'Read More -->'}
+
+ )}
+
+
+ ))}
+
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/card-section.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/card-section.tsx
new file mode 100644
index 0000000000..08fe35b9e5
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/card-section.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import Link from 'next/link';
+import { Action } from "../typescript/action";
+
+type AdditionalParam = {
+ title_h3: string;
+ description: string;
+ }
+
+type Card = {
+ title_h3: string;
+ description: string;
+ call_to_action: Action;
+ $: AdditionalParam;
+ }
+
+type CardProps = {
+ cards: [Card]
+ }
+
+export default function CardSection({ cards }: CardProps) {
+ return (
+
+ {cards?.map((card, index) => (
+
+ {card.title_h3 &&
{card.title_h3} }
+ {card.description &&
{card.description}
}
+
+
+ ))}
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/devtools.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/devtools.tsx
new file mode 100644
index 0000000000..9c2a07aef1
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/devtools.tsx
@@ -0,0 +1,118 @@
+import React, { useState, useEffect } from 'react';
+import dynamic from 'next/dynamic';
+import Tooltip from './tool-tip';
+
+const DynamicReactJson = dynamic(import('react-json-view'), { ssr: false });
+
+function filterObject(inputObject: any) {
+ const unWantedProps = [
+ '_version',
+ 'ACL',
+ '_owner',
+ '_in_progress',
+ 'created_at',
+ 'created_by',
+ 'updated_at',
+ 'updated_by',
+ 'publish_details',
+ ];
+ for (const key in inputObject) {
+ unWantedProps.includes(key) && delete inputObject[key];
+ if (typeof inputObject[key] !== 'object') {
+ continue;
+ }
+ inputObject[key] = filterObject(inputObject[key]);
+ }
+ return inputObject;
+}
+
+const DevTools = ({ response }: any) => {
+ const filteredJson = filterObject(response);
+ const [forceUpdate, setForceUpdate] = useState(0);
+
+ function copyObject(object: any) {
+ navigator.clipboard.writeText(object);
+ setForceUpdate(1);
+ }
+
+ useEffect(() => {
+ if (forceUpdate !== 0) {
+ setTimeout(() => setForceUpdate(0), 300);
+ }
+ }, [forceUpdate]);
+
+ return (
+
+
+
+
+
+ JSON Preview
+
+
copyObject(JSON.stringify(filteredJson))}
+ aria-hidden="true"
+ >
+
+
+
+
+
+
+
+ {response ? (
+
+ {response && (
+
+ )}
+
+ ) : (
+ ''
+ )}
+
+
+
+ Close
+
+
+
+
+
+ );
+};
+export default DevTools;
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/footer.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/footer.tsx
new file mode 100644
index 0000000000..c72d5e66ce
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/footer.tsx
@@ -0,0 +1,124 @@
+import React, { useState, useEffect } from 'react';
+import Link from 'next/link';
+import parse from 'html-react-parser';
+import { onEntryChange } from '../contentstack-sdk';
+import { getFooterRes } from '../helper';
+import Skeleton from 'react-loading-skeleton';
+import { FooterProps, Entry, Links } from "../typescript/layout";
+
+export default function Footer({ footer, entries }: {footer: FooterProps, entries: Entry}) {
+
+ const [getFooter, setFooter] = useState(footer);
+
+ function buildNavigation(ent: Entry, ft: FooterProps) {
+ let newFooter = { ...ft };
+ if (ent.length !== newFooter.navigation.link.length) {
+ ent.forEach((entry) => {
+ const fFound = newFooter?.navigation.link.find(
+ (nlink: Links) => nlink.title === entry.title
+ );
+ if (!fFound) {
+ newFooter.navigation.link?.push({
+ title: entry.title,
+ href: entry.url,
+ $: entry.$,
+ });
+ }
+ });
+ }
+ return newFooter;
+ }
+
+ async function fetchData() {
+ try {
+ if (footer && entries) {
+ const footerRes = await getFooterRes();
+ const newfooter = buildNavigation(entries, footerRes);
+ setFooter(newfooter);
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ useEffect(() => {
+ onEntryChange(() => fetchData());
+ }, [footer]);
+
+ const footerData = getFooter ? getFooter : undefined;
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/header.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/header.tsx
new file mode 100644
index 0000000000..5f07e458e9
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/header.tsx
@@ -0,0 +1,125 @@
+import React, { useState, useEffect } from 'react';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+import parse from 'html-react-parser';
+import Tooltip from './tool-tip';
+import { onEntryChange } from '../contentstack-sdk';
+import { getHeaderRes } from '../helper';
+import Skeleton from 'react-loading-skeleton';
+import { HeaderProps, Entry, NavLinks } from "../typescript/layout";
+
+export default function Header({ header, entries }: {header: HeaderProps, entries: Entry}) {
+
+ const router = useRouter();
+ const [getHeader, setHeader] = useState(header);
+
+ function buildNavigation(ent: Entry, hd: HeaderProps) {
+ let newHeader={...hd};
+ if (ent.length!== newHeader.navigation_menu.length) {
+ ent.forEach((entry) => {
+ const hFound = newHeader?.navigation_menu.find(
+ (navLink: NavLinks) => navLink.label === entry.title
+ );
+ if (!hFound) {
+ newHeader.navigation_menu?.push({
+ label: entry.title,
+ page_reference: [
+ { title: entry.title, url: entry.url, $: entry.$ },
+ ],
+ $:{}
+ });
+ }
+ });
+ }
+ return newHeader
+ }
+
+ async function fetchData() {
+ try {
+ if (header && entries) {
+ const headerRes = await getHeaderRes();
+ const newHeader = buildNavigation(entries,headerRes)
+ setHeader(newHeader);
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ useEffect(() => {
+ if (header && entries) {
+ onEntryChange(() => fetchData());
+ }
+ }, [header]);
+ const headerData = getHeader ? getHeader : undefined;
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/hero-banner.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/hero-banner.tsx
new file mode 100644
index 0000000000..4ac9f2ab0a
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/hero-banner.tsx
@@ -0,0 +1,80 @@
+import React from 'react';
+import Link from 'next/link';
+import { Image, Action } from "../typescript/action";
+
+type AdditionalParam = {
+ banner_title: string;
+ banner_description: string;
+}
+
+type Banner = {
+ bg_color: string;
+ text_color: string;
+ banner_title: string;
+ banner_description: string;
+ call_to_action: Action;
+ banner_image: Image;
+ $: AdditionalParam;
+}
+
+type BannerProps = {
+ banner: Banner;
+}
+
+export default function HeroBanner(props: BannerProps) {
+
+ const banner = props.banner;
+
+ return (
+
+
+ {banner.banner_title && (
+
+ {banner.banner_title}
+
+ )}
+ {banner.banner_description ? (
+
+ {banner?.banner_description}
+
+ ) : (
+ ''
+ )}
+ {banner.call_to_action.title && banner.call_to_action.href ? (
+
+
+ {banner?.call_to_action.title}
+
+
+ ) : (
+ ''
+ )}
+
+ {banner.banner_image ? (
+
+ ) : (
+ ''
+ )}
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/layout.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/layout.tsx
new file mode 100644
index 0000000000..86931fbcd4
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/layout.tsx
@@ -0,0 +1,74 @@
+import React, { useState, useEffect } from 'react';
+import Header from './header';
+import Footer from './footer';
+import DevTools from './devtools';
+import { HeaderProps, FooterProps, PageProps, Posts, ChilderenProps, Entry, NavLinks, Links } from "../typescript/layout";
+
+export default function Layout({
+ header,
+ footer,
+ page,
+ blogPost,
+ blogList,
+ entries,
+ children,
+}: { header: HeaderProps, footer: FooterProps, page: PageProps, blogPost: Posts, blogList: Posts, entries: Entry, children: ChilderenProps }) {
+
+ const [getLayout, setLayout] = useState({ header, footer });
+ const jsonObj: any = { header, footer };
+ page && (jsonObj.page = page);
+ blogPost && (jsonObj.blog_post = blogPost);
+ blogList && (jsonObj.blog_post = blogList);
+
+ function buildNavigation(ent: Entry, hd: HeaderProps, ft: FooterProps) {
+ let newHeader = { ...hd };
+ let newFooter = { ...ft };
+ if (ent.length !== newHeader.navigation_menu.length) {
+ ent.forEach((entry) => {
+ const hFound = newHeader?.navigation_menu.find(
+ (navLink: NavLinks) => navLink.label === entry.title
+ );
+ if (!hFound) {
+ newHeader.navigation_menu?.push({
+ label: entry.title,
+ page_reference: [
+ { title: entry.title, url: entry.url, $: entry.$ },
+ ],
+ $: {},
+ });
+ }
+ const fFound = newFooter?.navigation.link.find(
+ (nlink: Links) => nlink.title === entry.title
+ );
+ if (!fFound) {
+ newFooter.navigation.link?.push({
+ title: entry.title,
+ href: entry.url,
+ $: entry.$,
+ });
+ }
+ });
+ }
+ return [newHeader, newFooter];
+ }
+
+ useEffect(() => {
+ if (footer && header && entries) {
+ const [newHeader, newFooter] = buildNavigation(entries, header, footer);
+ setLayout({ header: newHeader, footer: newFooter });
+ }
+ }, [header, footer]);
+
+ return (
+ <>
+ {header ? : ''}
+
+ <>
+ {children}
+ {Object.keys(jsonObj).length && }
+ >
+
+ {footer ? : ''}
+ >
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/render-components.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/render-components.tsx
new file mode 100644
index 0000000000..9281b0c35c
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/render-components.tsx
@@ -0,0 +1,89 @@
+import React from 'react';
+
+import Section from './section';
+import HeroBanner from './hero-banner';
+import BlogBanner from './blog-banner';
+import CardSection from './card-section';
+import TeamSection from './team-section';
+import BlogSection from './blog-section';
+import SectionBucket from './section-bucket';
+import AboutSectionBucket from './about-section-bucket';
+import SectionWithHtmlCode from './section-with-html-code';
+import { RenderProps } from "../typescript/component";
+
+export default function RenderComponents(props: RenderProps) {
+ const { pageComponents, blogPost, entryUid, contentTypeUid, locale } = props;
+ return (
+
+ {pageComponents?.map((component, key: number) => {
+ if (component.hero_banner) {
+ return blogPost ? (
+
+ ) : (
+
+ );
+ }
+ if (component.section) {
+ return (
+
+ );
+ }
+ if (component.section_with_buckets) {
+ return component.section_with_buckets.bucket_tabular ? (
+
+ ) : (
+
+ );
+ }
+ if (component.from_blog) {
+ return (
+
+ );
+ }
+ if (component.section_with_cards) {
+ return (
+
+ );
+ }
+ if (component.section_with_html_code) {
+ return (
+
+ );
+ }
+ if (component.our_team) {
+ return (
+
+ );
+ }
+ })}
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section-bucket.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section-bucket.tsx
new file mode 100644
index 0000000000..9c8dd48ffe
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section-bucket.tsx
@@ -0,0 +1,77 @@
+import React from 'react';
+import Link from 'next/link';
+import parse from 'html-react-parser';
+import { Image, Action } from "../typescript/action";
+
+type AdditionalParam = {
+ title: string;
+ title_h2: string;
+ title_h3: string;
+ description: string;
+ html_code: string;
+ designation: string;
+ name: string;
+}
+
+type Buckets = {
+ title_h3: string;
+ description: string;
+ call_to_action: Action;
+ icon: Image;
+ $: AdditionalParam;
+}
+
+export type BucketProps = {
+ title_h2: string;
+ description: string;
+ buckets: [Buckets];
+ $: AdditionalParam;
+}
+
+export default function SectionBucket({ section }: {section: BucketProps}) {
+ return (
+
+
+ {section.title_h2 && (
+
{section.title_h2}
+ )}
+ {section.description && (
+
{section.description}
+ )}
+
+
+ {section.buckets?.map((bucket, index) => (
+
+ {bucket.icon && (
+
+ )}
+
+ {bucket.title_h3 ? (
+
{bucket.title_h3}
+ ) : (
+ ''
+ )}
+ {typeof bucket.description === 'string' && (
+
{parse(bucket.description)}
+ )}
+ {bucket.call_to_action.title ? (
+
+ {`${bucket.call_to_action.title} -->`}
+
+ ) : (
+ ''
+ )}
+
+ ))}
+
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section-with-html-code.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section-with-html-code.tsx
new file mode 100644
index 0000000000..9dbec58260
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section-with-html-code.tsx
@@ -0,0 +1,60 @@
+import parse from 'html-react-parser';
+
+type AdditionalParam = {
+ title: string;
+ title_h2: string;
+ title_h3: string;
+ description: string;
+ html_code: string;
+ designation: string;
+ name: string;
+}
+
+type ObjectProps = {
+ html_code_alignment: string;
+ title: string;
+ description: string;
+ html_code: string;
+ $: AdditionalParam;
+}
+
+export default function SectionWithHtmlCode({ embedCode }: {embedCode : ObjectProps}) {
+ if (embedCode.html_code_alignment === 'Left') {
+ return (
+
+
+ {embedCode.title && (
+
{embedCode.title}
+ )}
+ {typeof embedCode.description === 'string' && (
+
+ {parse(embedCode.description)}
+
+ )}
+
+
+ {typeof embedCode.html_code === 'string' && (
+
{parse(embedCode.html_code)}
+ )}
+
+
+ );
+ }
+ return (
+
+
+ {typeof embedCode.html_code === 'string' && (
+
{parse(embedCode.html_code)}
+ )}
+
+
+ {embedCode.title ?
{embedCode.title} : ''}
+ {typeof embedCode.description === 'string' && (
+
+ {parse(embedCode.description)}
+
+ )}
+
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section.tsx
new file mode 100644
index 0000000000..464a329026
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/section.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import Link from 'next/link';
+import { Image, Action } from "../typescript/action";
+
+type AdditionalParam = {
+ title: string;
+ title_h2: string;
+ title_h3: string;
+ description: string;
+ html_code: string;
+ designation: string;
+ name: string;
+}
+
+type SectionProps = {
+ title_h2: String;
+ description: string;
+ call_to_action: Action;
+ image: Image;
+ image_alignment: string;
+ $: AdditionalParam;
+}
+
+export default function Section({ section }: {section : SectionProps}) {
+ function contentSection(key: any) {
+ return (
+
+ {section.title_h2 && (
+
{section.title_h2}
+ )}
+ {section.description && (
+
{section.description}
+ )}
+ {section.call_to_action.title && section.call_to_action.href ? (
+
+
+ {section.call_to_action.title}
+
+
+ ) : (
+ ''
+ )}
+
+ );
+ }
+
+ function imageContent(key: any) {
+ return (
+
+ );
+ }
+ return (
+
+ {section.image_alignment === 'Left'
+ ? [imageContent('key-image'), contentSection('key-contentstection')]
+ : [contentSection('key-contentstection'), imageContent('key-image')]}
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/team-section.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/team-section.tsx
new file mode 100644
index 0000000000..cf7209dfae
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/team-section.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import { Image } from "../typescript/action";
+
+type AdditionalParam = {
+ title: string;
+ title_h2: string;
+ title_h3: string;
+ description: string;
+ html_code: string;
+ designation: string;
+ name: string;
+}
+
+type Employee = {
+ image: Image;
+ name: string;
+ designation: string;
+ $: AdditionalParam;
+}
+
+type TeamProps = {
+ title_h2: string;
+ description: string;
+ $: AdditionalParam;
+ employees: [Employee];
+}
+
+export default function TeamSection({ ourTeam }: {ourTeam : TeamProps}) {
+ return (
+
+
+ {ourTeam.title_h2 && (
+
{ourTeam.title_h2}
+ )}
+ {ourTeam.description ? (
+
{ourTeam.description}
+ ) : (
+ ''
+ )}
+
+
+ {ourTeam.employees?.map((employee, index) => (
+
+ {employee.image && (
+
+ )}
+
+ {employee.name &&
{employee.name} }
+ {employee.designation && (
+
{employee.designation}
+ )}
+
+
+ ))}
+
+
+ );
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/tool-tip.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/tool-tip.tsx
new file mode 100644
index 0000000000..75d11fea54
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/components/tool-tip.tsx
@@ -0,0 +1,50 @@
+import React, { useRef, useEffect, MutableRefObject } from 'react';
+
+type TooltipProps = {
+ children?: JSX.Element|JSX.Element[];
+ content: string;
+ direction: string;
+ status: number;
+ delay: number;
+ dynamic: boolean;
+}
+
+const Tooltip = (props: TooltipProps) => {
+ let timeout: any;
+ const toolTipRef = useRef() as MutableRefObject ;
+
+ const showTip = () => {
+ timeout = setTimeout(() => {
+ toolTipRef.current.style.display = "block";
+ }, props.delay || 400);
+ };
+
+ const hideTip = () => {
+ clearInterval(timeout);
+ toolTipRef.current.style.display = "none";
+ };
+
+ useEffect(() => {
+ if (props.dynamic) {
+ props.status !== 0 && (toolTipRef.current.style.display = "block");
+ timeout = setTimeout(() => {
+ toolTipRef.current.style.display = "none";
+ }, props.delay || 400);
+ }
+ }, [props.content]);
+
+ return (
+
+ {props.children}
+
+ {props.content}
+
+
+ );
+};
+
+export default Tooltip;
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/contentstack-sdk/index.js b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/contentstack-sdk/index.js
new file mode 100644
index 0000000000..40313f5aad
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/contentstack-sdk/index.js
@@ -0,0 +1,112 @@
+import * as contentstack from 'contentstack';
+import * as Utils from '@contentstack/utils';
+
+import ContentstackLivePreview from '@contentstack/live-preview-utils';
+import getConfig from 'next/config';
+
+const { publicRuntimeConfig } = getConfig();
+const envConfig = process.env.CONTENTSTACK_API_KEY
+ ? process.env
+ : publicRuntimeConfig;
+
+const Stack = contentstack.Stack({
+ api_key: envConfig.CONTENTSTACK_API_KEY
+ ? envConfig.CONTENTSTACK_API_KEY
+ : envConfig.NEXT_PUBLIC_CONTENTSTACK_API_KEY,
+ delivery_token: envConfig.CONTENTSTACK_DELIVERY_TOKEN,
+ environment: envConfig.CONTENTSTACK_ENVIRONMENT,
+ region: envConfig.CONTENTSTACK_REGION ? envConfig.CONTENTSTACK_REGION : 'us',
+ live_preview: {
+ enable: true,
+ management_token: envConfig.CONTENTSTACK_MANAGEMENT_TOKEN,
+ host: envConfig.CONTENTSTACK_API_HOST,
+ },
+});
+
+if (envConfig.CONTENTSTACK_API_HOST) {
+ Stack.setHost(envConfig.CONTENTSTACK_API_HOST);
+}
+
+ContentstackLivePreview.init({
+ stackSdk: Stack,
+ clientUrlParams: {
+ host: envConfig.CONTENTSTACK_APP_HOST,
+ },
+ ssr: false,
+});
+
+export const { onEntryChange } = ContentstackLivePreview;
+
+const renderOption = {
+ span: (node, next) => next(node.children),
+};
+
+export default {
+ /**
+ *
+ * fetches all the entries from specific content-type
+ * @param {* content-type uid} contentTypeUid
+ * @param {* reference field name} referenceFieldPath
+ * @param {* Json RTE path} jsonRtePath
+ *
+ */
+ getEntry({ contentTypeUid, referenceFieldPath, jsonRtePath }) {
+ return new Promise((resolve, reject) => {
+ const query = Stack.ContentType(contentTypeUid).Query();
+ if (referenceFieldPath) query.includeReference(referenceFieldPath);
+ query
+ .includeOwner()
+ .toJSON()
+ .find()
+ .then(
+ (result) => {
+ jsonRtePath
+ && Utils.jsonToHTML({
+ entry: result,
+ paths: jsonRtePath,
+ renderOption,
+ });
+ resolve(result);
+ },
+ (error) => {
+ reject(error);
+ },
+ );
+ });
+ },
+
+ /**
+ *fetches specific entry from a content-type
+ *
+ * @param {* content-type uid} contentTypeUid
+ * @param {* url for entry to be fetched} entryUrl
+ * @param {* reference field name} referenceFieldPath
+ * @param {* Json RTE path} jsonRtePath
+ * @returns
+ */
+ getEntryByUrl({
+ contentTypeUid, entryUrl, referenceFieldPath, jsonRtePath,
+ }) {
+ return new Promise((resolve, reject) => {
+ const blogQuery = Stack.ContentType(contentTypeUid).Query();
+ if (referenceFieldPath) blogQuery.includeReference(referenceFieldPath);
+ blogQuery.includeOwner().toJSON();
+ const data = blogQuery.where('url', `${entryUrl}`).find();
+ data.then(
+ (result) => {
+ jsonRtePath
+ && Utils.jsonToHTML({
+ entry: result,
+ paths: jsonRtePath,
+ renderOption,
+ });
+ resolve(result[0]);
+ },
+ (error) => {
+ console.error(error);
+ reject(error);
+ },
+ );
+ });
+ },
+};
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/helper/index.js b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/helper/index.js
new file mode 100644
index 0000000000..9b533789c2
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/helper/index.js
@@ -0,0 +1,79 @@
+import Stack from '../contentstack-sdk';
+import { addEditableTags } from '@contentstack/utils';
+import getConfig from 'next/config';
+
+const { publicRuntimeConfig } = getConfig();
+const envConfig = process.env.CONTENTSTACK_API_KEY
+ ? process.env
+ : publicRuntimeConfig;
+
+const liveEdit = envConfig.CONTENTSTACK_LIVE_EDIT_TAGS === 'true';
+
+export const getHeaderRes = async () => {
+ const response = await Stack.getEntry({
+ contentTypeUid: 'header',
+ referenceFieldPath: ['navigation_menu.page_reference'],
+ jsonRtePath: ['notification_bar.announcement_text'],
+ });
+
+ liveEdit && addEditableTags(response[0][0], 'header', true);
+ return response[0][0];
+};
+
+export const getFooterRes = async () => {
+ const response = await Stack.getEntry({
+ contentTypeUid: 'footer',
+ referenceFieldPath: undefined,
+ jsonRtePath: ['copyright'],
+ });
+ liveEdit && addEditableTags(response[0][0], 'footer', true);
+ return response[0][0];
+};
+
+export const getAllEntries = async () => {
+ const response = await Stack.getEntry({
+ contentTypeUid: 'page',
+ referenceFieldPath: undefined,
+ jsonRtePath: undefined,
+ });
+ liveEdit &&
+ response[0].forEach((entry) => addEditableTags(entry, 'page', true));
+ return response[0];
+};
+
+export const getPageRes = async (entryUrl) => {
+ const response = await Stack.getEntryByUrl({
+ contentTypeUid: 'page',
+ entryUrl,
+ referenceFieldPath: ['page_components.from_blog.featured_blogs'],
+ jsonRtePath: [
+ 'page_components.from_blog.featured_blogs.body',
+ 'page_components.section_with_buckets.buckets.description',
+ 'page_components.section_with_html_code.description',
+ ],
+ });
+ liveEdit && addEditableTags(response[0], 'page', true);
+ return response[0];
+};
+
+export const getBlogListRes = async () => {
+ const response = await Stack.getEntry({
+ contentTypeUid: 'blog_post',
+ referenceFieldPath: ['author', 'related_post'],
+ jsonRtePath: ['body'],
+ });
+ liveEdit &&
+ response[0].forEach((entry) => addEditableTags(entry, 'blog_post', true));
+ return response[0];
+};
+
+export const getBlogPostRes = async (entryUrl) => {
+ const response = await Stack.getEntryByUrl({
+ contentTypeUid: 'blog_post',
+ entryUrl,
+ referenceFieldPath: ['author', 'related_post'],
+ jsonRtePath: ['body', 'related_post.body'],
+ });
+ liveEdit && addEditableTags(response[0], 'blog_post', true);
+ return response[0];
+};
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/next-env.d.ts b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/next-env.d.ts
new file mode 100644
index 0000000000..4f11a03dc6
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/next-env.d.ts
@@ -0,0 +1,5 @@
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/next.config.js b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/next.config.js
new file mode 100644
index 0000000000..ba4251cbe4
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/next.config.js
@@ -0,0 +1,28 @@
+const withPWA = require('next-pwa');
+
+const config = {
+ publicRuntimeConfig: {
+ // Will be available on both server and client
+ CONTENTSTACK_API_KEY: process.env.CONTENTSTACK_API_KEY,
+ CONTENTSTACK_DELIVERY_TOKEN: process.env.CONTENTSTACK_DELIVERY_TOKEN,
+ CONTENTSTACK_ENVIRONMENT: process.env.CONTENTSTACK_ENVIRONMENT,
+ CONTENTSTACK_MANAGEMENT_TOKEN: process.env.CONTENTSTACK_MANAGEMENT_TOKEN,
+ CONTENTSTACK_API_HOST:
+ process.env.CONTENTSTACK_API_HOST || 'api.contentstack.io',
+ CONTENTSTACK_APP_HOST:
+ process.env.CONTENTSTACK_APP_HOST || 'app.contentstack.com',
+ NEXT_PUBLIC_CONTENTSTACK_API_KEY: process.env.CONTENTSTACK_API_KEY,
+ CONTENTSTACK_LIVE_PREVIEW:
+ process.env.NEXT_PUBLIC_CONTENTSTACK_LIVE_PREVIEW || 'true',
+ CONTENTSTACK_LIVE_EDIT_TAGS:
+ process.env.CONTENTSTACK_LIVE_EDIT_TAGS || 'false',
+ },
+ devIndicators: {
+ autoPrerender: false,
+ },
+ pwa: {
+ dest: 'public',
+ },
+};
+module.exports =
+ process.env.NODE_ENV === 'development' ? config : withPWA(config);
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/package.json b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/package.json
new file mode 100644
index 0000000000..14c42a27b0
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "contentstack-nextjs-starter-app",
+ "description": "A starter app for Contentstack and Nextjs",
+ "version": "2.0.0",
+ "private": true,
+ "author": "Contentstack",
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "eslint pages/**/*.jsx"
+ },
+ "dependencies": {
+ "@contentstack/live-preview-utils": "^1.0.1",
+ "@contentstack/utils": "^1.1.1",
+ "contentstack": "^3.15.0",
+ "html-react-parser": "^1.4.6",
+ "moment": "^2.29.2",
+ "next": "12.1.6",
+ "next-pwa": "^5.5.0",
+ "nprogress": "^0.2.0",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2",
+ "react-json-view": "^1.21.3",
+ "react-loading-skeleton": "^3.0.3"
+ },
+ "devDependencies": {
+ "@types/node": "17.0.33",
+ "@types/nprogress": "^0.2.0",
+ "@types/react": "18.0.9",
+ "@types/react-dom": "18.0.4",
+ "eslint": "8.15.0",
+ "eslint-config-next": "12.1.6",
+ "typescript": "4.6.4"
+ }
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/404.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/404.tsx
new file mode 100644
index 0000000000..801fad5d54
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/404.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+
+export default class ErrorPage extends React.Component {
+ render() {
+ return (
+
+
404: Not Found
+
You just hit a route that doesn't exist... the sadness.
+
+ );
+ }
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/[page].tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/[page].tsx
new file mode 100644
index 0000000000..1556941a4e
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/[page].tsx
@@ -0,0 +1,53 @@
+import React, { useState, useEffect } from 'react';
+import { onEntryChange } from '../contentstack-sdk';
+import RenderComponents from '../components/render-components';
+import { getPageRes } from '../helper';
+import Skeleton from 'react-loading-skeleton';
+import { Props } from "../typescript/pages";
+
+export default function Page(props: Props) {
+ const { page, entryUrl } = props;
+ const [getEntry, setEntry] = useState(page);
+
+ async function fetchData() {
+ try {
+ const entryRes = await getPageRes(entryUrl);
+ if (!entryRes) throw new Error('Status code 404');
+ setEntry(entryRes);
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ useEffect(() => {
+ onEntryChange(() => fetchData());
+ }, [page]);
+
+ return getEntry.page_components ? (
+
+ ) : (
+
+ );
+}
+
+export async function getServerSideProps({params}: any) {
+ try {
+ const entryUrl = params.page.includes('/') ? params.page:`/${params.page}`
+ const entryRes = await getPageRes(entryUrl);
+ if (!entryRes) throw new Error('404');
+ return {
+ props: {
+ entryUrl: entryUrl,
+ page: entryRes,
+ },
+ };
+
+ } catch (error) {
+ return { notFound: true };
+ }
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/_app.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/_app.tsx
new file mode 100644
index 0000000000..913966f0b2
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/_app.tsx
@@ -0,0 +1,83 @@
+import App from 'next/app';
+import Head from 'next/head';
+import Router from 'next/router';
+import NProgress from 'nprogress';
+import Layout from '../components/layout';
+import { getHeaderRes, getFooterRes, getAllEntries } from '../helper';
+import 'nprogress/nprogress.css';
+import '../styles/third-party.css';
+import '../styles/style.css';
+import 'react-loading-skeleton/dist/skeleton.css';
+import '@contentstack/live-preview-utils/dist/main.css';
+import { Props } from "../typescript/pages";
+
+
+Router.events.on('routeChangeStart', () => NProgress.start());
+Router.events.on('routeChangeComplete', () => NProgress.done());
+Router.events.on('routeChangeError', () => NProgress.done());
+
+function MyApp(props: Props) {
+ const { Component, pageProps, header, footer, entries } = props;
+ const { page, posts, archivePost, blogPost } = pageProps;
+
+ const metaData = (seo: any) => {
+ const metaArr = [];
+ for (const key in seo) {
+ if (seo.enable_search_indexing) {
+ metaArr.push(
+
+ );
+ }
+ }
+ return metaArr;
+ };
+ const blogList: any = posts?.concat(archivePost);
+ return (
+ <>
+
+
+
+
+
+
+ Contentstack-Nextjs-Starter-App
+ {page?.seo && page.seo.enable_search_indexing && metaData(page.seo)}
+
+
+
+
+ >
+ );
+}
+
+MyApp.getInitialProps = async (appContext: any) => {
+ const appProps = await App.getInitialProps(appContext);
+ const header = await getHeaderRes();
+ const footer = await getFooterRes();
+ const entries = await getAllEntries();
+
+ return { ...appProps, header, footer, entries };
+};
+
+export default MyApp;
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/_document.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/_document.tsx
new file mode 100644
index 0000000000..0fc0058fbd
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/_document.tsx
@@ -0,0 +1,51 @@
+/* eslint-disable react/react-in-jsx-scope */
+import Document, { Html, Head, Main, NextScript } from 'next/document';
+
+class MyDocument extends Document {
+ static async getInitialProps(ctx: any) {
+ const initialProps = await Document.getInitialProps(ctx);
+ return { ...initialProps };
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default MyDocument;
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/blog/[post].tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/blog/[post].tsx
new file mode 100644
index 0000000000..d37210e54f
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/blog/[post].tsx
@@ -0,0 +1,113 @@
+import React, { useEffect, useState } from 'react';
+import moment from 'moment';
+import parse from 'html-react-parser';
+import { getPageRes, getBlogPostRes } from '../../helper';
+import { onEntryChange } from '../../contentstack-sdk';
+import Skeleton from 'react-loading-skeleton';
+import RenderComponents from '../../components/render-components';
+import ArchiveRelative from '../../components/archive-relative';
+import { Page, BlogPosts, PageUrl } from "../../typescript/pages";
+
+
+export default function BlogPost({ blogPost, page, pageUrl }: {blogPost: BlogPosts, page: Page, pageUrl: PageUrl}) {
+
+ const [getPost, setPost] = useState({ banner: page, post: blogPost });
+ async function fetchData() {
+ try {
+ const entryRes = await getBlogPostRes(pageUrl);
+ const bannerRes = await getPageRes('/blog');
+ if (!entryRes || !bannerRes) throw new Error('Status: ' + 404);
+ setPost({ banner: bannerRes, post: entryRes });
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ useEffect(() => {
+ onEntryChange(() => fetchData());
+ }, [blogPost]);
+
+ const { post, banner } = getPost;
+ return (
+ <>
+ {banner ? (
+
+ ) : (
+
+ )}
+
+
+ {post && post.title ? (
+ {post.title}
+ ) : (
+
+
+
+ )}
+ {post && post.date ? (
+
+ {moment(post.date).format('ddd, MMM D YYYY')},{' '}
+
+ {post.author[0].title}
+
+
+ ) : (
+
+
+
+ )}
+ {post && post.body ? (
+ {parse(post.body)}
+ ) : (
+
+ )}
+
+
+
+ {banner && banner?.page_components[2].widget ? (
+
+ {banner?.page_components[2].widget.title_h2}
+
+ ) : (
+
+
+
+ )}
+ {post && post.related_post ? (
+
+ ) : (
+
+ )}
+
+
+
+ >
+ );
+}
+export async function getServerSideProps({ params }: any) {
+ try {
+ const page = await getPageRes('/blog');
+ const posts = await getBlogPostRes(`/blog/${params.post}`);
+ if (!page || !posts) throw new Error('404');
+
+ return {
+ props: {
+ pageUrl: `/blog/${params.post}`,
+ blogPost: posts,
+ page,
+ },
+ };
+ } catch (error) {
+ console.error(error);
+ return { notFound: true };
+ }
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/blog/index.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/blog/index.tsx
new file mode 100644
index 0000000000..8fb499fa86
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/blog/index.tsx
@@ -0,0 +1,92 @@
+import React, { useState, useEffect } from 'react';
+import { onEntryChange } from '../../contentstack-sdk';
+import BlogList from '../../components/blog-list';
+import RenderComponents from '../../components/render-components';
+import { getPageRes, getBlogListRes } from '../../helper';
+
+import ArchiveRelative from '../../components/archive-relative';
+import Skeleton from 'react-loading-skeleton';
+import { Page, PostPage, PageUrl, Context } from "../../typescript/pages";
+
+
+export default function Blog({ page, posts, archivePost, pageUrl }: {page: Page, posts: PostPage, archivePost: PostPage, pageUrl: PageUrl}) {
+
+ const [getBanner, setBanner] = useState(page);
+ async function fetchData() {
+ try {
+ const bannerRes = await getPageRes(pageUrl);
+ if (!bannerRes) throw new Error('Status code 404');
+ setBanner(bannerRes);
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ useEffect(() => {
+ onEntryChange(() => fetchData());
+ }, []);
+ return (
+ <>
+ {getBanner.page_components ? (
+
+ ) : (
+
+ )}
+
+
+ {posts ? (
+ posts.map((blogList, index) => (
+
+ ))
+ ) : (
+
+ )}
+
+
+ {getBanner && getBanner.page_components[1].widget && (
+
{getBanner.page_components[1].widget.title_h2}
+ )}
+ {archivePost ? (
+
+ ) : (
+
+ )}
+
+
+ >
+ );
+}
+
+export async function getServerSideProps(context: Context) {
+ try {
+ const page = await getPageRes(context.resolvedUrl);
+ const result: PostPage = await getBlogListRes();
+
+ const archivePost = [] as any;
+ const posts = [] as any;
+ result.forEach((blogs) => {
+ if (blogs.is_archived) {
+ archivePost.push(blogs);
+ } else {
+ posts.push(blogs);
+ }
+ });
+ return {
+ props: {
+ pageUrl: context.resolvedUrl,
+ page,
+ posts,
+ archivePost,
+ },
+ };
+ } catch (error) {
+ console.error(error);
+ return { notFound: true };
+ }
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/index.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/index.tsx
new file mode 100644
index 0000000000..9d7d5c1d02
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/index.tsx
@@ -0,0 +1,52 @@
+import React, { useState, useEffect } from 'react';
+import { onEntryChange } from '../contentstack-sdk';
+import RenderComponents from '../components/render-components';
+import { getPageRes } from '../helper';
+import Skeleton from 'react-loading-skeleton';
+import { Props, Context } from "../typescript/pages";
+
+export default function Home(props: Props) {
+
+ const { page, entryUrl } = props;
+
+ const [getEntry, setEntry] = useState(page);
+
+ async function fetchData() {
+ try {
+ const entryRes = await getPageRes(entryUrl);
+ if (!entryRes) throw new Error('Status code 404');
+ setEntry(entryRes);
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ useEffect(() => {
+ onEntryChange(() => fetchData());
+ }, []);
+
+ return getEntry ? (
+
+ ) : (
+
+ );
+}
+
+export async function getServerSideProps(context: Context) {
+ try {
+ const entryRes = await getPageRes(context.resolvedUrl);
+ return {
+ props: {
+ entryUrl: context.resolvedUrl,
+ page: entryRes,
+ },
+ };
+ } catch (error) {
+ return { notFound: true };
+ }
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/sitemap.xml.tsx b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/sitemap.xml.tsx
new file mode 100644
index 0000000000..54ae4dafc4
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/pages/sitemap.xml.tsx
@@ -0,0 +1,45 @@
+import { getAllEntries, getBlogListRes } from '../helper';
+import { Context, Pages, PostPage } from "../typescript/pages";
+
+const Sitemap = () => {
+ return null;
+};
+
+export const getServerSideProps = async ({ res }: {res: Context}) => {
+
+ const baseUrl = process.env.NEXT_PUBLIC_HOSTED_URL || 'http://localhost:3000';
+
+ let pages: Pages = await getAllEntries();
+ let posts: PostPage = await getBlogListRes();
+
+ const allPages = pages.map((page) => `${baseUrl}${page.url}`);
+ const allPosts = posts.map((post) => `${baseUrl}${post.url}`);
+ const siteMapList = [...allPages, ...allPosts].sort();
+
+ const sitemap = `
+
+ ${siteMapList
+ .map((url) => {
+ return `
+
+ ${url}
+ ${new Date().toISOString()}
+ monthly
+ 1.0
+
+ `;
+ })
+ .join('')}
+
+ `;
+
+ res.setHeader('Content-Type', 'text/xml');
+ res.write(sitemap);
+ res.end();
+
+ return {
+ props: {},
+ };
+};
+
+export default Sitemap;
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/contentstack-readme-logo.png b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/contentstack-readme-logo.png
new file mode 100644
index 0000000000..31f84727c6
Binary files /dev/null and b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/contentstack-readme-logo.png differ
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/copy.svg b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/copy.svg
new file mode 100644
index 0000000000..5927e2119c
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/copy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/favicon.ico b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/favicon.ico
new file mode 100644
index 0000000000..14817ed9ea
Binary files /dev/null and b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/favicon.ico differ
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-192x192.png b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-192x192.png
new file mode 100644
index 0000000000..3f2df6abbb
Binary files /dev/null and b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-192x192.png differ
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-256x256.png b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-256x256.png
new file mode 100644
index 0000000000..5dfd156d7c
Binary files /dev/null and b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-256x256.png differ
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-384x384.png b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-384x384.png
new file mode 100644
index 0000000000..4637d1ee34
Binary files /dev/null and b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-384x384.png differ
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-512x512.png b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-512x512.png
new file mode 100644
index 0000000000..008484780c
Binary files /dev/null and b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/icon/icon-512x512.png differ
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/json.svg b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/json.svg
new file mode 100644
index 0000000000..97fe4f4f90
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/json.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/manifest.json b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/manifest.json
new file mode 100644
index 0000000000..d2d243367b
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/manifest.json
@@ -0,0 +1,36 @@
+{
+ "theme_color": "#715cdd",
+ "background_color": "#fff",
+ "display": "standalone",
+ "scope": "/",
+ "start_url": "/",
+ "name": "Contentstack-Nextjs-Starter-App",
+ "short_name": "Starter-App",
+ "description": "Starter app for nextjs and contentstack integration",
+ "icons": [
+ {
+ "src": "/icon/icon-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "any maskable"
+ },
+ {
+ "src": "/icon/icon-256x256.png",
+ "sizes": "256x256",
+ "type": "image/png",
+ "purpose": "any maskable"
+ },
+ {
+ "src": "/icon/icon-384x384.png",
+ "sizes": "384x384",
+ "type": "image/png",
+ "purpose": "any maskable"
+ },
+ {
+ "src": "/icon/icon-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "any maskable"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/starter-app.png b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/starter-app.png
new file mode 100644
index 0000000000..0ce53dd292
Binary files /dev/null and b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/starter-app.png differ
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/vercel.svg b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/vercel.svg
new file mode 100644
index 0000000000..fbf0e25a65
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/public/vercel.svg
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/Home.module.css b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/Home.module.css
new file mode 100644
index 0000000000..32a57d52f3
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/Home.module.css
@@ -0,0 +1,116 @@
+.container {
+ padding: 0 2rem;
+}
+
+.main {
+ min-height: 100vh;
+ padding: 4rem 0;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.footer {
+ display: flex;
+ flex: 1;
+ padding: 2rem 0;
+ border-top: 1px solid #eaeaea;
+ justify-content: center;
+ align-items: center;
+}
+
+.footer a {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-grow: 1;
+}
+
+.title a {
+ color: #0070f3;
+ text-decoration: none;
+}
+
+.title a:hover,
+.title a:focus,
+.title a:active {
+ text-decoration: underline;
+}
+
+.title {
+ margin: 0;
+ line-height: 1.15;
+ font-size: 4rem;
+}
+
+.title,
+.description {
+ text-align: center;
+}
+
+.description {
+ margin: 4rem 0;
+ line-height: 1.5;
+ font-size: 1.5rem;
+}
+
+.code {
+ background: #fafafa;
+ border-radius: 5px;
+ padding: 0.75rem;
+ font-size: 1.1rem;
+ font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
+ Bitstream Vera Sans Mono, Courier New, monospace;
+}
+
+.grid {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: wrap;
+ max-width: 800px;
+}
+
+.card {
+ margin: 1rem;
+ padding: 1.5rem;
+ text-align: left;
+ color: inherit;
+ text-decoration: none;
+ border: 1px solid #eaeaea;
+ border-radius: 10px;
+ transition: color 0.15s ease, border-color 0.15s ease;
+ max-width: 300px;
+}
+
+.card:hover,
+.card:focus,
+.card:active {
+ color: #0070f3;
+ border-color: #0070f3;
+}
+
+.card h2 {
+ margin: 0 0 1rem 0;
+ font-size: 1.5rem;
+}
+
+.card p {
+ margin: 0;
+ font-size: 1.25rem;
+ line-height: 1.5;
+}
+
+.logo {
+ height: 1em;
+ margin-left: 0.5rem;
+}
+
+@media (max-width: 600px) {
+ .grid {
+ width: 100%;
+ flex-direction: column;
+ }
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/globals.css b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/globals.css
new file mode 100644
index 0000000000..e5e2dcc23b
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/globals.css
@@ -0,0 +1,16 @@
+html,
+body {
+ padding: 0;
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
+ Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
+
+* {
+ box-sizing: border-box;
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/json-preview.css b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/json-preview.css
new file mode 100644
index 0000000000..f8c356ada1
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/json-preview.css
@@ -0,0 +1,15 @@
+.json-preview {
+ width: 50px;
+ text-align: center;
+}
+
+.json-preview:hover {
+ background: #EDF1F7;
+ cursor: pointer;
+}
+
+.json-copy{
+ cursor: pointer;
+ position: absolute;
+ right: 2.5rem;
+}
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/style.css b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/style.css
new file mode 100644
index 0000000000..e8db433403
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/style.css
@@ -0,0 +1,1354 @@
+@import "./json-preview.css";
+@import "./tool-tip.css";
+
+body {
+ font-family: Inter, sans-serif;
+ font-size: 14px;
+ margin: 0;
+ line-height: 22px;
+}
+
+h1, h2, h3, h4 {
+ font-weight: bold;
+ letter-spacing: 0.2px;
+}
+
+body h1 {
+ font-size: 44px;
+ line-height: 56px;
+}
+
+body h2 {
+ font-size: 28px;
+ line-height: 34px;
+}
+
+body h3, h4 {
+ font-size: 18px;
+ line-height: 24px;
+}
+
+body a {
+ text-decoration: none;
+ color: #222222;
+}
+
+body p {
+ color: #444444;
+}
+
+.max-width {
+ width: 90%;
+ margin: 0 auto;
+ max-width: 1280px;
+}
+
+.note-div {
+ background: #f2efff;
+}
+
+.note-div p {
+ margin: 0 auto;
+ text-align: center;
+ padding: 5px 0;
+ color: #222222;
+}
+
+nav ul {
+ list-style: none;
+ padding: 0;
+ margin: auto;
+}
+
+nav ul li {
+ display: inline-block;
+ padding: 23px 30px;
+ letter-spacing: 0.2px;
+ text-transform: capitalize;
+}
+
+nav ul li a {
+ font-weight: 600;
+}
+
+.top-section h2, .top-section p {
+ margin: 6px 0;
+ padding: 0;
+}
+
+header {
+ background: #fff;
+ position: sticky;
+ top: 0;
+ z-index: 9;
+}
+
+header .max-width {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+header .wrapper-logo {
+ flex: 0 0 170px;
+ margin: 20px 0;
+}
+
+header .wrapper-logo img {
+ width: 130px;
+}
+
+header nav {
+ flex: 1 1 100%;
+ text-align: right;
+}
+
+.header-div {
+ height: 70px;
+}
+
+.devtools {
+ float: right;
+ position: relative;
+ bottom: 30px;
+ right: 1%;
+ cursor: pointer;
+}
+
+.devtools img {
+ width: 28px;
+}
+
+.header-ul {
+ overflow: hidden;
+}
+
+header nav li a:hover, header nav li a.active {
+ color: #715cdd;
+}
+
+.header-ul .hamburger-icon {
+ display: none;
+}
+
+footer {
+ margin-top: 75px;
+ background: #fff;
+}
+
+footer a {
+ color: #222222;
+ padding: 12px;
+}
+
+.footer-div {
+ display: flex;
+ flex-wrap: wrap;
+ flex-direction: row;
+}
+
+.footer-nav-li {
+ padding: 0;
+}
+
+.col-half {
+ margin: auto;
+}
+
+.col-quarter {
+ display: inline-block;
+ margin: auto 0;
+}
+
+.copyright {
+ padding: 5px;
+ text-align: center;
+}
+
+.contact-form {
+ width: 100%;
+ background: #f7f7f7;
+ height: 400px;
+}
+
+.blog-roll, .blog-entry {
+ font-size: 0.9em;
+}
+
+.blog-post h2 {
+ margin: 0 0 12px;
+}
+
+.blog-post .blog-meta {
+ margin-top: 0;
+ font-weight: 300;
+ font-size: 24px;
+}
+
+.blog-post .blog-meta .author {
+ padding-left: 1em;
+}
+
+/* button area in contact form */
+
+.btn {
+ border: none;
+ font-size: 14px;
+ line-height: 18px;
+ border-radius: 2px;
+ letter-spacing: 0.3px;
+ padding: 12px 28px;
+}
+
+.primary-btn {
+ background: #715cdd;
+ color: #fff;
+ cursor: pointer;
+}
+
+.primary-btn:hover {
+ background: #715cdd;
+ color: #fff;
+ font-weight: 600;
+}
+
+.secondary-btn {
+ border: 1px solid #715cdd;
+ color: #715cdd;
+}
+
+.secondary-btn:hover {
+ color: #715cdd;
+ font-weight: bold;
+}
+
+.tertiary-btn {
+ background: #ffffff;
+ color: #715cdd;
+ font-weight: bold;
+}
+
+.tertiary-btn:hover {
+ color: #5c49be;
+}
+
+.btn-close {
+ width: 0.6rem;
+ height: 0.6rem;
+ padding: 0 0.5rem !important;
+}
+
+.modal-btn {
+ font-style: normal;
+ font-weight: bold;
+ font-size: 13px;
+ line-height: 135%;
+ color: #647696;
+}
+
+.modal-btn:hover {
+ color: #222222;
+}
+
+.text-field textarea {
+ width: 550px;
+ height: 120px;
+ background-color: #f3f3f3;
+ padding: 10px 15px;
+ border: none;
+}
+
+/* Blog list section */
+
+.blog-container {
+ margin: 53px auto 0 auto;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+
+.blog-list {
+ display: flex;
+ border: 2px solid #dacccc33;
+ border-radius: 3px;
+ margin-bottom: 12px;
+}
+
+.blog-list>a {
+ text-align: center;
+ width: 40%;
+ background: #efefef;
+ display: inline-flex;
+}
+
+.blog-list-img {
+ max-width: 100%;
+}
+
+.blog-column-left, .blog-column-right {
+ display: flex;
+ flex-direction: column;
+ padding: 60px;
+}
+
+.blog-column-left {
+ width: 690px;
+}
+
+.blog-column-right {
+ width: 360px;
+}
+
+.blog-column-right a:hover {
+ color: #222222;
+}
+
+.blog-content h3 {
+ color: #222222;
+}
+
+.blog-content {
+ width: 60%;
+ padding: 15px;
+}
+
+.blog-column-left .blog-content a {
+ color: #715cdd;
+}
+
+/* blog individual page */
+
+.blog-detail {
+ width: 690px;
+}
+
+/* home page */
+
+.hero-description {
+ font-size: 16px;
+ line-height: 22px;
+ letter-spacing: 0.3px;
+ margin-bottom: 40px;
+ color: #ffffff;
+}
+
+.blogpost-readmore {
+ color: #715cdd;
+}
+
+.card-cta {
+ display: flex;
+ margin-top: auto;
+}
+
+.blog-roll .blog-entry {
+ font-size: 0.9em;
+}
+
+/* New Custom */
+
+.hero-banner {
+ display: flex;
+ justify-content: space-evenly;
+ text-align: center;
+ background: #715cdd;
+ padding: 63px;
+ color: #fff;
+ flex-wrap: wrap;
+}
+
+.hero-content, .home-content {
+ text-align: left;
+ margin-top: 65px;
+ width: 475px;
+}
+
+.home-content p {
+ margin-bottom: 32px;
+}
+
+.home-advisor-section {
+ background: #fff;
+ display: flex;
+ justify-content: space-evenly;
+ text-align: center;
+ margin: 63px;
+ flex-wrap: wrap;
+}
+
+.member-section {
+ display: flex;
+ justify-content: space-evenly;
+ flex-wrap: wrap;
+ padding: 27px;
+ text-align: center;
+ margin-top: 43px;
+}
+
+.member-main-section {
+ background: #f7f7f7;
+ margin: auto;
+ padding: 34px;
+}
+
+.member-head {
+ text-align: center;
+}
+
+.content-section {
+ width: 350px;
+}
+
+.content-section a {
+ font-weight: bold;
+ color: #715cdd;
+}
+
+.home-featured-blogs {
+ display: flex;
+ padding: 20px;
+ justify-content: center;
+ text-align: left;
+ flex-wrap: wrap;
+}
+
+.community-section {
+ text-align: center;
+}
+
+.community-head {
+ padding: 19px;
+ display: flex;
+ justify-content: space-evenly;
+ flex-wrap: wrap;
+}
+
+.community-head a {
+ display: inline-block;
+ margin: auto 0 auto 0;
+}
+
+.featured-blog {
+ width: 526px;
+ border: #f7f5f5 solid;
+ margin: 4px 33px;
+}
+
+.featured-blog img {
+ object-fit: cover;
+ inline-size: max-content;
+}
+
+.featured-content>p {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 4;
+ /* number of lines to show */
+ -webkit-box-orient: vertical;
+}
+
+.featured-content {
+ padding: 16px;
+}
+
+.demo-section {
+ display: flex;
+ justify-content: center;
+ background: #f7f7f7;
+ padding: 60px 0px;
+ flex-wrap: wrap;
+}
+
+.cards {
+ width: 410px;
+ background: #ffffff;
+ border: 1px solid #e5e5e5;
+ border-radius: 5px;
+ padding: 15px;
+ margin-left: 24px;
+ display: flex;
+ flex-direction: column;
+}
+
+/* home page ends here */
+
+/* About us page start */
+
+.about-content {
+ color: #222222;
+ text-align: left;
+ margin-top: 35px;
+ width: 475px;
+}
+
+.about-desc {
+ color: #737b7d;
+}
+
+.mission-content-section {
+ display: flex;
+ width: 380px;
+}
+
+.mission-icon, .mission-section-content {
+ display: inline-block;
+}
+
+.mission-icon {
+ height: 50px;
+ margin-top: 12px;
+ display: inline-block;
+ padding-right: 32px;
+}
+
+.mission-section-content {
+ display: inline-block;
+}
+
+.mission-content-top {
+ display: flex;
+ justify-content: space-evenly;
+ text-align: left;
+}
+
+.mission-content-bottom {
+ display: flex;
+ justify-content: space-evenly;
+ text-align: left;
+}
+
+.story-advisor-section {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-evenly;
+ margin-top: 35px;
+ padding: 63px;
+}
+
+.about-team-section {
+ background: #f7f7f7;
+ text-align: center;
+}
+
+.story-content {
+ text-align: left;
+ margin-top: 35px;
+ width: 475px;
+}
+
+.story-content p {
+ margin-bottom: 32px;
+}
+
+.team-head-section {
+ padding-top: 64px;
+ width: auto;
+ max-width: 920px;
+ margin: auto;
+}
+
+.team-content {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ text-align: center;
+ padding-top: 35px;
+ margin: 5px;
+}
+
+.team-details {
+ padding: 0px 15px;
+}
+
+/* contact page */
+
+.contact-page-content {
+ width: 50%;
+ padding-top: 55px;
+ padding-right: 80px;
+}
+
+.contact-page-form {
+ width: 50%;
+}
+
+.contact-page-content>h2 {
+ font-weight: bold;
+ font-size: 44px;
+ line-height: 56px;
+}
+
+.contact-page-content>p {
+ font-size: 16px;
+ color: #737b7d;
+}
+
+.input-fields, .text-field {
+ margin-bottom: 30px;
+}
+
+.input-fields input {
+ width: 100%;
+ background-color: #f3f3f3;
+ padding: 16px 15px;
+ border: none;
+}
+
+.text-field input {
+ width: 100%;
+ height: 120px;
+ background-color: #f3f3f3;
+ padding: 25px 15px;
+ border: none;
+}
+
+.contact-maps-content {
+ margin-top: 70px;
+ width: 50%;
+}
+
+/* blog list */
+
+.blog-page-banner {
+ background: #715cdd;
+ text-align: center;
+}
+
+.blog-page-content {
+ color: #fff;
+ text-align: center;
+ display: inline-block;
+ width: 482px;
+ padding: 58px 0px 58px 0px;
+}
+
+.error-page {
+ text-align: center;
+ min-height: 400px;
+ padding-top: 80px;
+}
+
+.header .menu-btn {
+ display: none;
+}
+
+.contact-page-section, .contact-maps-section {
+ display: flex;
+ justify-content: center;
+ flex-wrap: nowrap;
+ padding: 45px 0;
+}
+
+.maps-details {
+ width: 50%;
+}
+
+.maps-details img {
+ max-width: 100%;
+}
+
+.modal {
+ overflow: hidden;
+ border-radius: 10px;
+}
+
+.modal-content {
+ border: 0;
+}
+
+.modal-dialog {
+ max-width: 680px;
+}
+
+.devtools-modal-title {
+ display: block;
+ font-weight: bold;
+ font-size: 18px;
+ line-height: 135%;
+ letter-spacing: -0.00019em;
+ margin-top: 2px;
+}
+
+.modal-body {
+ min-height: 8.625rem;
+ overflow: auto;
+}
+
+.modal-footer {
+ padding: .61rem .75rem;
+}
+
+/* ========================== */
+
+/* Mobile */
+
+/* ========================== */
+
+@media screen and (min-width: 320px) and (max-width: 767px) {
+ .header {
+ height: 70px;
+ background-color: #fff;
+ }
+
+ .header-div {
+ height: auto;
+ }
+
+ .footer-div {
+ flex-direction: column;
+ }
+
+ .col-half {
+ padding: 0px;
+ margin: 0px;
+ }
+
+ .col-quarter {
+ padding: 15px 0;
+ }
+
+ .footer-nav-li {
+ padding: 7px;
+ }
+
+ .nav-ul {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ padding: 0px;
+ margin: 0px;
+ }
+
+ .header ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ overflow: hidden;
+ background-color: #fff;
+ }
+
+ .header li a {
+ display: block;
+ padding: 0 20px;
+ border-right: 1px solid #f4f4f4;
+ text-decoration: none;
+ }
+
+ .header li a:hover, .header .menu-btn:hover {
+ background-color: #f4f4f4;
+ }
+
+ /* menu */
+ .header .menu {
+ clear: both;
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.2s ease-out;
+ }
+
+ .header .header-div {
+ display: inline-block;
+ width: 100%;
+ background-color: #fff;
+ }
+
+ .header .wrapper-logo {
+ float: left;
+ margin-left: 15px;
+ }
+
+ .menu-icon {
+ float: right;
+ margin-top: 2px;
+ }
+
+ /* menu icon */
+ .header .menu-icon {
+ cursor: pointer;
+ display: inline-block;
+ float: right;
+ padding: 28px 20px;
+ position: relative;
+ user-select: none;
+ }
+
+ .header .menu-icon .navicon {
+ background: #333;
+ display: block;
+ height: 2px;
+ position: relative;
+ transition: background 0.2s ease-out;
+ width: 18px;
+ }
+
+ .header .menu-icon .navicon:before, .header .menu-icon .navicon:after {
+ background: #333;
+ content: "";
+ display: block;
+ height: 100%;
+ position: absolute;
+ transition: all 0.2s ease-out;
+ width: 100%;
+ }
+
+ .header .menu-icon .navicon:before {
+ top: 5px;
+ }
+
+ .header .menu-icon .navicon:after {
+ top: -5px;
+ }
+
+ .header .menu-btn:checked~nav {
+ max-height: 240px;
+ overflow: auto;
+ }
+
+ .header .menu-btn:checked~.menu-icon .navicon {
+ background: transparent;
+ }
+
+ .header .menu-btn:checked~.menu-icon .navicon:before {
+ transform: rotate(-45deg);
+ }
+
+ .header .menu-btn:checked~.menu-icon .navicon:after {
+ transform: rotate(45deg);
+ }
+
+ .header .menu-btn:checked~.menu-icon:not(.steps) .navicon:before, .header .menu-btn:checked~.menu-icon:not(.steps) .navicon:after {
+ top: 0;
+ }
+
+ nav ul li {
+ padding: 15px 0;
+ }
+
+ h1 h2 h3 h4 {
+ font-weight: bold;
+ letter-spacing: 0.1px;
+ }
+
+ body h1 {
+ font-size: 29px;
+ line-height: 38px;
+ letter-spacing: 0.2px;
+ }
+
+ body h2 {
+ font-size: 20px;
+ line-height: 28px;
+ }
+
+ body h3 {
+ font-size: 14px;
+ line-height: 24px;
+ }
+
+ .btn {
+ border: none;
+ display: block;
+ text-align: center;
+ font-size: 12px;
+ line-height: 18px;
+ border-radius: 2px;
+ letter-spacing: 0.3px;
+ padding: 8px 21px;
+ }
+
+ .secondary-btn {
+ border: 1px solid #715cdd;
+ color: #715cdd;
+ }
+
+ .hero-banner {
+ display: flex;
+ justify-content: space-evenly;
+ text-align: left;
+ background: #715cdd;
+ padding: 28px;
+ color: #fff;
+ flex-wrap: wrap;
+ }
+
+ .home-advisor-section {
+ background: #fff;
+ display: flex;
+ justify-content: space-evenly;
+ text-align: left;
+ padding: 28px;
+ margin: 0;
+ flex-wrap: wrap-reverse;
+ }
+
+ .blog-page-content {
+ color: #fff;
+ text-align: left;
+ width: 90%;
+ }
+
+ .blog-list>img {
+ max-width: 100%;
+ }
+
+ .blog-list-img {
+ margin: auto;
+ }
+
+ .blog-list>a {
+ width: 100%;
+ }
+
+ .blog-column-left {
+ padding: 0;
+ }
+
+ .blog-column-right {
+ background: #f2f2f2;
+ padding: 17px;
+ height: fit-content;
+ }
+
+ .blog-content {
+ width: auto;
+ }
+
+ .hero-banner>img {
+ max-width: 100%;
+ margin-top: 40px;
+ }
+
+ .home-content {
+ text-align: left;
+ margin-top: 9px;
+ width: 475px;
+ }
+
+ .home-advisor-section>img {
+ max-width: 100%;
+ margin-top: 40px;
+ }
+
+ .featured-blog {
+ width: 90%;
+ margin: 5px auto;
+ }
+
+ .community-head {
+ padding: 19px;
+ display: block;
+ justify-content: space-evenly;
+ flex-wrap: wrap;
+ }
+
+ .community-head a {
+ display: block;
+ margin: auto 0 auto 0;
+ }
+
+ .home-featured-blogs {
+ display: flex;
+ padding: 0 5px 27px;
+ justify-content: center;
+ text-align: left;
+ flex-wrap: wrap;
+ }
+
+ .content-section {
+ margin: 12px;
+ }
+
+ .featured-blog>img {
+ width: 100%;
+ }
+
+ .member-section {
+ display: flex;
+ justify-content: space-evenly;
+ flex-wrap: wrap;
+ padding: 27px;
+ text-align: center;
+ margin-top: 14px;
+ }
+
+ .cards {
+ background: #ffffff;
+ border: 1px solid #e5e5e5;
+ border-radius: 5px;
+ padding: 22px;
+ display: flex;
+ margin: 16px 17px 15px 17px;
+ max-width: 100%;
+ }
+
+ .mission-icon {
+ margin-top: 12px;
+ display: inline-block;
+ padding: 0;
+ }
+
+ .mission-content-top {
+ display: flex;
+ justify-content: space-evenly;
+ text-align: left;
+ flex-wrap: wrap;
+ }
+
+ .mission-content-bottom {
+ display: flex;
+ justify-content: space-evenly;
+ text-align: left;
+ flex-wrap: wrap;
+ }
+
+ .mission-content-section {
+ width: 313px;
+ display: inline-block;
+ text-align: center;
+ }
+
+ .story-advisor-section>img {
+ max-width: 100%;
+ }
+
+ .team-head-section {
+ padding-top: 64px;
+ margin: auto;
+ width: 90%;
+ }
+
+ .blog-list {
+ display: block;
+ border: 2px solid #dacccc33;
+ border-radius: 3px;
+ margin-bottom: 12px;
+ }
+
+ .contact-page-content {
+ width: auto;
+ padding: 55px 0;
+ text-align: left;
+ }
+
+ .blog-container {
+ padding: 26px;
+ }
+
+ .contact-page-form {
+ width: 100%;
+ }
+
+ .contact-page-section, .contact-maps-section {
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+ padding: 45px 0;
+ }
+
+ .maps-details {
+ width: auto;
+ overflow: hidden;
+ }
+
+ .contact-maps-content {
+ width: auto;
+ }
+
+ .json-preview {
+ position: absolute;
+ top: 3.3rem;
+ right: 2.5rem;
+ }
+
+}
+
+/* ========================== */
+
+/* Tablet */
+
+/* ========================== */
+
+@media screen and (min-width: 768px) and (max-width: 1024px) {
+ body p {
+ color: #444444;
+ }
+
+ .btn {
+ border: none;
+ font-size: 14px;
+ line-height: 18px;
+ border-radius: 2px;
+ letter-spacing: 0.3px;
+ padding: 11px 17px;
+ }
+
+ .secondary-btn {
+ border: 1px solid #715cdd;
+ color: #715cdd;
+ }
+
+ body h1 {
+ font-weight: bold;
+ font-size: 28px;
+ line-height: 34px;
+ letter-spacing: 0.1px;
+ }
+
+ body h2 {
+ font-weight: bold;
+ font-size: 20px;
+ line-height: 24px;
+ letter-spacing: 0.1px;
+ }
+
+ body h3, body h4 {
+ font-weight: bold;
+ font-size: 14px;
+ line-height: 24px;
+ }
+
+ header nav {
+ display: block;
+ }
+
+ .hero-banner {
+ display: flex;
+ justify-content: space-evenly;
+ text-align: center;
+ background: #715cdd;
+ padding: 63px;
+ color: #fff;
+ flex-wrap: nowrap;
+ }
+
+ .hero-description {
+ font-size: 14px;
+ line-height: 22px;
+ letter-spacing: 0.3px;
+ margin-bottom: 40px;
+ }
+
+ .home-content {
+ width: 50%;
+ margin-top: 12px;
+ }
+
+ .hero-banner>img {
+ width: 50%;
+ margin: 27px 0px 0px 0px;
+ }
+
+ .home-advisor-section {
+ background: #fff;
+ display: flex;
+ justify-content: space-evenly;
+ text-align: center;
+ margin: 80px 63px 63px 63px;
+ flex-wrap: nowrap;
+ }
+
+ .home-advisor-section>img {
+ width: 50%;
+ }
+
+ .member-section {
+ display: flex;
+ justify-content: space-evenly;
+ padding: 27px;
+ text-align: center;
+ margin-top: 43px;
+ flex-wrap: nowrap;
+ }
+
+ .home-featured-blogs {
+ display: flex;
+ padding: 20px;
+ justify-content: center;
+ text-align: left;
+ flex-wrap: nowrap;
+ }
+
+ .featured-blog {
+ width: 335px;
+ border: #f7f5f5 solid;
+ margin: 4px 14px;
+ }
+
+ .featured-blog>img {
+ max-width: 100%;
+ height: 260px;
+ object-fit: cover;
+ inline-size: max-content;
+ }
+
+ .featured-content>p {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 4;
+ /* number of lines to show */
+ -webkit-box-orient: vertical;
+ }
+
+ .demo-section {
+ display: flex;
+ justify-content: center;
+ background: #f7f7f7;
+ padding: 60px 0px;
+ flex-wrap: nowrap;
+ }
+
+ .cards {
+ width: 334px;
+ background: #ffffff;
+ border: 1px solid #e5e5e5;
+ border-radius: 5px;
+ padding: 15px;
+ margin-left: 24px;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .home-content p {
+ font-size: 14px;
+ line-height: 24px;
+ }
+
+ .mission-content-section {
+ display: block;
+ text-align: center;
+ width: fit-content;
+ padding: 20px;
+ }
+
+ .mission-icon {
+ padding: 0;
+ }
+
+ .team-details>p {
+ margin-top: -10px;
+ margin-bottom: 50px;
+ }
+
+ .team-head-section {
+ margin: auto;
+ width: 79%;
+ }
+
+ .contact-maps-section {
+ display: flex;
+ justify-content: center;
+ flex-wrap: nowrap;
+ padding: 45px 0;
+ }
+
+ .contact-page-section {
+ display: flex;
+ justify-content: center;
+ flex-wrap: nowrap;
+ padding: 45px 0;
+ }
+
+ .maps-details>img {
+ max-width: 100%;
+ }
+
+ .maps-details {
+ width: 50%;
+ }
+
+ .contact-maps-content {
+ width: 50%;
+ padding: 0px 47px 1px 52px;
+ margin-top: 0;
+ }
+
+ .contact-page-section p {
+ font-size: 14px;
+ line-height: 20px;
+ }
+
+ .blog-column-left {
+ width: 65%;
+ padding: 30px;
+ }
+
+ .blog-column-right {
+ width: 35%;
+ padding: 18px;
+ margin: 33px;
+ background: #f2f2f2;
+ height: fit-content;
+ }
+
+ .blog-list-img {
+ max-width: 100%;
+ }
+
+ .blog-list>a {
+ text-align: center;
+ background: #f2f2f2;
+ display: block;
+ width: 100%;
+ }
+
+ .blog-content {
+ width: 100%;
+ }
+
+ .blog-list {
+ display: block;
+ border: 2px solid #dacccc33;
+ border-radius: 3px;
+ margin-bottom: 12px;
+ }
+
+ .blog-container {
+ margin: 0 auto;
+ margin-top: 53px;
+ display: flex;
+ justify-content: center;
+ flex-wrap: nowrap;
+ }
+
+ .blog-detail p {
+ font-size: 14px;
+ line-height: 20px;
+ }
+
+ .blog-detail {
+ width: 65%;
+ margin-left: 23px;
+ }
+}
+
+/* scroll bar */
+::-webkit-scrollbar {
+ width: 5px;
+ height: 5px;
+}
+
+::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #e0e2e8;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: #eee;
+}
+
+/* scroll end */
+
+/* json preview css*/
+
+.object-key {
+ color: #C8501E;
+}
+
+.string-value {
+ color: #5d9ccb;
+}
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/third-party.css b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/third-party.css
new file mode 100644
index 0000000000..b26f69f69f
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/third-party.css
@@ -0,0 +1,411 @@
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS and IE text size adjust after device orientation change,
+ * without disabling user zoom.
+ */
+
+ html {
+ font-family: sans-serif;
+ /* 1 */
+ -ms-text-size-adjust: 100%;
+ /* 2 */
+ -webkit-text-size-adjust: 100%;
+ /* 2 */
+ box-sizing: border-box;
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+
+article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
+ display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio, canvas, progress, video {
+ display: inline-block;
+ /* 1 */
+ vertical-align: baseline;
+ /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
+ */
+
+[hidden], template {
+ display: none;
+}
+
+/* Links
+ ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * Improve readability of focused elements when they are also in an
+ * active/hover state.
+ */
+
+a:active, a:hover {
+ outline: 0;
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+
+b, strong {
+ font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub, sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9/10.
+ */
+
+img {
+ border: 0;
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+
+figure {
+ margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+ overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+
+code, kbd, pre, samp {
+ font-family: monospace;
+ font-size: 1em;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ * Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ */
+
+button, input, optgroup, select, textarea {
+ color: inherit;
+ /* 1 */
+ font: inherit;
+ /* 2 */
+ margin: 0;
+ /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+
+button {
+ overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button, select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button, html input[type="button"], input[type="reset"], input[type="submit"] {
+ -webkit-appearance: button;
+ /* 2 */
+ cursor: pointer;
+ /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled], html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner, input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+ line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"], input[type="radio"] {
+ box-sizing: border-box;
+ /* 1 */
+ padding: 0;
+ /* 2 */
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+
+input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield;
+ /* 1 */
+ box-sizing: content-box;
+ /* 2 */
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+
+input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0;
+ /* 1 */
+ padding: 0;
+ /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+ font-weight: bold;
+}
+
+/* Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+td, th {
+ padding: 0;
+}
+
+/* CSS Resets */
+
+*, *::before, *::after {
+ box-sizing: inherit;
+}
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/tool-tip.css b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/tool-tip.css
new file mode 100644
index 0000000000..58c208dcad
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/styles/tool-tip.css
@@ -0,0 +1,97 @@
+ /* Custom properties */
+ :root {
+ --tooltip-text-color: white;
+ --tooltip-background-color: black;
+ --tooltip-margin: 30px;
+ --tooltip-arrow-size: 6px;
+ }
+
+ /* Wrapping */
+ .Tooltip-Wrapper {
+ display: inline-block;
+ position: relative;
+ }
+
+ /* Absolute positioning */
+ .Tooltip-Tip {
+ position: absolute;
+ border-radius: 4px;
+ left: 50%;
+ transform: translateX(-50%);
+ padding: 6px;
+ color: var(--tooltip-text-color);
+ background: var(--tooltip-background-color);
+ font-size: 14px;
+ font-family: sans-serif;
+ line-height: 1;
+ z-index: 100;
+ white-space: nowrap;
+ display: none;
+ }
+
+ /* CSS border triangles */
+ .Tooltip-Tip::before {
+ content: " ";
+ left: 50%;
+ border: solid transparent;
+ height: 0;
+ width: 0;
+ position: absolute;
+ pointer-events: none;
+ border-width: var(--tooltip-arrow-size);
+ margin-left: calc(var(--tooltip-arrow-size) * -1);
+ }
+
+ /* Absolute positioning */
+ .Tooltip-Tip.top {
+ top: calc(var(--tooltip-margin) * -1);
+ }
+
+ /* CSS border triangles */
+ .Tooltip-Tip.top::before {
+ top: 100%;
+ border-top-color: var(--tooltip-background-color);
+ }
+
+ /* Absolute positioning */
+ .Tooltip-Tip.right {
+ left: calc(100% + var(--tooltip-margin));
+ top: 50%;
+ transform: translateX(0) translateY(-50%);
+ }
+
+ /* CSS border triangles */
+ .Tooltip-Tip.right::before {
+ left: calc(var(--tooltip-arrow-size) * -1);
+ top: 50%;
+ transform: translateX(0) translateY(-50%);
+ border-right-color: var(--tooltip-background-color);
+ }
+
+ /* Absolute positioning */
+ .Tooltip-Tip.bottom {
+ bottom: calc(var(--tooltip-margin) * -1);
+ }
+
+ /* CSS border triangles */
+ .Tooltip-Tip.bottom::before {
+ bottom: 100%;
+ border-bottom-color: var(--tooltip-background-color);
+ }
+
+ /* Absolute positioning */
+ .Tooltip-Tip.left {
+ left: auto;
+ right: calc(100% + var(--tooltip-margin));
+ top: 50%;
+ transform: translateX(0) translateY(-50%);
+ }
+
+ /* CSS border triangles */
+ .Tooltip-Tip.left::before {
+ left: auto;
+ right: calc(var(--tooltip-arrow-size) * -2);
+ top: 50%;
+ transform: translateX(0) translateY(-50%);
+ border-left-color: var(--tooltip-background-color);
+ }
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/tsconfig.json b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/tsconfig.json
new file mode 100644
index 0000000000..24ebcd741f
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
+ "exclude": ["node_modules"]
+}
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/action.ts b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/action.ts
new file mode 100644
index 0000000000..2de3952189
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/action.ts
@@ -0,0 +1,16 @@
+type AdditionalParam = {
+ url: string;
+ title: {};
+}
+
+export type Action = {
+ title: string;
+ href: string;
+ $: AdditionalParam;
+ }
+
+export type Image = {
+ filename: string;
+ url: string;
+ $: AdditionalParam;
+ }
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/component.ts b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/component.ts
new file mode 100644
index 0000000000..59b1b96aed
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/component.ts
@@ -0,0 +1,136 @@
+import { Action, Image } from "./action";
+
+type AdditionalParam = {
+ title: string;
+ title_h2: string;
+ title_h3: string;
+ description: string;
+ banner_title: string;
+ banner_description: string;
+ designation: string;
+ name: string;
+ html_code: string;
+ body: string;
+ date: string;
+}
+
+type Employee = {
+ image: Image;
+ name: string;
+ designation: string;
+ $: AdditionalParam;
+}
+
+type BucketList = [
+ BucketArray:{
+ title_h3: string;
+ description: string;
+ url: string;
+ call_to_action: Action;
+ icon: Image;
+ $: AdditionalParam;
+ }
+]
+
+type Card = [
+ cardArray: {
+ title_h3: string;
+ description: string;
+ call_to_action: Action;
+ $: AdditionalParam;
+ }
+]
+
+type Article = {
+ href: string;
+ title: string;
+ $: AdditionalParam;
+}
+
+type FeaturedBlog = [
+ BlogArray: {
+ title: string;
+ featured_image: Image;
+ body: string;
+ url: string;
+ $: AdditionalParam;
+ }
+]
+
+type Widget = {
+ title_h2: string;
+ type?: string;
+ $: AdditionalParam;
+}
+
+export type Component = {
+ hero_banner: Banner;
+ section?: SectionProps;
+ section_with_buckets?: SectionWithBucket;
+ from_blog?: FeaturedBlogData;
+ section_with_cards?: Cards;
+ section_with_html_code?: AdditionalParamProps;
+ our_team?: TeamProps;
+ widget?: Widget;
+}
+
+export type SectionWithBucket = {
+ bucket_tabular: boolean
+ title_h2: string;
+ buckets: BucketList;
+ description: string;
+ $: AdditionalParam;
+ }
+
+export type Cards = {
+ cards: Card;
+ }
+
+export type Banner = {
+ banner_title:string;
+ banner_description: string;
+ bg_color: string;
+ call_to_action: Action;
+ banner_image: Image;
+ text_color: string;
+ $: AdditionalParam;
+ }
+
+export type AdditionalParamProps = {
+ html_code_alignment: string;
+ title: string;
+ $: AdditionalParam;
+ description: string;
+ html_code: string;
+ }
+
+export type SectionProps = {
+ title_h2: String;
+ description: string;
+ call_to_action: Action;
+ image: Image;
+ image_alignment: string;
+ $: AdditionalParam;
+ }
+
+export type TeamProps = {
+ title_h2: string;
+ description: string;
+ $: AdditionalParam;
+ employees: [Employee];
+ }
+
+export type FeaturedBlogData = {
+ title_h2: string;
+ view_articles: Article;
+ featured_blogs: FeaturedBlog;
+ $: AdditionalParam;
+}
+
+export type RenderProps = {
+ blogPost?: boolean;
+ contentTypeUid: string;
+ entryUid: string;
+ locale: string;
+ pageComponents:Component[];
+}
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/layout.ts b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/layout.ts
new file mode 100644
index 0000000000..55b8106777
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/layout.ts
@@ -0,0 +1,130 @@
+import { Image } from "./action";
+import { Component } from "../typescript/component";
+
+type AdditionalParam = {
+ title: {};
+ copyright: string;
+ announcement_text: string;
+ label: {};
+ url: string;
+}
+
+type EntryData = {
+ title: string;
+ url: string;
+ $: AdditionalParam;
+}
+
+type Announcement = {
+ show_announcement: boolean;
+ announcement_text: string;
+ $: AdditionalParam;
+}
+
+type PageRef = {
+ title: string;
+ url: string;
+ $: AdditionalParam;
+}
+
+type Share = {
+ link: Links;
+ icon: Image;
+}
+
+type Social = {
+ social_share: [Share];
+}
+
+type Navigation = {
+ link: [Links];
+}
+
+type Author = {
+ title: string;
+ $: AdditionalParam;
+}
+
+type Blog = {
+ url: string;
+ body: string;
+ title: string;
+ $: AdditionalParam;
+}
+
+export type Posts = {
+ locale: string;
+ author: [Author];
+ body: string;
+ date: string;
+ featured_image: {};
+ is_archived: boolean;
+ related_post: [Blog];
+ seo: {};
+ url:string;
+ title: string;
+ _owner: {}
+}
+
+
+export type HeaderProps = {
+ locale:string;
+ logo: Image;
+ navigation_menu:[List]
+ notification_bar: Announcement;
+ title: string;
+ uid: string;
+ social: Social;
+ navigation: Navigation;
+ copyright: string;
+ $: AdditionalParam;
+}
+
+export type Entry = [
+ entry: EntryData
+]
+
+type List = {
+ label?: string;
+ page_reference: [PageRef];
+ $: {};
+ href?: string;
+}
+
+export type NavLinks = {
+ label?: string;
+}
+
+export type Links = {
+ label?: string;
+ title: string;
+ href: string;
+ $:AdditionalParam;
+}
+
+export type PageProps = {
+ locale: string;
+ page_components: Component[];
+ uid: string;
+ url: string;
+ title: string;
+ seo: {};
+}
+
+export type FooterProps = {
+ logo: Image;
+ title: string;
+ social: Social;
+ navigation: Navigation;
+ copyright: string;
+ locale: string,
+ navigation_menu: [List];
+ notification_bar: Announcement;
+ uid: string;
+ $: AdditionalParam;
+}
+
+export type ChilderenProps = {
+ props: {};
+ type: Function;
+}
\ No newline at end of file
diff --git a/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/pages.ts b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/pages.ts
new file mode 100644
index 0000000000..3117f92962
--- /dev/null
+++ b/packages/contentstack-bootstrap/contentstack-nextjs-starter-app/typescript/pages.ts
@@ -0,0 +1,109 @@
+import { Component } from "../typescript/component";
+import { Image } from "../typescript/action";
+import { Entry, HeaderProps ,FooterProps } from "./layout";
+
+type AdditionalParam = {
+ title: string;
+ title_h2: string;
+ title_h3: string;
+ description: string;
+ banner_title: string;
+ banner_description: string;
+ designation: string;
+ name: string;
+ html_code: string;
+ body: string;
+ date: string;
+ related_post: [];
+ copyright: string;
+ announcement_text: string;
+ label: {};
+ url: string;
+}
+
+type Post = {
+ url: string;
+ is_archived: boolean;
+ body: string;
+ featured_image: Image;
+ title: string;
+ date: string;
+ author: [Author];
+ $: AdditionalParam;
+}
+
+type Author = {
+ title: string;
+ $: AdditionalParam;
+}
+
+type PageProps = {
+ page: Page;
+ posts: [];
+ archivePost: [];
+ blogPost: BlogPosts;
+}
+
+type Seo = {
+ enable_search_indexing: boolean
+}
+
+type Blog = {
+ url: string;
+ body: string;
+ title: string;
+ $: AdditionalParam;
+}
+
+export type Props = {
+ page: Page;
+ entryUrl: string;
+ Component: Function;
+ entries: Entry;
+ pageProps: PageProps;
+ header: HeaderProps;
+ footer: FooterProps;
+}
+
+export type Page ={
+ page_components: Component[];
+ uid: string;
+ locale: string;
+ url: string;
+ seo: Seo;
+ title: string;
+}
+
+export type Context = {
+ resolvedUrl: string;
+ setHeader: Function;
+ write: Function;
+ end: Function;
+}
+
+export type Pages = [
+ page: Page
+]
+
+export type PostPage = [
+ post: Post
+]
+
+export type PageUrl = {
+ pageUrl: string;
+}
+
+export type BlogPosts = {
+ title: string;
+ date: string;
+ body: string;
+ author: [Author];
+ related_post: [Blog];
+ locale: string;
+ featured_image: Image;
+ is_archived: boolean;
+ seo: Seo;
+ url: string;
+ _owner: string;
+ $: AdditionalParam;
+}
\ No newline at end of file
diff --git a/packages/contentstack-import/src/import/modules/index.ts b/packages/contentstack-import/src/import/modules/index.ts
index 377537fd51..47b4839f86 100644
--- a/packages/contentstack-import/src/import/modules/index.ts
+++ b/packages/contentstack-import/src/import/modules/index.ts
@@ -4,13 +4,6 @@ import { ModuleClassParams } from '../../types';
import startJSModuleImport from '../modules-js';
export default async function startModuleImport(modulePayload: ModuleClassParams) {
- // Todo: Remove below code when auto detect mechanism implemented for old and new module
- if (
- modulePayload.moduleName === 'assets' &&
- !new FsUtility({ basePath: join(modulePayload.importConfig?.backupDir, 'assets') }).isNewFsStructure
- ) {
- return startJSModuleImport(modulePayload);
- }
const { default: ModuleRunner } = await import(`./${modulePayload.moduleName}`);
const moduleRunner = new ModuleRunner(modulePayload);
return moduleRunner.start();