Skip to content

Commit

Permalink
Merge pull request #32 from contentstack/staging
Browse files Browse the repository at this point in the history
Staging
  • Loading branch information
RohitKini authored Sep 9, 2024
2 parents f7e9cb4 + 906e54f commit 1b4d7d5
Show file tree
Hide file tree
Showing 58 changed files with 4,587 additions and 21,555 deletions.
4 changes: 2 additions & 2 deletions .env.local.sample
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ CONTENTSTACK_DELIVERY_TOKEN=YOUR_DELIVERY_TOKEN
CONTENTSTACK_ENVIRONMENT=YOUR_PUBLISHING_ENVIRONMENT

# For live preview
CONTENTSTACK_MANAGEMENT_TOKEN=
CONTENTSTACK_API_HOST=api.contentstack.io
CONTENTSTACK_PREVIEW_TOKEN=
CONTENTSTACK_APP_HOST=app.contentstack.com
CONTENTSTACK_PREVIEW_HOST=rest-preview.contentstack.com
CONTENTSTACK_LIVE_PREVIEW=true
CONTENTSTACK_LIVE_EDIT_TAGS=true

Expand Down
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
2 changes: 1 addition & 1 deletion .github/workflows/sast-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Semgrep Scan
run: docker run -v /var/run/docker.sock:/var/run/docker.sock -v "${PWD}:/src" returntocorp/semgrep semgrep scan --config auto
run: docker run -v /var/run/docker.sock:/var/run/docker.sock -v "${PWD}:/src" returntocorp/semgrep semgrep scan --config auto
2 changes: 1 addition & 1 deletion .github/workflows/sca-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ jobs:
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --all-projects --fail-on=all
args: --all-projects --fail-on=all --strict-out-of-sync=false
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Contentstack
Copyright (c) 2024 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
Expand Down
47 changes: 31 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,47 @@
[![Contentstack Logo](/public/contentstack-readme-logo.png)](https://www.contentstack.com/)

# academy-upgrade

# Build a Starter Website with Next.js and Contentstack
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

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.
## Getting Started

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.
First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

![Contentstack-Nextjs-starter-app](/public/starter-app.png)
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

## Live Demo
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

You can check the [live demo](https://contentstack-nextjs-starter-app.vercel.app) to get first-hand experience of the website.
## Learn More

To learn more about Next.js, take a look at the following resources:

## Tutorial
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js 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.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

[Build Website using Next.js and Contentstack](https://www.contentstack.com/docs/developers/sample-apps/build-a-starter-website-using-next-js-and-contentstack/)
## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

**More Resources**
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

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/)
>>>>>>> da15541 (Initial commit from Create Next App)
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
44 changes: 44 additions & 0 deletions app/[page]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use client';

import RenderComponents from '@/components/render-components';
import { onEntryChange } from '@/contentstack-sdk';
import { getPageRes, metaData } from '@/helper';
import { Page as PageProp } from '@/typescript/pages';
import { usePathname } from 'next/navigation';
import React, { useState, useEffect } from 'react';
import Skeleton from 'react-loading-skeleton';

export default function Page() {
const entryUrl = usePathname();

const [getEntry, setEntry] = useState<PageProp>();

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?.page_components ? (
<>
{getEntry.seo && getEntry.seo.enable_search_indexing && metaData(getEntry.seo)}
<RenderComponents
pageComponents={getEntry.page_components}
contentTypeUid='page'
entryUid={getEntry.uid}
locale={getEntry.locale}
/>
</>
) : (
<Skeleton count={3} height={300} />
);
}
104 changes: 104 additions & 0 deletions app/blog/[post]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use client';

import React, { useEffect, useState } from 'react';
import moment from 'moment';
import parse from 'html-react-parser';
import Skeleton from 'react-loading-skeleton';
import { usePathname } from 'next/navigation';
import { getBlogPostRes, getPageRes, metaData } from '@/helper';
import { BlogPosts, Page } from '@/typescript/pages';
import { onEntryChange } from '@/contentstack-sdk';
import RenderComponents from '@/components/render-components';
import ArchiveRelative from '@/components/archive-relative';


export default function BlogPost() {
const entryUrl = usePathname();

const [blogPost, setBlogPost] = useState<BlogPosts>();
const [page, setPage] = useState<Page>();
const [getPost, setPost] = useState({ banner: page, post: blogPost });
async function fetchData() {
try {
const entryRes = await getBlogPostRes(entryUrl);
const bannerRes = await getPageRes('/blog');
if (!entryRes || !bannerRes) throw new Error('Status: ' + 404);
setBlogPost(entryRes);
setPage(bannerRes);
setPost({ banner: bannerRes, post: entryRes });
} catch (error) {
console.error(error);
}
}

useEffect(() => {
onEntryChange(() => fetchData());
}, []);

const { post, banner } = getPost;
return (
<>
{blogPost?.seo && blogPost.seo.enable_search_indexing && metaData(blogPost.seo)}
{banner ? (
<RenderComponents
pageComponents={banner.page_components}
blogPost
contentTypeUid='blog_post'
entryUid={banner?.uid}
locale={banner?.locale}
/>
) : (
<Skeleton height={400} />
)}
<div className='blog-container'>
<article className='blog-detail'>
{post && post.title ? (
<h2 {...post.$?.title as {}}>{post.title}</h2>
) : (
<h2>
<Skeleton />
</h2>
)}
{post && post.date ? (
<p {...post.$?.date as {}}>
{moment(post.date).format('ddd, MMM D YYYY')},{' '}
<strong {...post.author[0].$?.title as {}}>
{post.author[0].title}
</strong>
</p>
) : (
<p>
<Skeleton width={300} />
</p>
)}
{post && post.body ? (
<div {...post.$?.body as {}}>{parse(post.body)}</div>
) : (
<Skeleton height={800} width={600} />
)}
</article>
<div className='blog-column-right'>
<div className='related-post'>
{banner && banner?.page_components[2].widget ? (
<h2 {...banner?.page_components[2].widget.$?.title_h2 as {}}>
{banner?.page_components[2].widget.title_h2}
</h2>
) : (
<h2>
<Skeleton />
</h2>
)}
{post && post.related_post ? (
<ArchiveRelative
{...post.$?.related_post}
blogs={post.related_post}
/>
) : (
<Skeleton width={300} height={500} />
)}
</div>
</div>
</div>
</>
);
}
86 changes: 86 additions & 0 deletions app/blog/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use client';

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, metaData } from '../../helper';

import ArchiveRelative from '../../components/archive-relative';
import Skeleton from 'react-loading-skeleton';
import { Page, PostPage, PageUrl, Context } from "../../typescript/pages";
import { usePathname } from 'next/navigation';


export default function Blog() {
const entryUrl = usePathname();

const [getBanner, setBanner] = useState<Page>();
const [archivePost, setArchivePost] = useState<PostPage>();
const [posts, setPosts] = useState<PostPage>();
async function fetchData() {
try {
const bannerRes = await getPageRes(entryUrl);
if (!bannerRes) throw new Error('Status code 404');
setBanner(bannerRes);

const result: PostPage = await getBlogListRes();
const archivePostRes = [] as any;
const postsRes = [] as any;

result.forEach((blogs) => {
if (blogs.is_archived) {
archivePostRes.push(blogs);
} else {
postsRes.push(blogs);
}
});

setArchivePost(archivePostRes);
setPosts(postsRes);
} catch (error) {
console.error(error);
}
}

useEffect(() => {
onEntryChange(() => fetchData());
}, []);
return (
<>
{getBanner?.seo && getBanner.seo.enable_search_indexing && metaData(getBanner.seo)}
{getBanner?.page_components ? (
<RenderComponents
pageComponents={getBanner.page_components}
blogPost
contentTypeUid='page'
entryUid={getBanner.uid}
locale={getBanner.locale}
/>
) : (
<Skeleton height={400} />
)}
<div className='blog-container'>
<div className='blog-column-left'>
{posts ? (
posts.map((blogList, index) => (
<BlogList bloglist={blogList} key={index} />
))
) : (
<Skeleton height={400} width={400} count={3} />
)}
</div>
<div className='blog-column-right'>
{getBanner && getBanner.page_components[1].widget && (
<h2>{getBanner.page_components[1].widget.title_h2}</h2>
)}
{archivePost ? (
<ArchiveRelative blogs={archivePost} />
) : (
<Skeleton height={600} width={300} />
)}
</div>
</div>
</>
);
}
Loading

0 comments on commit 1b4d7d5

Please sign in to comment.