├── .eslintignore ├── .flotiq ├── .env.dist ├── InternalContentTypeMedia │ ├── _media-448eab50-efc1-46ef-83f2-b910b8cc58e0.jpg │ ├── _media-759527ba-b22f-4046-a129-13555d5574d3.jpg │ ├── contentObjectMedia.json │ └── ContentTypeDefinition.json └── ContentTypeBlogpost │ ├── ContentTypeDefinition.json │ └── contentObjectBlogpost.json ├── .prettierignore ├── src ├── assets │ ├── kyan-logo.png │ ├── audio │ │ └── horse.mp3 │ ├── blog-image-1.jpg │ ├── favicons │ │ ├── favicon-16x16.png │ │ └── favicon-32x32.png │ ├── flotiq-logo-badge.svg │ └── flotiq-logo.svg ├── style │ └── global.css ├── components │ ├── blog-post │ │ ├── BlogPostAuthor.js │ │ ├── BlogPostTags.js │ │ ├── BlogPostFeaturedImage.js │ │ ├── BlogPostMetaDetails.js │ │ └── BlogPostNavigation.js │ ├── Announcement.js │ ├── Card.js │ ├── Header.js │ └── Footer.js ├── layouts │ └── layout.js ├── pages │ └── 404.js ├── sections │ └── BlogCards.js └── templates │ ├── index.js │ └── blog-post.js ├── postcss.config.js ├── .prettierrc ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── --anything-else.md │ └── ---bug-report.md └── workflows │ ├── push.yml │ ├── cloudflare_worker.yml │ └── pull_requests.yml ├── gatsby-browser.js ├── wrangler.toml ├── netlify.toml ├── app.json ├── static.json ├── tailwind.config.js ├── LICENSE ├── .gitignore ├── gatsby-node.js ├── worker-index.js ├── package.json ├── .eslintrc.js ├── gatsby-config.js └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.flotiq/.env.dist: -------------------------------------------------------------------------------- 1 | GATSBY_FLOTIQ_API_KEY= 2 | GA_MEASUREMENT_ID=test 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | -------------------------------------------------------------------------------- /src/assets/kyan-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flotiq/flotiq-gatsby-blog-1/HEAD/src/assets/kyan-logo.png -------------------------------------------------------------------------------- /src/assets/audio/horse.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flotiq/flotiq-gatsby-blog-1/HEAD/src/assets/audio/horse.mp3 -------------------------------------------------------------------------------- /src/assets/blog-image-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flotiq/flotiq-gatsby-blog-1/HEAD/src/assets/blog-image-1.jpg -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /src/assets/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flotiq/flotiq-gatsby-blog-1/HEAD/src/assets/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /src/assets/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flotiq/flotiq-gatsby-blog-1/HEAD/src/assets/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": true, 4 | "singleQuote": true, 5 | "tabWidth": 4, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /src/style/global.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html { 6 | scroll-behavior: smooth; 7 | } 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: '/' 5 | schedule: 6 | interval: 'monthly' 7 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import './src/style/global.css'; 2 | import '@fontsource/sora/300.css'; 3 | import '@fontsource/sora/400.css'; 4 | import '@fontsource/sora/600.css'; 5 | -------------------------------------------------------------------------------- /wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "flotiq-gatsby-blog-1" 2 | main = "worker-index.js" 3 | compatibility_date = "2024-03-27" 4 | workers_dev = true 5 | 6 | [site] 7 | bucket = "./public" -------------------------------------------------------------------------------- /.flotiq/InternalContentTypeMedia/_media-448eab50-efc1-46ef-83f2-b910b8cc58e0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flotiq/flotiq-gatsby-blog-1/HEAD/.flotiq/InternalContentTypeMedia/_media-448eab50-efc1-46ef-83f2-b910b8cc58e0.jpg -------------------------------------------------------------------------------- /.flotiq/InternalContentTypeMedia/_media-759527ba-b22f-4046-a129-13555d5574d3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flotiq/flotiq-gatsby-blog-1/HEAD/.flotiq/InternalContentTypeMedia/_media-759527ba-b22f-4046-a129-13555d5574d3.jpg -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "gatsby clean && gatsby build" 3 | publish = "public/" 4 | 5 | [template.environment] 6 | GATSBY_FLOTIQ_API_KEY="YOUR FLOTIQ API KEY" 7 | GA_MEASUREMENT_ID="YOUR GA MEASUREMENT ID" 8 | -------------------------------------------------------------------------------- /src/components/blog-post/BlogPostAuthor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const BlogPostAuthor = ({ additionalClass, authorName }) => ( 4 |

5 | Author: 6 | {authorName} 7 |

8 | ); 9 | 10 | export default BlogPostAuthor; 11 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Gatsby starter boilerplate", 3 | "env":{ 4 | "GATSBY_FLOTIQ_API_KEY": { 5 | "description": "Flotiq API key" 6 | }, 7 | "GA_MEASUREMENT_ID": { 8 | "description": "Google Analytics Measurement ID" 9 | } 10 | }, 11 | "buildpacks": [ 12 | { 13 | "url": "heroku/nodejs" 14 | }, 15 | { 16 | "url": "https://github.com/heroku/heroku-buildpack-static" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/layouts/layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Helmet } from 'react-helmet'; 3 | import Header from '../components/Header'; 4 | import Footer from '../components/Footer'; 5 | 6 | const Layout = ({ children, additionalClass = [] }) => ( 7 |
8 | 9 | 10 | 11 |
12 | {children} 13 |
15 | ); 16 | 17 | export default Layout; 18 | -------------------------------------------------------------------------------- /src/components/blog-post/BlogPostTags.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const BlogPostTags = ({ tags }) => ( 4 |
7 | {tags && tags.map((tag) => ( 8 | 13 | {tag} 14 | 15 | ))} 16 |
17 | ); 18 | 19 | export default BlogPostTags; 20 | -------------------------------------------------------------------------------- /static.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "public/", 3 | "headers": { 4 | "/**": { 5 | "Cache-Control": "public, max-age=0, must-revalidate" 6 | }, 7 | "/**.css": { 8 | "Cache-Control": "public, max-age=31536000, immutable" 9 | }, 10 | "/**.js": { 11 | "Cache-Control": "public, max-age=31536000, immutable" 12 | }, 13 | "/static/**": { 14 | "Cache-Control": "public, max-age=31536000, immutable" 15 | }, 16 | "/icons/*.png": { 17 | "Cache-Control": "public, max-age=31536000, immutable" 18 | } 19 | }, 20 | "https_only": true, 21 | "error_page": "404" 22 | } 23 | -------------------------------------------------------------------------------- /src/components/blog-post/BlogPostFeaturedImage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { GatsbyImage, getImage } from 'gatsby-plugin-image'; 3 | 4 | const BlogPostFeaturedImage = ({ headerImage, title }) => ( 5 |
6 | {headerImage && headerImage[0] && ( 7 | 12 | )} 13 |
14 | ); 15 | 16 | export default BlogPostFeaturedImage; 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--anything-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Anything else" 3 | about: "For help, support, features & ideas - please use https://discord.gg/FwXcHnX" 4 | 5 | --- 6 | 7 | Click "Preview" for a nicer view! 8 | 9 | For support, help, questions, requests and ideas use https://discord.gg/FwXcHnX 10 | 11 | Alternatively, check out these resources below. Thanks! 12 | 13 | - [Discord](https://discord.gg/FwXcHnX) 14 | - [Gatsby API reference](https://docs.ghost.org/api/gatsby/) 15 | - [Content API Docs](https://flotiq.com/docs/panel/) 16 | - [Gatsby.js](https://www.gatsbyjs.org) 17 | - [GraphQL](https://graphql.org/) 18 | -------------------------------------------------------------------------------- /.flotiq/InternalContentTypeMedia/contentObjectMedia.json: -------------------------------------------------------------------------------- 1 | {"id":"_media-448eab50-efc1-46ef-83f2-b910b8cc58e0","url":"/image/0x0/_media-448eab50-efc1-46ef-83f2-b910b8cc58e0.jpg","size":490013,"type":"image","width":1280,"height":718,"source":"disk","fileName":"_media-7a279806-381a-4043-b9f8-b257df70e303.jpg","mimeType":"image/jpeg","extension":"jpg","externalId":""} 2 | {"id":"_media-759527ba-b22f-4046-a129-13555d5574d3","url":"/image/0x0/_media-759527ba-b22f-4046-a129-13555d5574d3.jpg","size":129335,"type":"image","width":1280,"height":718,"source":"disk","fileName":"_media-efbbdb2f-4df3-47c2-9f71-52c6d347fdc9.jpg","mimeType":"image/jpeg","extension":"jpg","externalId":""} -------------------------------------------------------------------------------- /src/components/Announcement.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Announcement as FlotiqAnnouncement } from 'flotiq-components-react'; 3 | 4 | const Announcement = ({ content }) => ( 5 |
6 | 9 | {content} 10 | 11 | )} 12 | additionalClasses={['bg-gradient-to-r', 'from-primary', 'to-secondary']} 13 | textAlignment="center" 14 | textSize="xl" 15 | rounded="lg" 16 | /> 17 |
18 | ); 19 | 20 | export default Announcement; 21 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Helmet } from 'react-helmet'; 3 | import { Button, Header } from 'flotiq-components-react'; 4 | import { Link } from 'gatsby'; 5 | import Layout from '../layouts/layout'; 6 | 7 | const NotFoundPage = () => ( 8 | 9 | 10 | Page not found 11 | 12 |
13 | Page not found, sorry 14 |
15 |
16 | {/* Example usage of button */} 17 |
19 |
20 | ); 21 | 22 | export default NotFoundPage; 23 | -------------------------------------------------------------------------------- /src/sections/BlogCards.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import moment from 'moment'; 3 | import Card from '../components/Card'; 4 | 5 | const BlogCards = ({ posts }) => ( 6 |
7 | {posts.map((post) => ( 8 | 18 | ))} 19 |
20 | ); 21 | 22 | export default BlogCards; 23 | -------------------------------------------------------------------------------- /src/assets/flotiq-logo-badge.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/blog-post/BlogPostMetaDetails.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import BlogPostTags from './BlogPostTags'; 3 | 4 | const BlogPostMetaDetails = ({ date, readingTime, withTags = false, tags, additionalClass }) => ( 5 |
9 |
10 |

11 | Date: 12 | {date} 13 |

14 |

15 | Reading Time: 16 | {readingTime} 17 |

18 |
19 |
20 | {withTags && ( 21 | 22 | )} 23 |
24 | ); 25 | 26 | export default BlogPostMetaDetails; 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Bug report" 3 | about: Report reproducible software issues, so we can improve 4 | 5 | --- 6 | 7 | Welcome to the Gatsby Blog Starter Flotiq GitHub repo! 8 | 9 | For questions related to the usage of Gatsby or GraphQL, please check out their docs at https://www.gatsbyjs.org/ and https://graphql.org/ 10 | 11 | For support, help, questions, requests and ideas use https://discord.gg/FwXcHnX 12 | 13 | If your issue is with Gatsby.js itself, please report it at the Gatsby repo https://github.com/gatsbyjs/gatsby/issues/new. 14 | 15 | ### Issue Summary 16 | 17 | A summary of the issue and the browser/OS environment in which it occurs. 18 | 19 | ### To Reproduce 20 | 21 | 1. This is the first step 22 | 2. This is the second step, etc. 23 | 24 | Any other info e.g. Why do you consider this to be a bug? What did you expect to happen instead? 25 | 26 | ### Technical details: 27 | 28 | * Gatsby Version: 29 | * Node Version: 30 | * OS: 31 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: Push workflow 2 | on: 3 | push: 4 | branches: 5 | - master 6 | schedule: 7 | - cron: "0 8 * * 1" 8 | workflow_dispatch: 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | node-version: [ 20.x ] 15 | steps: 16 | - name: Checkout 🛎️ 17 | uses: actions/checkout@v2 18 | with: 19 | persist-credentials: false 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm install -g gatsby-cli 25 | - run: npm install -g flotiq-cli 26 | - run: flotiq import .flotiq ${{ secrets.GATSBY_FLOTIQ_API_KEY }} 27 | - run: yarn install 28 | - run: gatsby build 29 | env: 30 | GATSBY_FLOTIQ_API_KEY: ${{ secrets.GATSBY_FLOTIQ_API_KEY }} 31 | SNIPCART_API_KEY: 'test' 32 | GA_MEASUREMENT_ID: '' 33 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: [ 3 | './node_modules/flotiq-components-react/dist/**/*.{js,jsx,ts,tsx}', 4 | './src/**/*.{js,jsx,ts,tsx}', 5 | ], 6 | theme: { 7 | extend: { 8 | screens: { 9 | sm: '480px', 10 | md: '768px', 11 | lg: '976px', 12 | xl: '1440px', 13 | }, 14 | colors: { 15 | primary: '#64FBC1', 16 | secondary: '#0083FC', 17 | 'light-gray': '#F9F9F9', 18 | 'olive-green': '#C6FB55', 19 | dark: '#000000', 20 | }, 21 | fontFamily: { 22 | sora: ['Sora', 'sans-serif'], 23 | }, 24 | }, 25 | }, 26 | plugins: [ 27 | require('@tailwindcss/typography'), 28 | ], 29 | presets: [ 30 | require('./node_modules/flotiq-components-react/dist/tailwind.preset'), 31 | ], 32 | safelist: require('./node_modules/flotiq-components-react/dist/tailwind.safelist'), 33 | }; 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Flotiq team 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variable files 55 | .env* 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | .idea/ 72 | .vscode/ 73 | -------------------------------------------------------------------------------- /.github/workflows/cloudflare_worker.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Cloudflare Worker 2 | on: 3 | repository_dispatch: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | deploy: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | node-version: [ 18.x ] 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Use Node.js {{ matrix.node-version }} 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: ${{ matrix.node-version }} 18 | - name: Check if Flotiq API key is set. 19 | env: 20 | GATSBY_FLOTIQ_API_KEY: ${{ secrets.GATSBY_FLOTIQ_API_KEY }} 21 | run: | 22 | if [ -z "$GATSBY_FLOTIQ_API_KEY" ]; then 23 | echo "Flotiq API Key is not set, using a starter one." && echo "GATSBY_FLOTIQ_API_KEY=23a419dd26f2dbe61cf37c3625cf77de" >> $GITHUB_ENV 24 | else 25 | echo "Using user-provided Flotiq API Key. Importing starter data to Flotiq." && echo "GATSBY_FLOTIQ_API_KEY=$GATSBY_FLOTIQ_API_KEY" >> $GITHUB_ENV 26 | npm install -g flotiq-cli 27 | flotiq import .flotiq $GATSBY_FLOTIQ_API_KEY 28 | fi 29 | - run: npm install -g gatsby-cli 30 | - run: yarn install 31 | - run: gatsby build 32 | - name: Build & Deploy Worker 33 | uses: cloudflare/wrangler-action@v3 34 | with: 35 | apiToken: ${{ secrets.CF_API_TOKEN }} 36 | accountId: ${{ secrets.CF_ACCOUNT_ID }} 37 | -------------------------------------------------------------------------------- /.github/workflows/pull_requests.yml: -------------------------------------------------------------------------------- 1 | name: PR workflow 2 | on: pull_request 3 | 4 | permissions: 5 | pull-requests: write 6 | 7 | jobs: 8 | test-build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | node-version: [ 20.x ] 13 | steps: 14 | - name: Checkout 🛎️ 15 | uses: actions/checkout@v2 16 | with: 17 | persist-credentials: false 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | - run: npm install -g gatsby-cli 23 | - run: npm install -g flotiq-cli 24 | - run: flotiq import .flotiq ${{ secrets.GATSBY_FLOTIQ_API_KEY }} 25 | - run: yarn install 26 | - run: gatsby build 27 | env: 28 | GATSBY_FLOTIQ_API_KEY: ${{ secrets.GATSBY_FLOTIQ_API_KEY }} 29 | SNIPCART_API_KEY: 'test' 30 | GA_MEASUREMENT_ID: '' 31 | dependabot: 32 | needs: test-build 33 | permissions: 34 | pull-requests: write 35 | runs-on: ubuntu-latest 36 | if: github.actor == 'dependabot[bot]' 37 | steps: 38 | - name: Dependabot metadata 39 | id: metadata 40 | uses: dependabot/fetch-metadata@v1 41 | with: 42 | github-token: "${{ secrets.GITHUB_TOKEN }}" 43 | - name: Approve a PR 44 | run: gh pr review --approve "$PR_URL" 45 | env: 46 | PR_URL: ${{github.event.pull_request.html_url}} 47 | GH_TOKEN: ${{secrets.GITHUB_TOKEN}} 48 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | exports.createPages = async ({ graphql, actions }) => { 4 | const { createPage } = actions; 5 | 6 | const blogPost = path.resolve('./src/templates/blog-post.js'); 7 | const result = await graphql(` 8 | query GetBlogPosts { 9 | allBlogpost(sort: {flotiqInternal: {createdAt: DESC}}) { 10 | edges { 11 | node { 12 | slug 13 | } 14 | } 15 | } 16 | } 17 | `); 18 | 19 | if (result.errors) { 20 | throw result.errors; 21 | } 22 | const posts = result.data.allBlogpost.edges; 23 | 24 | // Create paginated index 25 | const postsPerPage = 4; 26 | const numPages = Math.ceil(posts.length / postsPerPage); 27 | 28 | Array.from({ length: numPages }).forEach((item, i) => { 29 | createPage({ 30 | path: i === 0 ? '/' : `/${i + 1}`, 31 | component: path.resolve('./src/templates/index.js'), 32 | context: { 33 | limit: postsPerPage, 34 | skip: i * postsPerPage, 35 | numPages, 36 | currentPage: i + 1, 37 | }, 38 | }); 39 | }); 40 | 41 | // Create blog posts pages. 42 | posts.forEach((post, index) => { 43 | const previous = index === posts.length - 1 ? null : posts[index + 1].node; 44 | const next = index === 0 ? null : posts[index - 1].node; 45 | 46 | createPage({ 47 | path: post.node.slug, 48 | component: blogPost, 49 | context: { 50 | slug: post.node.slug, 51 | previous, 52 | next, 53 | }, 54 | }); 55 | }); 56 | }; 57 | -------------------------------------------------------------------------------- /src/components/blog-post/BlogPostNavigation.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ArrowNarrowLeftIcon, ArrowNarrowRightIcon } from '@heroicons/react/solid'; 3 | import { Link } from 'gatsby'; 4 | 5 | const BlogPostNavigation = ({ additionalClass, prevText, nextText, pageContext }) => ( 6 | 32 | ); 33 | 34 | export default BlogPostNavigation; 35 | -------------------------------------------------------------------------------- /src/templates/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Helmet } from 'react-helmet'; 3 | import { graphql } from 'gatsby'; 4 | import { Pagination } from 'flotiq-components-react'; 5 | import Layout from '../layouts/layout'; 6 | import BlogCards from '../sections/BlogCards'; 7 | import Announcement from '../components/Announcement'; 8 | 9 | const IndexPage = ({ data, pageContext }) => { 10 | const posts = data.allBlogpost.nodes; 11 | return ( 12 | 13 | 14 | {data.site.siteMetadata.title} 15 | 19 | 20 | 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export const pageQuery = graphql` 30 | query indexQuery($skip: Int!, $limit: Int!) { 31 | site { 32 | siteMetadata { 33 | title 34 | description 35 | } 36 | } 37 | allBlogpost( 38 | sort: {flotiqInternal: {createdAt: DESC}} 39 | limit: $limit 40 | skip: $skip 41 | ) { 42 | nodes { 43 | headerImage { 44 | extension 45 | url 46 | width 47 | height 48 | localFile { 49 | publicURL 50 | childImageSharp { 51 | gatsbyImageData(layout: FULL_WIDTH, placeholder: NONE, formats: [AUTO, WEBP, AVIF]) 52 | } 53 | } 54 | } 55 | id 56 | excerpt 57 | slug 58 | title 59 | flotiqInternal { 60 | createdAt 61 | } 62 | } 63 | } 64 | } 65 | `; 66 | 67 | export default IndexPage; 68 | -------------------------------------------------------------------------------- /worker-index.js: -------------------------------------------------------------------------------- 1 | import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler' 2 | 3 | /** 4 | * The DEBUG flag will do two things that help during development: 5 | * 1. we will skip caching on the edge, which makes it easier to 6 | * debug. 7 | * 2. we will return an error message on exception in your Response rather 8 | * than the default 404.html page. 9 | */ 10 | const DEBUG = false 11 | 12 | addEventListener('fetch', event => { 13 | try { 14 | event.respondWith(handleEvent(event)) 15 | } catch (e) { 16 | if (DEBUG) { 17 | return event.respondWith( 18 | new Response(e.message || e.toString(), { 19 | status: 500, 20 | }), 21 | ) 22 | } 23 | event.respondWith(new Response('Internal Error', { status: 500 })) 24 | } 25 | }) 26 | 27 | async function handleEvent(event) { 28 | const url = new URL(event.request.url) 29 | let options = {} 30 | 31 | /** 32 | * You can add custom logic to how we fetch your assets 33 | * by configuring the function `mapRequestToAsset` 34 | */ 35 | // options.mapRequestToAsset = handlePrefix(/^\/docs/) 36 | 37 | try { 38 | if (DEBUG) { 39 | // customize caching 40 | options.cacheControl = { 41 | bypassCache: true, 42 | } 43 | } 44 | return await getAssetFromKV(event, options) 45 | } catch (e) { 46 | // if an error is thrown try to serve the asset at 404.html 47 | if (!DEBUG) { 48 | try { 49 | let notFoundResponse = await getAssetFromKV(event, { 50 | mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req), 51 | }) 52 | 53 | return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 }) 54 | } catch (e) {} 55 | } 56 | 57 | return new Response(e.message || e.toString(), { status: 500 }) 58 | } 59 | } 60 | 61 | /** 62 | * Here's one example of how to modify a request to 63 | * remove a specific prefix, in this case `/docs` from 64 | * the url. This can be useful if you are deploying to a 65 | * route on a zone, or if you only want your static content 66 | * to exist at a specific path. 67 | */ 68 | function handlePrefix(prefix) { 69 | return request => { 70 | // compute the default (e.g. / -> index.html) 71 | let defaultAssetKey = mapRequestToAsset(request) 72 | let url = new URL(defaultAssetKey.url) 73 | 74 | // strip the prefix from the path for lookup 75 | url.pathname = url.pathname.replace(prefix, '/') 76 | 77 | // inherit all other props from the default request 78 | return new Request(url.toString(), defaultAssetKey) 79 | } 80 | } -------------------------------------------------------------------------------- /src/components/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'gatsby'; 3 | import { Card } from 'flotiq-components-react'; 4 | import { GatsbyImage, getImage } from 'gatsby-plugin-image'; 5 | import BlogPostTags from './blog-post/BlogPostTags'; 6 | 7 | const CustomCard = ({ title, excerpt, date, readingTime, withTags = false, tags, image, slug }) => { 8 | return ( 9 | 19 | 24 | 25 |
26 | 27 | {title} 28 | 29 | 30 | {excerpt} 31 | 32 |
33 | 34 |
35 | {withTags && ( 36 | 37 | )} 38 | 39 |
40 |

41 | Date: 42 | {' '} 43 | {date} 44 |

45 |

46 | Reading time: 47 | {' '} 48 | {readingTime} 49 |

50 |
51 | 52 |
53 |
54 | 55 |
56 | {image && ( 57 | 58 | )} 59 |
60 | 61 |
62 | ); 63 | }; 64 | 65 | export default CustomCard; 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flotiq-gatsby-blog-1", 3 | "private": true, 4 | "description": "A blog starter for Gatsby", 5 | "version": "1.0.0", 6 | "license": "MIT", 7 | "author": "Flotiq team (https://flotiq.com/)", 8 | "scripts": { 9 | "build": "gatsby build", 10 | "develop": "gatsby develop", 11 | "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"", 12 | "start": "gatsby develop", 13 | "serve": "gatsby serve", 14 | "clean": "gatsby clean", 15 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1" 16 | }, 17 | "dependencies": { 18 | "@fontsource/sora": "^5.1.1", 19 | "@headlessui/react": "^2.2.0", 20 | "@heroicons/react": "1.0.6", 21 | "@popperjs/core": "^2.11.8", 22 | "@tailwindcss/typography": "^0.5.16", 23 | "flotiq-components-react": "^2.0.2", 24 | "gatsby": "^5.14.1", 25 | "gatsby-plugin-gatsby-cloud": "^5.14.0", 26 | "gatsby-plugin-google-gtag": "^5.14.0", 27 | "gatsby-plugin-image": "^3.14.0", 28 | "gatsby-plugin-manifest": "^5.14.0", 29 | "gatsby-plugin-react-helmet": "^6.14.0", 30 | "gatsby-plugin-robots-txt": "^1.8.0", 31 | "gatsby-plugin-sharp": "^5.14.0", 32 | "gatsby-plugin-sitemap": "^6.14.0", 33 | "gatsby-source-filesystem": "^5.14.0", 34 | "gatsby-source-flotiq": "^5.3.1", 35 | "gatsby-transformer-sharp": "^5.14.0", 36 | "moment": "^2.30.1", 37 | "node": "^23.7.0", 38 | "react": "^18.3.1", 39 | "react-dom": "^18.3.1", 40 | "react-helmet": "^6.1.0", 41 | "typescript": "^5.7.3", 42 | "webpack": "^5.97.1" 43 | }, 44 | "devDependencies": { 45 | "@babel/core": "^7.26.7", 46 | "@babel/eslint-parser": "^7.26.5", 47 | "@babel/plugin-syntax-flow": "^7.26.0", 48 | "@babel/plugin-transform-react-jsx": "^7.25.9", 49 | "@babel/preset-react": "^7.26.3", 50 | "@hot-loader/react-dom": "17.0.2", 51 | "@typescript-eslint/parser": "^8.22.0", 52 | "autoprefixer": "^10.4.20", 53 | "babel-eslint": "^10.1.0", 54 | "cross-env": "^7.0.3", 55 | "dotenv": "^16.4.7", 56 | "eslint": "^8.57.1", 57 | "eslint-config-airbnb": "^19.0.4", 58 | "eslint-config-react-app": "^7.0.1", 59 | "eslint-plugin-flowtype": "^8.0.3", 60 | "eslint-plugin-import": "^2.31.0", 61 | "eslint-plugin-jsx": "^0.1.0", 62 | "eslint-plugin-jsx-a11y": "^6.10.2", 63 | "eslint-plugin-react": "^7.37.4", 64 | "eslint-plugin-react-hooks": "^5.1.0", 65 | "gatsby-plugin-postcss": "^6.14.0", 66 | "postcss": "^8.5.1", 67 | "prettier": "^3.4.2", 68 | "tailwindcss": "^3.4.17" 69 | }, 70 | "repository": { 71 | "type": "git", 72 | "url": "https://github.com/flotiq/flotiq-gatsby-blog-1" 73 | }, 74 | "bugs": { 75 | "url": "https://github.com/flotiq/flotiq-gatsby-blog-1/issues" 76 | }, 77 | "resolutions": { 78 | "webpack": "^5.97.1" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | es6: true, 6 | }, 7 | parser: '@babel/eslint-parser', 8 | parserOptions: { 9 | requireConfigFile: false, 10 | babelOptions: { 11 | presets: ['@babel/preset-react'], 12 | }, 13 | }, 14 | extends: [ 15 | 'react-app', 16 | ], 17 | plugins: [ 18 | 'flowtype', 19 | ], 20 | rules: { 21 | /* Restrict file extensions that may contain JSX */ 22 | 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], 23 | /* This rule will warn when it encounters a reference to an identifier that has not yet been declared. */ 24 | 'no-use-before-define': ['error', { variables: false }], 25 | /* This rule enforces consistent line breaks inside braces of object literals or destructuring assignments. */ 26 | 'object-curly-newline': ['error', { ImportDeclaration: 'never' }], 27 | /* Enforce consistent usage of destructuring assignment of props, state, and context */ 28 | 'react/destructuring-assignment': 0, 29 | /* Prevent missing props validation in a React component definition */ 30 | 'react/prop-types': 0, 31 | /* Enforce require() on the top-level module scope */ 32 | 'global-require': 0, 33 | indent: ['error', 4], 34 | /* This rule is aimed to enforce consistent indentation style */ 35 | 'react/jsx-indent': ['error', 4], 36 | /* This rule is aimed to enforce consistent indentation style */ 37 | 'react/jsx-indent-props': ['error', 4], 38 | /* Enforces that there is no spreading for any JSX attribute. 39 | This enhances readability of code by being more explicit about what props are received by the component. */ 40 | 'react/jsx-props-no-spreading': 'off', 41 | 'max-len': ['error', { code: 120 }], 42 | /* Enforces the rule of https://reactjs.org/docs/hooks-rules.html */ 43 | 'react-hooks/rules-of-hooks': 'error', 44 | /* This is a new ESLint rule that verifies the list of dependencies for Hooks like useEffect and similar, 45 | protecting against the stale closure pitfalls. For most cases it has an autofix. */ 46 | 'react-hooks/exhaustive-deps': 'warn', 47 | /* This rules enforces an explicit type attribute for all the button elements 48 | and checks that its value is valid per spec */ 49 | 'react/button-has-type': 0, 50 | 'react/state-in-constructor': 0, 51 | 'react/jsx-fragments': 0, 52 | 'guard-for-in': 0, 53 | 'no-underscore-dangle': 0, 54 | 'jsx-a11y/click-events-have-key-events': 0, 55 | 'jsx-a11y/no-static-element-interactions': 0, 56 | 'react/function-component-definition': [1, { 57 | namedComponents: 'arrow-function', 58 | }], 59 | }, 60 | }; 61 | -------------------------------------------------------------------------------- /.flotiq/ContentTypeBlogpost/ContentTypeDefinition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blogpost", 3 | "label": "Blog Post", 4 | "internal": false, 5 | "schemaDefinition": { 6 | "type": "object", 7 | "allOf": [ 8 | { 9 | "$ref": "#/components/schemas/AbstractContentTypeSchemaDefinition" 10 | }, 11 | { 12 | "type": "object", 13 | "properties": { 14 | "slug": { 15 | "type": "string", 16 | "pattern": "^[a-zA-Z0-9-_]*$", 17 | "minLength": 1 18 | }, 19 | "title": { 20 | "type": "string", 21 | "minLength": 1 22 | }, 23 | "content": { 24 | "type": "object", 25 | "minLength": 1, 26 | "properties": { 27 | "time": { 28 | "type": "number" 29 | }, 30 | "blocks": { 31 | "type": "array", 32 | "items": { 33 | "type": "object", 34 | "properties": { 35 | "id": { 36 | "type": "string" 37 | }, 38 | "data": { 39 | "type": "object", 40 | "properties": { 41 | "text": { 42 | "type": "string" 43 | } 44 | }, 45 | "additionalProperties": true 46 | }, 47 | "type": { 48 | "type": "string" 49 | } 50 | } 51 | } 52 | }, 53 | "version": { 54 | "type": "string" 55 | } 56 | }, 57 | "additionalProperties": false 58 | }, 59 | "excerpt": { 60 | "type": "string", 61 | "minLength": 1 62 | }, 63 | "headerImage": { 64 | "type": "array", 65 | "items": { 66 | "$ref": "#/components/schemas/DataSource" 67 | }, 68 | "minItems": 0 69 | } 70 | } 71 | } 72 | ], 73 | "required": [ 74 | "title", 75 | "slug", 76 | "excerpt", 77 | "content" 78 | ], 79 | "additionalProperties": false 80 | }, 81 | "metaDefinition": { 82 | "order": [ 83 | "title", 84 | "slug", 85 | "excerpt", 86 | "content", 87 | "headerImage" 88 | ], 89 | "propertiesConfig": { 90 | "slug": { 91 | "label": "Slug", 92 | "unique": true, 93 | "helpText": "Slug can only have alphanumerical characters, - and _", 94 | "inputType": "text" 95 | }, 96 | "title": { 97 | "label": "Title", 98 | "unique": false, 99 | "helpText": "", 100 | "inputType": "text", 101 | "isTitlePart": true 102 | }, 103 | "content": { 104 | "label": "Content", 105 | "unique": false, 106 | "helpText": "", 107 | "inputType": "block" 108 | }, 109 | "excerpt": { 110 | "label": "Excerpt", 111 | "unique": false, 112 | "helpText": "", 113 | "inputType": "textarea" 114 | }, 115 | "headerImage": { 116 | "label": "Header image", 117 | "unique": false, 118 | "helpText": "", 119 | "inputType": "datasource", 120 | "validation": { 121 | "relationContenttype": "_media" 122 | } 123 | } 124 | } 125 | }, 126 | "featuredImage": [] 127 | } 128 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Configure your Gatsby site with this file. 3 | * 4 | * See: https://www.gatsbyjs.com/docs/gatsby-config/ 5 | */ 6 | 7 | // eslint-disable-next-line import/no-extraneous-dependencies 8 | require('dotenv').config({ 9 | path: `.env.${process.env.NODE_ENV}`, 10 | }); 11 | 12 | module.exports = { 13 | siteMetadata: { 14 | title: 'Flotiq gatsby starter for blog', 15 | description: 'Flotiq gatsby starter for blog', 16 | siteUrl: 'https://flotiqgatsbyblog1master.gatsbyjs.io', 17 | }, 18 | plugins: [ 19 | { 20 | // How to configure? https://www.gatsbyjs.com/plugins/gatsby-plugin-google-gtag/ 21 | // Video: https://www.youtube.com/watch?v=Dwi99jtl3Fs 22 | resolve: 'gatsby-plugin-google-gtag', 23 | options: { 24 | trackingIds: [ 25 | process.env.GA_MEASUREMENT_ID || 'test', // GA Measurement 26 | ], 27 | gtagConfig: { 28 | optimize_id: 'OPT_CONTAINER_ID', 29 | anonymize_ip: true, 30 | cookie_expires: 0, 31 | }, 32 | pluginConfig: { 33 | head: true, 34 | respectDNT: true, 35 | exclude: ['/preview/**', '/do-not-track/me/too/'], 36 | }, 37 | }, 38 | }, 39 | 'gatsby-plugin-react-helmet', 40 | 'gatsby-plugin-sitemap', 41 | { 42 | resolve: 'gatsby-source-flotiq', 43 | options: { 44 | authToken: process.env.GATSBY_FLOTIQ_API_KEY, 45 | downloadMediaFile: true, 46 | forceReload: false, 47 | includeTypes: [ 48 | '_media', 49 | '_tag', 50 | 'blogpost', 51 | ], 52 | }, 53 | }, 54 | { 55 | resolve: 'gatsby-source-filesystem', 56 | options: { 57 | name: 'placeholder', 58 | path: `${__dirname}/gatsby-config.js`, 59 | }, 60 | }, 61 | 'gatsby-plugin-image', 62 | { 63 | resolve: 'gatsby-plugin-sharp', 64 | options: { 65 | defaults: { 66 | quality: 80, 67 | }, 68 | base64Width: 20, 69 | }, 70 | }, 71 | 'gatsby-transformer-sharp', 72 | { 73 | resolve: 'gatsby-plugin-robots-txt', 74 | options: { 75 | host: 'https://flotiqgatsbyblog1master.gatsbyjs.io', 76 | sitemap: 'https://flotiqgatsbyblog1master.gatsbyjs.io/sitemap.xml', 77 | policy: [{ userAgent: '*', allow: '/' }], 78 | }, 79 | }, 80 | { 81 | resolve: 'gatsby-plugin-manifest', 82 | options: { 83 | icon: 'src/assets/favicons/favicon-16x16.png', 84 | icons: [ 85 | { 86 | src: 'src/assets/favicons/favicon-32x32.png', 87 | sizes: '32x32', 88 | type: 'image/png', 89 | }, 90 | { 91 | src: 'src/assets/favicons/favicon-16x16.png', 92 | sizes: '16x16', 93 | type: 'image/png', 94 | }, 95 | ], 96 | }, 97 | }, 98 | 'gatsby-plugin-postcss', 99 | { 100 | resolve: 'gatsby-plugin-gatsby-cloud', 101 | options: { 102 | headers: { 103 | '/*': [ 104 | 'x-frame-options: allow-from https://jamstackthemes.dev/', 105 | ], 106 | }, 107 | }, 108 | }, 109 | ], 110 | }; 111 | -------------------------------------------------------------------------------- /src/components/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Disclosure } from '@headlessui/react'; 3 | import { MenuIcon, XIcon } from '@heroicons/react/outline'; 4 | import { Link } from 'gatsby'; 5 | import Logo from '../assets/kyan-logo.png'; 6 | 7 | const Header = () => ( 8 | 9 | {({ open }) => ( 10 | <> 11 |
12 |
13 |
14 |
15 | 20 | Open main menu 21 | {open ? ( 22 | 27 |
28 |
29 | 30 | Flotiq 35 | 36 |
37 |
38 |
39 |

Blog About Everything

40 |
41 |
42 | 59 |
60 |
61 |

Blog About Everything

62 |
63 |
64 |
65 | 66 | 67 |
68 |
69 |

Menu content here...

70 |
71 |
72 |
73 | 74 | )} 75 |
76 | ); 77 | 78 | export default Header; 79 | -------------------------------------------------------------------------------- /src/assets/flotiq-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'gatsby'; 3 | import { PoweredByFlotiq } from 'flotiq-components-react'; 4 | import Logo from '../assets/kyan-logo.png'; 5 | 6 | const navigation = { 7 | social: [ 8 | { 9 | name: 'Facebook', 10 | href: 'https://www.facebook.com/flotiq', 11 | icon: (props) => ( 12 | 13 | 21 | 22 | ), 23 | }, 24 | { 25 | name: 'LinkedIn', 26 | href: 'https://www.linkedin.com/company/flotiq/', 27 | icon: (props) => ( 28 | 29 | 30 | 35 | 36 | 37 | ), 38 | }, 39 | { 40 | name: 'Link', 41 | href: 'https://flotiq.com', 42 | icon: (props) => ( 43 | 44 | 52 | 59 | 60 | ), 61 | }, 62 | ], 63 | }; 64 | 65 | const CopyrightNotice = () => { 66 | const currentYear = new Date(); 67 | const date = currentYear.getFullYear(); 68 | return ( 69 | 70 | Copyright © Flotiq 71 | {date} 72 | 73 | ); 74 | }; 75 | 76 | const Footer = () => ( 77 |
78 |
79 |
82 | 83 | Flotiq 88 | 89 |
90 | {navigation.social.map((item) => ( 91 | 99 | {item.name} 100 | 102 | ))} 103 |
104 |
105 |
108 | 109 |

110 | {CopyrightNotice()} 111 |

112 |
113 |
114 |
115 | ); 116 | 117 | export default Footer; 118 | -------------------------------------------------------------------------------- /.flotiq/ContentTypeBlogpost/contentObjectBlogpost.json: -------------------------------------------------------------------------------- 1 | {"id":"blogpost-1","slug":"hello-my-blog","title":"Hello There!","content":{"time":1643368254832,"blocks":[{"id":"CzLBZad8_Z","data":{"text":"Flotiq strongly encourages separation of concerns and isolates the data from the presentation layer (unlike traditional CMS like WordPress). Thanks to that - you can easily use your data anywhere you need them"},"type":"paragraph","tunes":{"alignmentTuneTool":{"alignment":"left"}}},{"id":"611qBrxLXR","data":{"text":"# Header 2","level":2,"anchor":""},"type":"header","tunes":{"alignmentTuneTool":{"alignment":"left"}}},{"id":"JhlGMXHeiN","data":{"text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse pharetra eget augue at vulputate. Sed lacus lacus, facilisis quis rutrum sed, tincidunt vehicula orci. Morbi nibh ante, iaculis eget consectetur vitae, placerat eget mauris. Pellentesque in justo faucibus, tempor ex at, sollicitudin enim. Donec auctor massa eget nisl fringilla, sit amet suscipit ipsum aliquet. Phasellus pellentesque lacus ut diam molestie tincidunt. Vivamus ac pellentesque lectus. Nullam nec magna non justo efficitur molestie scelerisque nec urna. Integer nibh ante, euismod non laoreet quis, blandit at lectus. Etiam id tortor eget justo sollicitudin ultrices eu vel mi."},"type":"paragraph","tunes":{"alignmentTuneTool":{"alignment":"left"}}},{"id":"9RI4AFFGUX","data":{"text":"# Header 3","level":3,"anchor":""},"type":"header","tunes":{"alignmentTuneTool":{"alignment":"left"}}},{"id":"6FPNOG_n69","data":{"text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse pharetra eget augue at vulputate. Sed lacus lacus, facilisis quis rutrum sed, tincidunt vehicula orci. Morbi nibh ante, iaculis eget consectetur vitae, placerat eget mauris. Pellentesque in justo faucibus, tempor ex at, sollicitudin enim. Donec auctor massa eget nisl fringilla, sit amet suscipit ipsum aliquet. Phasellus pellentesque lacus ut diam molestie tincidunt. Vivamus ac pellentesque lectus. Nullam nec magna non justo efficitur molestie scelerisque nec urna. Integer nibh ante, euismod non laoreet quis, blandit at lectus. Etiam id tortor eget justo sollicitudin ultrices eu vel mi."},"type":"paragraph","tunes":{"alignmentTuneTool":{"alignment":"left"}}},{"id":"RQddK_jT0f","data":{"url":"https://api.flotiq.com/image/0x0/_media-4e30edc8-d1b5-45a1-842a-80f5e8467121.mp3","width":0,"height":0,"caption":"Example audio file","fileName":"file_example_MP3_700KB.mp3","extension":"mp3","withBorder":false,"withBackground":false},"type":"image"},{"id":"rCmkjFRy5s","data":{"text":"# Header 4","level":4,"anchor":""},"type":"header","tunes":{"alignmentTuneTool":{"alignment":"left"}}},{"id":"qfU92mppy-","data":{"text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse pharetra eget augue at vulputate. Sed lacus lacus, facilisis quis rutrum sed, tincidunt vehicula orci. Morbi nibh ante, iaculis eget consectetur vitae, placerat eget mauris. Pellentesque in justo faucibus, tempor ex at, sollicitudin enim. Donec auctor massa eget nisl fringilla, sit amet suscipit ipsum aliquet. Phasellus pellentesque lacus ut diam molestie tincidunt. Vivamus ac pellentesque lectus. Nullam nec magna non justo efficitur molestie scelerisque nec urna. Integer nibh ante, euismod non laoreet quis, blandit at lectus. Etiam id tortor eget justo sollicitudin ultrices eu vel mi."},"type":"paragraph","tunes":{"alignmentTuneTool":{"alignment":"left"}}},{"id":"08aVnYiuCM","data":{"url":"https://api.flotiq.com/image/0x0/_media-51bf075b-08ed-48b4-a41c-586db3e95bf9.jpg","width":1124,"height":423,"caption":"Example image","fileName":"blog-image-1.jpg","extension":"jpg","withBorder":false,"withBackground":false},"type":"image"},{"id":"40BeHKLydT","data":{"text":"If you’re a beginning website owner you might be wondering what a CMS is and if you need one. This article will look at some valid reasons to invest in a CMS, but also will try to shed some light on the caveats, so read on."},"type":"paragraph","tunes":{"alignmentTuneTool":{"alignment":"left"}}},{"id":"1mSuuq5B_s","data":{"items":[{"items":[],"content":"Websites"},{"items":[],"content":"Mobile apps"},{"items":[],"content":"Billboard advertising"},{"items":[],"content":"Desktop applications"},{"items":[],"content":"Amazon Lambda functions"},{"items":[],"content":"Mailing systems"}],"style":"unordered"},"type":"list"},{"id":"EcfJHKzMwA","data":{"text":"If you’re a beginning website owner you might be wondering what a CMS is and if you need one. This article will look at some valid reasons to invest in a CMS, but also will try to shed some light on the caveats, so read on.","caption":"Flotiq","alignment":"left"},"type":"quote"}],"version":"2.22.0"},"excerpt":"If you’re a beginning website owner you might be wondering what a CMS is and if you need one. This article will look at some valid reasons to invest in a CMS, but also will try to shed some light on the caveats, so read on.","headerImage":[{"type":"internal","dataUrl":"/api/v1/content/_media/_media-759527ba-b22f-4046-a129-13555d5574d3"}]} 2 | {"id":"blogpost-2","slug":"post-with-picture","title":"Post with picture","content":{"time":1643366117,"blocks":[{"id":"AOAWmvP1rd","data":{"text":"Example header","level":2},"type":"header"},{"id":"CzLBZad8_Z","data":{"text":"Example paragraph."},"type":"paragraph"}],"version":"2.22.0"},"excerpt":"If you’re a beginning website owner you might be wondering what a CMS is and if you need one. This article will look at some valid reasons to invest in a CMS, but also will try to shed some light on the caveats, so read on.","headerImage":[{"type":"internal","dataUrl":"/api/v1/content/_media/_media-448eab50-efc1-46ef-83f2-b910b8cc58e0"}]} -------------------------------------------------------------------------------- /src/templates/blog-post.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { graphql } from 'gatsby'; 3 | import moment from 'moment'; 4 | import { Content, Header } from 'flotiq-components-react'; 5 | import { Helmet } from 'react-helmet'; 6 | import Layout from '../layouts/layout'; 7 | import BlogPostFeaturedImage from '../components/blog-post/BlogPostFeaturedImage'; 8 | import BlogPostAuthor from '../components/blog-post/BlogPostAuthor'; 9 | import BlogPostMetaDetails from '../components/blog-post/BlogPostMetaDetails'; 10 | import BlogPostNavigation from '../components/blog-post/BlogPostNavigation'; 11 | 12 | const BlogPostTemplate = ({ data, pageContext }) => { 13 | const post = data.blogpost; 14 | return ( 15 | 16 | 17 | {post.title} 18 | 22 | 23 |
24 | 25 | 31 |
32 | {post.title} 33 |
34 | 54 | 55 |
56 | 62 |
63 | ); 64 | }; 65 | 66 | export const pageQuery = graphql` 67 | query BlogPostBySlug($slug: String!) { 68 | site { 69 | siteMetadata { 70 | title 71 | } 72 | } 73 | blogpost( slug: { eq: $slug } ) { 74 | id 75 | title 76 | excerpt 77 | headerImage { 78 | extension 79 | url 80 | width 81 | height 82 | localFile { 83 | publicURL 84 | childImageSharp { 85 | gatsbyImageData(layout: FULL_WIDTH, placeholder: NONE, formats: [AUTO, WEBP, AVIF]) 86 | } 87 | } 88 | } 89 | flotiqInternal { 90 | createdAt 91 | } 92 | content { 93 | blocks { 94 | id 95 | data { 96 | alignment 97 | anchor 98 | caption 99 | code 100 | content 101 | extension 102 | fileName 103 | height 104 | items { 105 | content 106 | items { 107 | content 108 | items { 109 | content 110 | items { 111 | content 112 | items { 113 | content 114 | items { 115 | content 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | level 123 | message 124 | stretched 125 | style 126 | text 127 | title 128 | url 129 | width 130 | withBackground 131 | withBorder 132 | withHeadings 133 | } 134 | tunes { 135 | alignmentTuneTool { 136 | alignment 137 | } 138 | } 139 | type 140 | } 141 | } 142 | } 143 | } 144 | `; 145 | 146 | export default BlogPostTemplate; 147 | -------------------------------------------------------------------------------- /.flotiq/InternalContentTypeMedia/ContentTypeDefinition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "_media", 3 | "label": "Media (internal)", 4 | "workflowId": "generic", 5 | "internal": true, 6 | "schemaDefinition": { 7 | "type": "object", 8 | "allOf": [ 9 | { 10 | "$ref": "#/components/schemas/AbstractContentTypeSchemaDefinition" 11 | }, 12 | { 13 | "type": "object", 14 | "properties": { 15 | "alt": { 16 | "type": "string" 17 | }, 18 | "url": { 19 | "type": "string", 20 | "minLength": 1 21 | }, 22 | "size": { 23 | "type": "number", 24 | "minLength": 1 25 | }, 26 | "tags": { 27 | "type": "array", 28 | "items": { 29 | "$ref": "#/components/schemas/DataSource" 30 | }, 31 | "minItems": 0 32 | }, 33 | "type": { 34 | "type": "string", 35 | "minLength": 1 36 | }, 37 | "width": { 38 | "type": "number" 39 | }, 40 | "height": { 41 | "type": "number" 42 | }, 43 | "source": { 44 | "type": "string", 45 | "minLength": 1 46 | }, 47 | "fileName": { 48 | "type": "string", 49 | "minLength": 1 50 | }, 51 | "mimeType": { 52 | "type": "string", 53 | "minLength": 1 54 | }, 55 | "variants": { 56 | "type": "array", 57 | "items": { 58 | "type": "object", 59 | "required": [ 60 | "name" 61 | ], 62 | "properties": { 63 | "name": { 64 | "type": "string", 65 | "pattern": "^[_a-zA-Z0-9]+$", 66 | "minLength": 1 67 | }, 68 | "trim": { 69 | "type": "object", 70 | "required": [ 71 | "top", 72 | "left" 73 | ], 74 | "properties": { 75 | "top": { 76 | "type": "number", 77 | "maximum": 9999999, 78 | "minimum": 0 79 | }, 80 | "left": { 81 | "type": "number", 82 | "maximum": 9999999, 83 | "minimum": 0 84 | }, 85 | "right": { 86 | "type": "number", 87 | "maximum": 9999999, 88 | "minimum": 0 89 | }, 90 | "width": { 91 | "type": "number", 92 | "maximum": 9999999, 93 | "minimum": 1 94 | }, 95 | "bottom": { 96 | "type": "number", 97 | "maximum": 9999999, 98 | "minimum": 0 99 | }, 100 | "height": { 101 | "type": "number", 102 | "maximum": 9999999, 103 | "minimum": 1 104 | } 105 | } 106 | } 107 | } 108 | }, 109 | "minItems": 0 110 | }, 111 | "extension": { 112 | "type": "string", 113 | "minLength": 1 114 | }, 115 | "externalId": { 116 | "type": "string" 117 | } 118 | } 119 | } 120 | ], 121 | "required": [ 122 | "fileName", 123 | "mimeType", 124 | "size", 125 | "url", 126 | "source", 127 | "extension", 128 | "type" 129 | ], 130 | "additionalProperties": false 131 | }, 132 | "metaDefinition": { 133 | "order": [ 134 | "fileName", 135 | "mimeType", 136 | "size", 137 | "width", 138 | "height", 139 | "url", 140 | "externalId", 141 | "source", 142 | "extension", 143 | "type", 144 | "tags", 145 | "alt", 146 | "variants" 147 | ], 148 | "propertiesConfig": { 149 | "alt": { 150 | "label": "ALT", 151 | "unique": false, 152 | "inputType": "text" 153 | }, 154 | "url": { 155 | "label": "Url", 156 | "unique": false, 157 | "inputType": "text" 158 | }, 159 | "size": { 160 | "label": "Size", 161 | "unique": false, 162 | "inputType": "number" 163 | }, 164 | "tags": { 165 | "label": "Tags", 166 | "unique": false, 167 | "helpText": "", 168 | "inputType": "datasource", 169 | "validation": { 170 | "relationMultiple": true, 171 | "relationContenttype": "_tag" 172 | } 173 | }, 174 | "type": { 175 | "label": "Type", 176 | "unique": false, 177 | "options": [ 178 | "image", 179 | "file" 180 | ], 181 | "inputType": "select" 182 | }, 183 | "width": { 184 | "label": "Width", 185 | "unique": false, 186 | "inputType": "number" 187 | }, 188 | "height": { 189 | "label": "Height", 190 | "unique": false, 191 | "inputType": "number" 192 | }, 193 | "source": { 194 | "label": "Source", 195 | "unique": false, 196 | "options": [ 197 | "disk", 198 | "unsplash" 199 | ], 200 | "inputType": "select" 201 | }, 202 | "fileName": { 203 | "label": "File name", 204 | "unique": false, 205 | "inputType": "text", 206 | "isTitlePart": true 207 | }, 208 | "mimeType": { 209 | "label": "MIME type", 210 | "unique": false, 211 | "inputType": "text" 212 | }, 213 | "variants": { 214 | "items": { 215 | "order": [ 216 | "name", 217 | "trim" 218 | ], 219 | "propertiesConfig": { 220 | "name": { 221 | "label": "name", 222 | "unique": true, 223 | "inputType": "text" 224 | }, 225 | "trim": { 226 | "label": "Trim", 227 | "order": [ 228 | "top", 229 | "right", 230 | "bottom", 231 | "left", 232 | "width", 233 | "height" 234 | ], 235 | "unique": false, 236 | "inputType": "custom", 237 | "propertiesConfig": { 238 | "top": { 239 | "label": "Top", 240 | "unique": false, 241 | "inputType": "number" 242 | }, 243 | "left": { 244 | "label": "Left", 245 | "unique": false, 246 | "inputType": "number" 247 | }, 248 | "right": { 249 | "label": "Right", 250 | "unique": false, 251 | "inputType": "number" 252 | }, 253 | "width": { 254 | "label": "Width", 255 | "unique": false, 256 | "inputType": "number" 257 | }, 258 | "bottom": { 259 | "label": "Bottom", 260 | "unique": false, 261 | "inputType": "number" 262 | }, 263 | "height": { 264 | "label": "Height", 265 | "unique": false, 266 | "inputType": "number" 267 | } 268 | } 269 | } 270 | } 271 | }, 272 | "label": "Variants", 273 | "unique": false, 274 | "helpText": "", 275 | "inputType": "object" 276 | }, 277 | "extension": { 278 | "label": "Extension", 279 | "unique": false, 280 | "inputType": "text" 281 | }, 282 | "externalId": { 283 | "label": "External id", 284 | "unique": false, 285 | "inputType": "text" 286 | } 287 | } 288 | }, 289 | "featuredImage": [] 290 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Flotiq logo 3 | 4 | 5 | Gatsby starter for blog with Flotiq source 6 | =========================== 7 | 8 | Kick off your project with this blog boilerplate. This starter ships with the main Gatsby configuration files you might need to get up and running blazing fast with the blazing fast app generator for React. 9 | 10 | Live Demo: https://flotiq-gatsby-blog-1.netlify.app 11 | 12 | This project use: 13 | * [Flotiq](https://flotiq.com) - Headless CMS for string your data (You can create account [here](https://editor.flotiq.com/register.html)) 14 | * [Tailwind](https://tailwindcss.com/) - utility-first CSS framework 15 | * [Flotiq source plugin](https://github.com/flotiq/gatsby-source-flotiq) - connector for fetching data from Flotiq 16 | * [Flotiq components for react](https://flotiq.github.io/flotiq-components-react) - components library designed and written to work perfectly with Flotiq Content Objects and display your data beautifully 17 | 18 | This project works on node >=18.0.0, as require Gatsby 5. 19 | 20 | ## Quick start using Flotiq CLI 21 | 22 | Start the project from template using [Flotiq CLI](https://github.com/flotiq/flotiq-cli) 23 | 24 | ```bash 25 | npm install -g flotiq-cli 26 | flotiq start [projectName] https://github.com/flotiq/flotiq-gatsby-blog-1.git [flotiqApiKey] 27 | ``` 28 | * `projectName` - Project path (if you wish to start project in the current directory - use `.`) 29 | * `flotiqApKey` - [Read and write API key](https://flotiq.com/docs/API/#application-api-keys) to your Flotiq account 30 | 31 | This command will: 32 | - create project based on template using the `gatsby new` command 33 | - install npm dependencies 34 | - setup variables in the .env file 35 | - import example data to you Flotiq account using the `flotiq import` command 36 | - start development server using the `gatsby develop` command 37 | 38 | ## Configuration 39 | 40 | Environment variables are stored in the `.env` files. 41 | The `.env.development` file inside the root of the directory should have the following structure: 42 | 43 | ``` 44 | GATSBY_FLOTIQ_API_KEY=YOUR FLOTIQ API KEY 45 | GA_MEASUREMENT_ID=YOUR MEASUREMENT ID 46 | ``` 47 | 48 | ## Import data (optional) 49 | 50 | This step is optional and is not necessary if you used flotiq-cli to start the project. 51 | 52 | If you wish to import example data to your account, before running `gatsby develop` run: 53 | 54 | ```sh 55 | flotiq import .flotiq [flotiqApiKey] 56 | ``` 57 | 58 | It will add four example objects to your Flotiq account. 59 | 60 | _Note: You need to put your Read and write API key as the `flotiqApiKey` for import to work, You don't need any content types in your account._ 61 | 62 | ## Developing 63 | 64 | Navigate into your new site’s directory and start it up. 65 | 66 | ```shell 67 | cd flotiq-gatsby-blog-1/ 68 | gatsby develop 69 | ``` 70 | 71 | Your site is now running at `http://localhost:8000`! 72 | 73 | _Note: You'll also see a second link: _`http://localhost:8000/___graphql`_. This is a tool you can use to experiment with querying your data. Learn more about using this tool in the [Gatsby Tutorial](https://www.gatsbyjs.com/docs/tutorial/part-4/#use-graphiql-to-explore-the-data-layer-and-write-graphql-queries)._ 74 | 75 | Open the `flotiq-gatsby-blog-1` directory in your code editor of choice and edit `src/templates/index.js`. 76 | Save your changes and the browser will update in real time! 77 | 78 | ## Manage your content using Flotiq editor 79 | 80 | You can now easily manage your content using [Flotiq editor](https://editor.flotiq.com). 81 | 82 | As Gatsby generates static pages based on content from headless CMS, you have to rebuild site after the data changes. 83 | 84 | ### Update data in development 85 | 86 | When you update the Content Object in Flotiq you have to rerun `gatsby develop`. 87 | When you update the Content Type Definition in Flotiq, you have to run `gatsby clean` command. 88 | 89 | _Note: To simplify this process you can configure [Gatsby Refreshing Content](https://www.gatsbyjs.com/docs/refreshing-content/) endpoint._ 90 | 91 | ### Update data in production 92 | 93 | When you update the data in Flotiq you have to rebuild project using `gatsby build` command. 94 | 95 | If you use hosting services listed below you can simplify the process: 96 | - For Gatsby Cloud use [Flotiq Gatsby plugin](https://flotiq.com/docs/panel/Plugins/Gatsby-cloud-integration/#installing-the-gatsby-plugin) 97 | - For Netlify use [Flotiq Netlify plugin](https://flotiq.com/docs/panel/Plugins/Netlify-integration/#installing-the-netlify-plugin) 98 | 99 | For other services you can configure [Webhook](https://flotiq.com/docs/panel/webhooks/examples/) on data change or manually rebuild site in hosting service. 100 | 101 | ## Deploy 102 | 103 | Deploy this project to [Heroku](https://www.heroku.com/) in 3 minutes: 104 | 105 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/flotiq/flotiq-gatsby-blog-1) 106 | 107 | Or to [Netlify](https://www.netlify.com/): 108 | 109 | [![Deploy](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/flotiq/flotiq-gatsby-blog-1) 110 | 111 | Or to [Cloudflare Workers](https://workers.cloudflare.com/): 112 | 113 | [![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/flotiq/flotiq-gatsby-blog-1) 114 | 115 | ### Note 116 | Cloudflare Workers deployment uses Flotiq starter API key, if you want to deploy a worker with your own Flotiq API key, after deployment go to your forked repository on GitHub and add a GATSBY_FLOTIQ_API secret in repository's settings, then in Actions, select "Deploy Cloudflare Worker" workflow and click "Run workflow" to deploy the worker again. 117 | 118 | More information about GitHub secrets can be found [here](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions). 119 | 120 | 121 | ## What's inside? 122 | 123 | A quick look at the top-level files and directories you'll see in a Gatsby project. 124 | 125 | . 126 | ├── .flotiq 127 | ├── .github 128 | ├── node_modules 129 | ├─┬ src 130 | │ ├── assets 131 | │ ├── components 132 | │ ├── layouts 133 | │ ├── pages 134 | │ ├── sections 135 | │ ├── style 136 | │ └── templates 137 | ├── .eslintignore 138 | ├── .eslintrc.js 139 | ├── .gitignore 140 | ├── .prettierignore 141 | ├── .prettierrc 142 | ├── app.json 143 | ├── gatsby-browser.js 144 | ├── gatsby-config.js 145 | ├── gatsby-node.js 146 | ├── LICENSE 147 | ├── netlify.toml 148 | ├── package.json 149 | ├── README.md 150 | ├── static.json 151 | ├── tailwind.config.js 152 | ├── worker-index.js 153 | ├── wrangler.toml 154 | └── yarn.lock 155 | 156 | 1. **`.flotiq`**: This directory contains content types necessary to starter to work. 157 | 158 | 2. **`.github`**: This directory contains templates of GitHub issues. 159 | 160 | 3. **`/node_modules`**: This directory contains all packages that your project depends on (npm packages) and are automatically installed. 161 | 162 | 4. **`/src`**: This directory will contain all the code related to what you will see on the front-end of your site (what you see in the browser) such as your site header or a page template. `src` is a convention for “source code”. 163 | 164 | 5. **`/src/assets`**: This directory will contain all static assets for the project (images, favicons, custom fonts). 165 | 166 | 6. **`/src/components`**: This directory will contain all small build blocks for your templates and layouts. 167 | 168 | 7. **`/src/layouts`**: This directory will contain all layout templates for your pages. 169 | 170 | 8. **`/src/pages`**: This directory will contain all static pages for the project. 171 | 172 | 9. **`/src/sections`**: This directory will contain all big build blocks for your project. 173 | 174 | 10. **`/src/style`**: This directory will contain global styles for the project. 175 | 176 | 11. **`/src/templates`**: This directory will contain all templates for automatically generated pages. 177 | 178 | 12. **`.eslintignore`**: This file tells eslint which files it should not track / not fix. 179 | 180 | 13. **`.eslintrc.js`**: This is a configuration file for [Eslint](https://eslint.org/). Eslint is a tool to help keep the formatting of your code consistent automatically. 181 | 182 | 14. **`.gitignore`**: This file tells git which files it should not track / not maintain a version history for. 183 | 184 | 15. **`.prettierignore`**: This file tells prettier which files it should not track / not fix. 185 | 186 | 16. **`.prettierrc`**: This is a configuration file for [Prettier](https://prettier.io/). Prettier is a tool to help keep the formatting of your code consistent. 187 | 188 | 17. **`app.json`**: Configuration file for Heroku deploy. You can safely remove this file if you do not plan to deploy on Heroku. 189 | 190 | 18. **`gatsby-browser.js`**: This file is where Gatsby expects to find any usage of the [Gatsby browser APIs](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-browser/) (if any). These allow customization/extension of default Gatsby settings affecting the browser. 191 | 192 | 19. **`gatsby-config.js`**: This is the main configuration file for a Gatsby site. This is where you can specify information about your site (metadata) like the site title and description, which Gatsby plugins you’d like to include, etc. (Check out the [config docs](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-config/) for more detail). 193 | 194 | 20. **`gatsby-node.js`**: This file is where Gatsby expects to find any usage of the [Gatsby Node APIs](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/) (if any). These allow customization/extension of default Gatsby settings affecting pieces of the site build process. 195 | 196 | 21. **`LICENSE`**: This Gatsby starter is licensed under the MIT license. 197 | 198 | 22. **`netlify.toml`**: Configuration file for Netlify deploy. You can safely remove this file if you do not plan to deploy on Netlify. 199 | 200 | 23. **`package.json`**: A manifest file for Node.js projects, which includes things like metadata (the project’s name, author, etc.). This manifest is how npm knows which packages to install for your project. 201 | 202 | 24. **`README.md`**: A text file containing useful reference information about your project. 203 | 204 | 25. **`static.json`**: Configuration file for caching the project. 205 | 206 | 26. **`tailwind.config.js`**: Configuration file for tailwind. 207 | 208 | 27. **`worker-index.js`**: Main file for Cloudflare Workers. 209 | 210 | 28. **`wrangler.toml`**: Configuration file for Cloudflare Workers deployment. 211 | 212 | 29. **`yarn.lock`**: This is an automatically generated file based on the exact versions of your yarn dependencies that were installed for your project. **(You won’t change this file directly).** 213 | 214 | ## Learning Gatsby 215 | 216 | Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.com/). Here are some places to start: 217 | 218 | - **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.com/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process. 219 | 220 | - **To dive straight into code samples, head [to the gatsby documentation](https://www.gatsbyjs.com/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar. 221 | 222 | ## Learning Flotiq 223 | 224 | Full documentation for Flotiq lives [on this website](https://flotiq.com/docs/). 225 | 226 | Documentation for gatsby starters is [here](https://flotiq.com/docs/Universe/gatsby/). 227 | 228 | ## Collaborating 229 | 230 | If you wish to talk with us about this project, feel free to hop on our [![Discord Chat](https://img.shields.io/discord/682699728454025410.svg)](https://discord.gg/FwXcHnX). 231 | 232 | If you found a bug, please report it in [issues](https://github.com/flotiq/flotiq-gatsby-blog-1/issues). 233 | --------------------------------------------------------------------------------