├── .eslintrc.json ├── netlify.toml ├── public ├── robots.txt ├── images │ ├── blog-1.jpg │ ├── blog-2.jpg │ ├── blog-3.jpg │ ├── blog-4.jpg │ ├── blog-5.jpg │ ├── blog-6.jpg │ ├── logo.png │ ├── favicon.png │ ├── service-slide-1.png │ ├── service-slide-2.png │ ├── service-slide-3.png │ ├── arrow-right.svg │ ├── code.svg │ ├── love.svg │ ├── user-clock.svg │ ├── checkmark-circle.svg │ ├── cloud.svg │ ├── speedometer.svg │ ├── oop.svg │ └── cta.svg └── .htaccess ├── content ├── 404.md ├── blogs │ ├── _index.md │ ├── blog-2.md │ ├── blog-4.md │ ├── blog-1.md │ ├── blog-3.md │ └── blog-5.md ├── contact.md ├── pricing.md ├── elements.md ├── _index.md └── faq.md ├── postcss.config.js ├── styles ├── utilities.scss ├── style.scss ├── base.scss ├── navigation.scss ├── buttons.scss └── components.scss ├── app ├── blogs │ ├── page.js │ ├── [single] │ │ └── page.js │ └── page │ │ └── [slug] │ │ └── page.js ├── not-found.js ├── helper │ └── MDXContent.js ├── page.js ├── [regular] │ └── page.js └── layout.js ├── next.config.js ├── layouts ├── shortcodes │ ├── all.js │ └── Button.jsx ├── components │ ├── YoutubePlayer.js │ ├── TwSizeIndicator.js │ ├── Logo.js │ ├── Cta.js │ ├── Pagination.js │ └── Social.js ├── partials │ ├── Providers.js │ ├── Workflow.js │ ├── HomeBanner.js │ ├── HomeFeatures.js │ ├── Footer.js │ ├── Services.js │ ├── Posts.js │ └── Header.js ├── Default.js ├── 404.js ├── Faq.js ├── PostSingle.js ├── Pricing.js ├── SeoMeta.js └── Contact.js ├── .editorconfig ├── jsconfig.json ├── lib ├── utils │ ├── mdxParser.js │ └── textConverter.js ├── taxonomyParser.js └── contentParser.js ├── config ├── theme.json ├── social.json ├── config.json └── menu.json ├── .gitignore ├── LICENSE ├── package.json ├── tailwind.config.js └── README.md /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [functions] 2 | included_files = ["content/**"] 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | 4 | Disallow: /api/* -------------------------------------------------------------------------------- /content/404.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Error 404" 3 | layout: "404" 4 | --- 5 | 6 | ## Page Not Found 7 | -------------------------------------------------------------------------------- /content/blogs/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Latest news" 3 | description: "this is meta description" 4 | --- 5 | -------------------------------------------------------------------------------- /public/images/blog-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/blog-1.jpg -------------------------------------------------------------------------------- /public/images/blog-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/blog-2.jpg -------------------------------------------------------------------------------- /public/images/blog-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/blog-3.jpg -------------------------------------------------------------------------------- /public/images/blog-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/blog-4.jpg -------------------------------------------------------------------------------- /public/images/blog-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/blog-5.jpg -------------------------------------------------------------------------------- /public/images/blog-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/blog-6.jpg -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/logo.png -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/favicon.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/images/service-slide-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/service-slide-1.png -------------------------------------------------------------------------------- /public/images/service-slide-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/service-slide-2.png -------------------------------------------------------------------------------- /public/images/service-slide-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themefisher/bigspring-light-nextjs/HEAD/public/images/service-slide-3.png -------------------------------------------------------------------------------- /styles/utilities.scss: -------------------------------------------------------------------------------- 1 | b, 2 | strong { 3 | @apply font-semibold; 4 | } 5 | 6 | .shadow { 7 | @apply shadow-[0_12px_24px_-6px_rgba(45,67,121,0.1)] 8 | } 9 | -------------------------------------------------------------------------------- /app/blogs/page.js: -------------------------------------------------------------------------------- 1 | import BlogPagination, { generateStaticParams } from "./page/[slug]/page"; 2 | 3 | export { generateStaticParams }; 4 | export default BlogPagination; 5 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('next').NextConfig} 3 | */ 4 | 5 | const nextConfig = { 6 | reactStrictMode: true, 7 | }; 8 | 9 | module.exports = nextConfig; 10 | -------------------------------------------------------------------------------- /layouts/shortcodes/all.js: -------------------------------------------------------------------------------- 1 | import YoutubePlayer from "../components/YoutubePlayer"; 2 | import Button from "./Button"; 3 | 4 | const shortcodes = { 5 | Button, 6 | YoutubePlayer, 7 | }; 8 | 9 | export default shortcodes; 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; https://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = 2 9 | indent_style = space 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /app/not-found.js: -------------------------------------------------------------------------------- 1 | import NotFound from "@layouts/404"; 2 | import { getRegularPage } from "@lib/contentParser"; 3 | 4 | const notFound = async () => { 5 | const notFoundData = await getRegularPage("404"); 6 | return ; 7 | }; 8 | 9 | export default notFound; 10 | -------------------------------------------------------------------------------- /styles/style.scss: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | @import "base"; 7 | } 8 | 9 | 10 | @layer components { 11 | @import "components"; 12 | @import "navigation"; 13 | @import "buttons"; 14 | } 15 | 16 | @layer utilities { 17 | @import "utilities"; 18 | } 19 | -------------------------------------------------------------------------------- /layouts/components/YoutubePlayer.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import LiteYouTubeEmbed from "react-lite-youtube-embed"; 4 | import "react-lite-youtube-embed/dist/LiteYouTubeEmbed.css"; 5 | 6 | const YoutubePlayer = ({ id, title, ...others }) => { 7 | return ; 8 | }; 9 | 10 | export default YoutubePlayer; 11 | -------------------------------------------------------------------------------- /layouts/partials/Providers.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { usePathname } from "next/navigation"; 3 | import { useEffect } from "react"; 4 | 5 | const Providers = ({ children }) => { 6 | const pathname = usePathname(); 7 | useEffect(() => { 8 | window.scroll(0, 0); 9 | }, [pathname]); 10 | return children; 11 | }; 12 | 13 | export default Providers; 14 | -------------------------------------------------------------------------------- /layouts/shortcodes/Button.jsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link" 2 | 3 | const Button = ({ href, type, rel, children }) => { 4 | return ( 5 | 6 | {children} 7 | 8 | ) 9 | } 10 | 11 | export default Button 12 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@layouts/*": ["layouts/*"], 6 | "@components/*": ["layouts/components/*"], 7 | "@partials/*": ["layouts/partials/*"], 8 | "@shortcodes/*": ["layouts/shortcodes/*"], 9 | "@config/*": ["config/*"], 10 | "@json/*": ["json/*"], 11 | "@hooks/*": ["hooks/*"], 12 | "@lib/*": ["lib/*"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/utils/mdxParser.js: -------------------------------------------------------------------------------- 1 | import { serialize } from "next-mdx-remote/serialize"; 2 | import rehypeSlug from "rehype-slug"; 3 | import remarkGfm from "remark-gfm"; 4 | 5 | // mdx content parser 6 | export const parseMDX = async (content) => { 7 | const options = { 8 | mdxOptions: { 9 | rehypePlugins: [rehypeSlug], 10 | remarkPlugins: [remarkGfm], 11 | }, 12 | }; 13 | return await serialize(content, options); 14 | }; 15 | -------------------------------------------------------------------------------- /content/contact.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Contact Us" 3 | layout: "contact" 4 | draft: false 5 | info: 6 | title: Why you should contact us! 7 | description: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit recusandae voluptates doloremque veniam temporibus porro culpa ipsa, nisi soluta minima saepe laboriosam debitis nesciunt. 8 | contacts: 9 | - "phone: +88 125 256 452" 10 | - "Mail: [info@bigspring.com](mailto:info@bigspring.com)" 11 | - "Address: 360 Main rd, Rio, Brazil" 12 | --- 13 | -------------------------------------------------------------------------------- /public/images/arrow-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors": { 3 | "default": { 4 | "theme_color": { 5 | "primary": "#0aa8a7", 6 | "body": "#fff", 7 | "border": "#e9e9e9", 8 | "theme_light": "#edf6f5" 9 | }, 10 | "text_color": { 11 | "default": "#777", 12 | "dark": "#222" 13 | } 14 | } 15 | }, 16 | "fonts": { 17 | "font_family": { 18 | "primary": "Lato:wght@300;400;700", 19 | "primary_type": "sans-serif" 20 | }, 21 | "font_size": { 22 | "base": "16", 23 | "scale": "1.250" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /layouts/Default.js: -------------------------------------------------------------------------------- 1 | import { markdownify } from "@lib/utils/textConverter"; 2 | import MDXContent from "app/helper/MDXContent"; 3 | 4 | const Default = ({ data }) => { 5 | const { frontmatter, content } = data; 6 | const { title } = frontmatter; 7 | return ( 8 |
9 |
10 | {markdownify(title, "h1", "h2 mb-8 text-center")} 11 |
12 | 13 |
14 |
15 |
16 | ); 17 | }; 18 | 19 | export default Default; 20 | -------------------------------------------------------------------------------- /layouts/404.js: -------------------------------------------------------------------------------- 1 | import { markdownify } from "@lib/utils/textConverter"; 2 | 3 | const NotFound = ({ data }) => { 4 | const { frontmatter, content } = data; 5 | 6 | return ( 7 |
8 |
9 |
10 |
11 |

{frontmatter.title}

12 | {markdownify(content, "div", "content")} 13 |
14 |
15 |
16 |
17 | ); 18 | }; 19 | 20 | export default NotFound; 21 | -------------------------------------------------------------------------------- /public/images/code.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | yarn.lock 8 | package-lock.json 9 | 10 | # testing 11 | /coverage 12 | 13 | # next.js 14 | /.next/ 15 | /out/ 16 | 17 | # production 18 | /build 19 | /.json 20 | 21 | # misc 22 | .DS_Store 23 | *.pem 24 | 25 | # debug 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | .pnpm-debug.log* 30 | 31 | # local env files 32 | .env.local 33 | .env.development.local 34 | .env.test.local 35 | .env.production.local 36 | 37 | # vercel 38 | .vercel 39 | 40 | # Local Netlify folder 41 | .netlify 42 | -------------------------------------------------------------------------------- /lib/taxonomyParser.js: -------------------------------------------------------------------------------- 1 | import { getSinglePages } from "@lib/contentParser"; 2 | import { slugify } from "./utils/textConverter"; 3 | 4 | // get all taxonomies from frontmatter 5 | export const getTaxonomy = (folder, name) => { 6 | const singlePages = getSinglePages(folder); 7 | const taxonomyPages = singlePages.map((page) => page.frontmatter[name]); 8 | let taxonomies = []; 9 | for (let i = 0; i < taxonomyPages.length; i++) { 10 | const categoryArray = taxonomyPages[i]; 11 | for (let j = 0; j < categoryArray.length; j++) { 12 | taxonomies.push(slugify(categoryArray[j])); 13 | } 14 | } 15 | const taxonomy = [...new Set(taxonomies)]; 16 | return taxonomy; 17 | }; 18 | -------------------------------------------------------------------------------- /app/helper/MDXContent.js: -------------------------------------------------------------------------------- 1 | import shortcodes from "@layouts/shortcodes/all"; 2 | import "highlight.js/styles/atom-one-dark.css"; 3 | import { MDXRemote } from "next-mdx-remote/rsc"; 4 | import rehypeHighlight from "rehype-highlight"; 5 | import remarkGfm from "remark-gfm"; 6 | 7 | const MDXContent = ({ content }) => { 8 | const mdxOptions = { 9 | remarkPlugins: [remarkGfm], 10 | rehypePlugins: [rehypeHighlight], 11 | }; 12 | 13 | return ( 14 | <> 15 | {/* @ts-ignore */} 16 | 21 | 22 | ); 23 | }; 24 | 25 | export default MDXContent; 26 | -------------------------------------------------------------------------------- /layouts/partials/Workflow.js: -------------------------------------------------------------------------------- 1 | import { markdownify } from "@lib/utils/textConverter"; 2 | import Image from "next/image"; 3 | 4 | const Workflow = ({ workflow }) => { 5 | return ( 6 |
7 |
8 | {markdownify( 9 | workflow.title, 10 | "h2", 11 | "mx-auto max-w-[400px] font-bold leading-[44px]" 12 | )} 13 | {markdownify(workflow.description, "p", "mt-3")} 14 |
15 | workflow image 21 |
22 | ); 23 | }; 24 | 25 | export default Workflow; 26 | -------------------------------------------------------------------------------- /styles/base.scss: -------------------------------------------------------------------------------- 1 | html { 2 | @apply text-base; 3 | } 4 | 5 | body { 6 | @apply bg-body font-primary font-normal leading-relaxed text-text; 7 | } 8 | 9 | h1, 10 | h2, 11 | h3, 12 | h4, 13 | h5, 14 | h6 { 15 | @apply font-primary font-bold leading-tight text-dark; 16 | } 17 | 18 | h1, 19 | .h1 { 20 | @apply font-primary text-h1-sm md:text-h1; 21 | } 22 | 23 | h2, 24 | .h2 { 25 | @apply text-h2-sm md:text-h2; 26 | } 27 | 28 | h3, 29 | .h3 { 30 | @apply text-h3-sm md:text-h3; 31 | } 32 | 33 | h4, 34 | .h4 { 35 | @apply text-h4; 36 | } 37 | 38 | h5, 39 | .h5 { 40 | @apply text-h5; 41 | } 42 | 43 | h6, 44 | .h6 { 45 | @apply text-h6; 46 | } 47 | 48 | code { 49 | @apply before:hidden after:hidden; 50 | } 51 | -------------------------------------------------------------------------------- /config/social.json: -------------------------------------------------------------------------------- 1 | { 2 | "facebook": "https://facebook.com/", 3 | "twitter": "https://twitter.com/", 4 | "instagram": "", 5 | "youtube": "", 6 | "linkedin": "https://linkedin.com/", 7 | "github": "", 8 | "gitlab": "", 9 | "discord": "", 10 | "slack": "", 11 | "medium": "", 12 | "codepen": "", 13 | "bitbucket": "", 14 | "dribbble": "", 15 | "behance": "", 16 | "pinterest": "", 17 | "soundcloud": "", 18 | "tumblr": "", 19 | "reddit": "", 20 | "vk": "", 21 | "whatsapp": "", 22 | "snapchat": "", 23 | "vimeo": "", 24 | "tiktok": "", 25 | "foursquare": "", 26 | "rss": "", 27 | "email": "", 28 | "phone": "", 29 | "address": "", 30 | "skype": "https://skype.com/", 31 | "website": "" 32 | } 33 | -------------------------------------------------------------------------------- /public/images/love.svg: -------------------------------------------------------------------------------- 1 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/user-clock.svg: -------------------------------------------------------------------------------- 1 | user-clock -------------------------------------------------------------------------------- /styles/navigation.scss: -------------------------------------------------------------------------------- 1 | .header { 2 | @apply bg-white py-[14px] px-4 md:px-0 md:py-[9px]; 3 | } 4 | 5 | // navbar items 6 | .navbar { 7 | @apply relative flex flex-wrap items-center justify-between; 8 | } 9 | 10 | .navbar-brand { 11 | @apply text-xl font-semibold text-dark; 12 | 13 | image { 14 | @apply max-h-full max-w-full; 15 | } 16 | } 17 | 18 | .navbar-nav { 19 | @apply text-center md:text-left; 20 | } 21 | 22 | #nav-menu { 23 | @apply w-full overflow-hidden md:max-h-full md:w-auto; 24 | } 25 | 26 | .nav-item { 27 | @apply lg:mx-3; 28 | 29 | select:focus { 30 | box-shadow: none; 31 | } 32 | } 33 | 34 | .nav-link { 35 | @apply py-3 px-2 font-primary text-base font-bold text-dark transition hover:text-primary md:py-4 lg:px-3; 36 | 37 | &-active { 38 | @apply text-primary; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /public/images/checkmark-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /layouts/components/TwSizeIndicator.js: -------------------------------------------------------------------------------- 1 | const TwSizeIndicator = () => { 2 | if (process.env.NODE_ENV === "development") { 3 | return ( 4 |
5 | all 6 | sm 7 | md 8 | lg 9 | xl 10 | 2xl 11 |
12 | ); 13 | } else { 14 | return null; 15 | } 16 | }; 17 | export default TwSizeIndicator; 18 | -------------------------------------------------------------------------------- /app/blogs/[single]/page.js: -------------------------------------------------------------------------------- 1 | import config from "@config/config.json"; 2 | import PostSingle from "@layouts/PostSingle"; 3 | import { getSinglePage } from "@lib/contentParser"; 4 | const { blog_folder } = config.settings; 5 | 6 | // post single layout 7 | const Article = async ({ params }) => { 8 | const { single } = params; 9 | const posts = await getSinglePage(`content/${blog_folder}`); 10 | const post = posts.filter((p) => p.slug == single); 11 | const { frontmatter, content } = post[0]; 12 | 13 | return ; 14 | }; 15 | 16 | // get post single slug 17 | export const generateStaticParams = () => { 18 | const allSlug = getSinglePage(`content/${blog_folder}`); 19 | const paths = allSlug.map((item) => ({ 20 | single: item.slug, 21 | })); 22 | 23 | return paths; 24 | }; 25 | 26 | export default Article; 27 | -------------------------------------------------------------------------------- /public/images/cloud.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /layouts/Faq.js: -------------------------------------------------------------------------------- 1 | import { markdownify } from "@lib/utils/textConverter"; 2 | 3 | function Faq({ data }) { 4 | const { frontmatter } = data; 5 | const { title, faqs } = frontmatter; 6 | return ( 7 |
8 |
9 | {markdownify(title, "h1", "text-center font-normal")} 10 |
11 | {faqs.map((faq, index) => ( 12 |
13 |
14 |
15 | {markdownify(faq.title, "h4")} 16 |
17 | {markdownify(faq.answer, "p", "faq-body mt-4")} 18 |
19 |
20 | ))} 21 |
22 |
23 |
24 | ); 25 | } 26 | 27 | export default Faq; 28 | -------------------------------------------------------------------------------- /config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "site": { 3 | "title": "Bigspring Light Nextjs", 4 | "base_url": "/", 5 | "favicon": "/images/favicon.png", 6 | "logo": "/images/logo.png", 7 | "logo_width": "200", 8 | "logo_height": "48", 9 | "logo_text": "Bigspring Light" 10 | }, 11 | 12 | "settings": { 13 | "pagination": 4, 14 | "summary_length": 200, 15 | "blog_folder": "blogs" 16 | }, 17 | 18 | "nav_button": { 19 | "enable": true, 20 | "label": "Get Started", 21 | "link": "/contact" 22 | }, 23 | 24 | "params": { 25 | "contact_form_action": "", 26 | "tag_manager_id": "", 27 | "footer_content": "Lorem ipsum dolor sit amet, consectetur elit. Consjat tristique eget amet, tempus eu at cttur.", 28 | "copyright": "Designed and Developed By [Themefisher](https://themefisher.com/)" 29 | }, 30 | 31 | "metadata": { 32 | "meta_author": "Themefisher", 33 | "meta_image": "", 34 | "meta_description": "A SAAS template for nextjs" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /layouts/components/Logo.js: -------------------------------------------------------------------------------- 1 | import config from "@config/config.json"; 2 | import Image from "next/image"; 3 | import Link from "next/link"; 4 | 5 | const Logo = ({ src }) => { 6 | // destructuring items from config object 7 | const { base_url, logo, logo_width, logo_height, logo_text, title } = 8 | config.site; 9 | 10 | return ( 11 | 19 | {src || logo ? ( 20 | {title} 27 | ) : logo_text ? ( 28 | logo_text 29 | ) : ( 30 | title 31 | )} 32 | 33 | ); 34 | }; 35 | 36 | export default Logo; 37 | -------------------------------------------------------------------------------- /styles/buttons.scss: -------------------------------------------------------------------------------- 1 | .btn { 2 | @apply inline-block font-primary font-bold border px-7 py-[17px] leading-[18px] transition; 3 | } 4 | 5 | .btn-primary { 6 | @apply bg-primary text-white border-transparent z-[1] rounded-[30px] relative hover:shadow-[0_12px_24px_-6px_rgba(45,67,121,.1)] transition-all; 7 | 8 | &:after { 9 | @apply w-full h-full rounded-[30px] absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] content-[''] bg-primary transition-all duration-300 ease-in-out -z-[1]; 10 | } 11 | &:hover::after { 12 | @apply w-[110%] h-[110%] 13 | } 14 | } 15 | 16 | .btn-outline-primary { 17 | @apply relative text-text border-0 bg-transparent rounded-[30px] hover:border-transparent hover:text-primary; 18 | 19 | &:after { 20 | @apply w-full h-full rounded-[30px] absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] content-[''] bg-transparent border border-primary transition-all duration-300 ease-in-out z-[0]; 21 | } 22 | &:hover::after { 23 | @apply w-[110%] h-[110%]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 - Present, Themefisher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/page.js: -------------------------------------------------------------------------------- 1 | import config from "@config/config.json"; 2 | import Cta from "@layouts/components/Cta"; 3 | import SeoMeta from "@layouts/SeoMeta"; 4 | 5 | import HomeBanner from "@layouts/partials/HomeBanner"; 6 | import HomeFeatures from "@layouts/partials/HomeFeatures"; 7 | import Services from "@layouts/partials/Services"; 8 | import Workflow from "@layouts/partials/Workflow"; 9 | import { getListPage } from "../lib/contentParser"; 10 | 11 | const Home = async () => { 12 | const homePage = await getListPage("content/_index.md"); 13 | const { frontmatter } = homePage; 14 | const { banner, feature, services, workflow, call_to_action } = frontmatter; 15 | const { title } = config.site; 16 | 17 | return ( 18 | <> 19 | 20 | 21 | {/* Banner */} 22 | 23 | 24 | {/* Features */} 25 | 26 | 27 | {/* services */} 28 | 29 | 30 | {/* workflow */} 31 | 32 | 33 | {/* Cta */} 34 | 35 | 36 | ); 37 | }; 38 | 39 | export default Home; 40 | -------------------------------------------------------------------------------- /layouts/partials/HomeBanner.js: -------------------------------------------------------------------------------- 1 | import { markdownify } from "@lib/utils/textConverter"; 2 | import Image from "next/image"; 3 | import Link from "next/link"; 4 | 5 | const HomeBanner = ({ banner }) => { 6 | return ( 7 |
8 |
9 |
10 |
11 |

{banner.title}

12 |

{markdownify(banner.content)}

13 | {banner.button.enable && ( 14 | 19 | {banner.button.label} 20 | 21 | )} 22 | banner image 30 |
31 |
32 |
33 |
34 | ); 35 | }; 36 | 37 | export default HomeBanner; 38 | -------------------------------------------------------------------------------- /layouts/components/Cta.js: -------------------------------------------------------------------------------- 1 | import { markdownify } from "@lib/utils/textConverter"; 2 | import Image from "next/image"; 3 | import Link from "next/link"; 4 | 5 | function Cta({ cta }) { 6 | return ( 7 |
8 |
9 |
10 |
11 | call to action image 18 |
19 |
20 |

{cta?.title}

21 |

{markdownify(cta?.content)}

22 | {cta.button.enable && ( 23 | 28 | {cta.button.label} 29 | 30 | )} 31 |
32 |
33 |
34 |
35 | ); 36 | } 37 | 38 | export default Cta; 39 | -------------------------------------------------------------------------------- /layouts/partials/HomeFeatures.js: -------------------------------------------------------------------------------- 1 | import { markdownify } from "@lib/utils/textConverter"; 2 | import Image from "next/image"; 3 | 4 | const HomeFeatures = ({ feature }) => { 5 | return ( 6 |
7 |
8 |
9 |

{markdownify(feature.title)}

10 |
11 |
12 | {feature.features.map((item, i) => ( 13 |
17 | {item.icon && ( 18 | 25 | )} 26 |
27 | {markdownify(item.name, "h3", "h5")} 28 |

{item.content}

29 |
30 |
31 | ))} 32 |
33 |
34 |
35 | ); 36 | }; 37 | 38 | export default HomeFeatures; 39 | -------------------------------------------------------------------------------- /content/pricing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pricing 3 | layout: pricing 4 | draft: false 5 | plans: 6 | - title: Basic Plan 7 | subtitle: Best For Small Individuals 8 | price: 49 9 | type: month 10 | features: 11 | - Express Service 12 | - Customs Clearance 13 | - Time-Critical Services 14 | button: 15 | label: Get started for free 16 | link: "/contact" 17 | 18 | - title: Professional Plan 19 | subtitle: Best For Professionals 20 | price: 69 21 | type: month 22 | recommended: true 23 | features: 24 | - Express Service 25 | - Customs Clearance 26 | - Time-Critical Services 27 | - Cloud Service 28 | - Best Dashboard 29 | button: 30 | label: Get started 31 | link: "/contact" 32 | 33 | - title: Business Plan 34 | subtitle: Best For Large Individuals 35 | price: 99 36 | type: month 37 | features: 38 | - Express Service 39 | - Customs Clearance 40 | - Time-Critical Services 41 | button: 42 | label: Get started 43 | link: "/contact" 44 | 45 | call_to_action: 46 | title: Need a larger plan? 47 | content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Consequat tristique eget amet, tempus eu at consecttur. 48 | image: '/images/cta.svg' 49 | button: 50 | enable: true 51 | label: "Contact Us" 52 | link: "/contact" 53 | 54 | --- -------------------------------------------------------------------------------- /layouts/PostSingle.js: -------------------------------------------------------------------------------- 1 | import { markdownify } from "@lib/utils/textConverter"; 2 | import MDXContent from "app/helper/MDXContent"; 3 | import Image from "next/image"; 4 | import SeoMeta from "./SeoMeta"; 5 | 6 | const PostSingle = ({ frontmatter, content }) => { 7 | let { description, title, image } = frontmatter; 8 | description = description ? description : content.slice(0, 120); 9 | 10 | return ( 11 | <> 12 | 13 |
14 |
15 |
16 |
17 | {image && ( 18 | {title} 27 | )} 28 | {markdownify(title, "h1", "h2 mb-6 mt-6 text-left")} 29 | 30 |
31 | 32 |
33 |
34 |
35 |
36 |
37 | 38 | ); 39 | }; 40 | 41 | export default PostSingle; 42 | -------------------------------------------------------------------------------- /config/menu.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": [ 3 | { 4 | "name": "Home", 5 | "url": "/" 6 | }, 7 | { 8 | "name": "Blog", 9 | "url": "/blogs" 10 | }, 11 | { 12 | "name": "Pricing", 13 | "url": "/pricing" 14 | }, 15 | { 16 | "name": "Contact", 17 | "url": "/contact" 18 | }, 19 | { 20 | "name": "FAQ", 21 | "url": "/faq" 22 | } 23 | ], 24 | "footer": [ 25 | { 26 | "name": "Company", 27 | "menu": [ 28 | { 29 | "text": "Pricing", 30 | "url": "/pricing" 31 | }, 32 | { 33 | "text": "Quick Start", 34 | "url": "#" 35 | } 36 | ] 37 | }, 38 | { 39 | "name": "Product", 40 | "menu": [ 41 | { 42 | "text": "Features", 43 | "url": "#" 44 | }, 45 | { 46 | "text": "Platform", 47 | "url": "#" 48 | }, 49 | { 50 | "text": "Pricing", 51 | "url": "/pricing" 52 | } 53 | ] 54 | }, 55 | { 56 | "name": "Support", 57 | "menu": [ 58 | { 59 | "text": "FAQ", 60 | "url": "/faq" 61 | }, 62 | { 63 | "text": "Privacy Policy", 64 | "url": "#" 65 | }, 66 | { 67 | "text": "Terms & Conditions", 68 | "url": "#" 69 | } 70 | ] 71 | } 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bigspring-light-nextjs", 3 | "description": "a nextjs and tailwindcss SAAS starter template", 4 | "version": "2.0.0", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "next dev", 9 | "build": "next build", 10 | "export": "next build && next export", 11 | "lint": "next lint", 12 | "start": "next start" 13 | }, 14 | "dependencies": { 15 | "github-slugger": "^2.0.0", 16 | "gray-matter": "^4.0.3", 17 | "marked": "^14.1.0", 18 | "next": "^14.2.7", 19 | "next-mdx-remote": "^5.0.0", 20 | "react": "^18.3.1", 21 | "react-dom": "^18.3.1", 22 | "react-gtm-module": "^2.0.11", 23 | "react-icons": "^5.3.0", 24 | "react-lite-youtube-embed": "^2.4.0", 25 | "rehype-highlight": "^7.0.0", 26 | "rehype-slug": "^6.0.0", 27 | "remark-gfm": "^4.0.0", 28 | "swiper": "^8.4.5" 29 | }, 30 | "devDependencies": { 31 | "@tailwindcss/forms": "^0.5.8", 32 | "@tailwindcss/typography": "^0.5.15", 33 | "autoprefixer": "^10.4.20", 34 | "date-fns": "^3.6.0", 35 | "date-fns-tz": "^3.1.3", 36 | "eslint": "8.29.0", 37 | "eslint-config-next": "13.0.6", 38 | "jshint": "^2.13.6", 39 | "postcss": "^8.4.42", 40 | "prettier": "^3.3.3", 41 | "prettier-plugin-tailwindcss": "^0.6.6", 42 | "sass": "^1.77.8", 43 | "sharp": "^0.33.5", 44 | "tailwind-bootstrap-grid": "^5.1.0", 45 | "tailwindcss": "^3.4.10" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/[regular]/page.js: -------------------------------------------------------------------------------- 1 | import NotFound from "@layouts/404"; 2 | import Contact from "@layouts/Contact"; 3 | import Default from "@layouts/Default"; 4 | import Faq from "@layouts/Faq"; 5 | import Pricing from "@layouts/Pricing"; 6 | import SeoMeta from "@layouts/SeoMeta"; 7 | import { getRegularPage, getSinglePage } from "@lib/contentParser"; 8 | 9 | // for all regular pages 10 | const RegularPages = async ({ params }) => { 11 | const { regular } = params; 12 | const regularPageData = await getRegularPage(regular); 13 | const { title, meta_title, description, image, noindex, canonical, layout } = 14 | regularPageData.frontmatter; 15 | const { content } = regularPageData; 16 | 17 | return ( 18 | <> 19 | 27 | {layout === "404" ? ( 28 | 29 | ) : layout === "contact" ? ( 30 | 31 | ) : layout === "pricing" ? ( 32 | 33 | ) : layout === "faq" ? ( 34 | 35 | ) : ( 36 | 37 | )} 38 | 39 | ); 40 | }; 41 | export default RegularPages; 42 | 43 | // for regular page routes 44 | export const generateStaticParams = async () => { 45 | const allslugs = await getSinglePage("content"); 46 | const slugs = allslugs.map((item) => item.slug); 47 | const paths = slugs.map((slug) => ({ 48 | regular: slug, 49 | })); 50 | 51 | return paths; 52 | }; 53 | -------------------------------------------------------------------------------- /lib/utils/textConverter.js: -------------------------------------------------------------------------------- 1 | import { slug } from "github-slugger"; 2 | import { marked } from "marked"; 3 | 4 | // slugify 5 | export const slugify = (content) => { 6 | if (!content) return null; 7 | 8 | return slug(content); 9 | }; 10 | 11 | // markdownify 12 | export const markdownify = (content, tag, className) => { 13 | if (!content) return null; 14 | 15 | const Tag = tag; 16 | return tag ? ( 17 | 24 | ) : ( 25 | 31 | ); 32 | }; 33 | 34 | // humanize 35 | export const humanize = (content) => { 36 | if (!content) return null; 37 | 38 | return content 39 | .replace(/^[\s_]+|[\s_]+$/g, "") 40 | .replace(/[_\s]+/g, " ") 41 | .replace(/^[a-z]/, function (m) { 42 | return m.toUpperCase(); 43 | }); 44 | }; 45 | 46 | // plainify 47 | export const plainify = (content) => { 48 | if (!content) return null; 49 | 50 | const mdParsed = marked.parseInline(String(content)); 51 | const filterBrackets = mdParsed.replace(/<\/?[^>]+(>|$)/gm, ""); 52 | const filterSpaces = filterBrackets.replace(/[\r\n]\s*[\r\n]/gm, ""); 53 | const stripHTML = htmlEntityDecoder(filterSpaces); 54 | return stripHTML; 55 | }; 56 | 57 | // strip entities for plainify 58 | const htmlEntityDecoder = (htmlWithEntities) => { 59 | let entityList = { 60 | " ": " ", 61 | "<": "<", 62 | ">": ">", 63 | "&": "&", 64 | """: '"', 65 | "'": "'", 66 | }; 67 | let htmlWithoutEntities = htmlWithEntities.replace( 68 | /(&|<|>|"|')/g, 69 | (entity) => { 70 | return entityList[entity]; 71 | } 72 | ); 73 | return htmlWithoutEntities; 74 | }; 75 | -------------------------------------------------------------------------------- /layouts/partials/Footer.js: -------------------------------------------------------------------------------- 1 | import Social from "@components/Social"; 2 | import config from "@config/config.json"; 3 | import menu from "@config/menu.json"; 4 | import social from "@config/social.json"; 5 | import { markdownify } from "@lib/utils/textConverter"; 6 | import Image from "next/image"; 7 | import Link from "next/link"; 8 | 9 | const Footer = () => { 10 | const { copyright, footer_content } = config.params; 11 | const { footer } = menu; 12 | return ( 13 |
14 |
15 | {/* footer menu */} 16 |
17 | {footer.map((col) => { 18 | return ( 19 |
20 | {markdownify(col.name, "h2", "h4")} 21 |
    22 | {col?.menu.map((item) => ( 23 |
  • 24 | 25 | {item.text} 26 | 27 |
  • 28 | ))} 29 |
30 |
31 | ); 32 | })} 33 | {/* social icons */} 34 |
35 | 36 | 42 | 43 | {markdownify(footer_content, "p", "mt-3 mb-6")} 44 | 45 |
46 |
47 | {/* copyright */} 48 |
49 | {markdownify(copyright, "p", "text-sm text-center")} 50 |
51 |
52 |
53 | ); 54 | }; 55 | 56 | export default Footer; 57 | -------------------------------------------------------------------------------- /layouts/Pricing.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import Cta from "./components/Cta"; 3 | 4 | function Pricing({ data }) { 5 | const { 6 | frontmatter: { title, plans, call_to_action }, 7 | } = data; 8 | return ( 9 | <> 10 |
11 |
12 |

{title}

13 |
14 | {plans.map((plan, index) => ( 15 |
21 |
22 |

{plan.title}

23 |
24 | ${plan.price} 25 | / {plan.type} 26 |
27 |
28 | {plan.subtitle} 29 |
30 |
    31 | {plan.features.map((feature, index) => ( 32 |
  • 33 | {feature} 34 |
  • 35 | ))} 36 |
37 | 44 | {plan.button.label} 45 | 46 |
47 |
48 | ))} 49 |
50 |
51 |
52 | 53 | 54 | ); 55 | } 56 | 57 | export default Pricing; 58 | -------------------------------------------------------------------------------- /public/images/speedometer.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/blogs/page/[slug]/page.js: -------------------------------------------------------------------------------- 1 | import Pagination from "@components/Pagination"; 2 | import config from "@config/config.json"; 3 | import SeoMeta from "@layouts/SeoMeta"; 4 | import { getListPage, getSinglePage } from "@lib/contentParser"; 5 | import { markdownify } from "@lib/utils/textConverter"; 6 | import Posts from "@partials/Posts"; 7 | const { blog_folder } = config.settings; 8 | 9 | // blog pagination 10 | const BlogPagination = async ({ params }) => { 11 | // 12 | const currentPage = parseInt((params && params.slug) || 1); 13 | const { pagination } = config.settings; 14 | const posts = await getSinglePage(`content/${blog_folder}`).sort( 15 | (post1, post2) => 16 | new Date(post2.frontmatter.date) - new Date(post1.frontmatter.date) 17 | ); 18 | const postIndex = await getListPage(`content/${blog_folder}/_index.md`); 19 | // 20 | const indexOfLastPost = currentPage * pagination; 21 | const indexOfFirstPost = indexOfLastPost - pagination; 22 | const totalPages = Math.ceil(posts.length / pagination); 23 | const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost); 24 | const { frontmatter } = postIndex; 25 | const { title } = frontmatter; 26 | 27 | return ( 28 | <> 29 | 30 |
31 |
32 | {markdownify(title, "h1", "h1 text-center font-normal text-[56px]")} 33 | 34 | 39 |
40 |
41 | 42 | ); 43 | }; 44 | 45 | export default BlogPagination; 46 | 47 | export async function generateStaticParams() { 48 | const getAllSlug = await getSinglePage(`content/${blog_folder}`); 49 | const allSlug = getAllSlug.map((item) => item.slug); 50 | const { pagination } = config.settings; 51 | const totalPages = Math.ceil(allSlug.length / pagination); 52 | let paths = []; 53 | 54 | for (let i = 1; i < totalPages; i++) { 55 | paths.push({ 56 | slug: (i + 1).toString(), 57 | }); 58 | } 59 | 60 | return paths; 61 | } 62 | -------------------------------------------------------------------------------- /app/layout.js: -------------------------------------------------------------------------------- 1 | import config from "@config/config.json"; 2 | import theme from "@config/theme.json"; 3 | import TwSizeIndicator from "@layouts/components/TwSizeIndicator"; 4 | import Footer from "@layouts/partials/Footer"; 5 | import Header from "@layouts/partials/Header"; 6 | import Providers from "@layouts/partials/Providers"; 7 | import "../styles/style.scss"; 8 | 9 | export const metadata = { 10 | title: "BigSpring Light Nextjs", 11 | description: "Generated by Next.js", 12 | }; 13 | 14 | export default function RootLayout({ children }) { 15 | const pf = theme.fonts.font_family.primary; 16 | const sf = theme.fonts.font_family.secondary; 17 | return ( 18 | 19 | 20 | {/* responsive meta */} 21 | 25 | 26 | {/* favicon */} 27 | 28 | {/* theme meta */} 29 | 30 | 31 | {/* google font css */} 32 | 37 | 43 | 44 | {/* theme meta */} 45 | 46 | 47 | 52 | 57 | 58 | 59 | 60 |
61 | {children} 62 |