├── .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 |
14 |
15 | );
16 |
17 | export default Layout;
18 |
--------------------------------------------------------------------------------
/src/components/blog-post/BlogPostTags.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const BlogPostTags = ({ tags }) => (
4 |
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 |
18 |
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 |
23 | ) : (
24 |
25 | )}
26 |
27 |
28 |
29 |
30 |

35 |
36 |
37 |
38 |
39 |
Blog About Everything
40 |
41 |
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 |
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 |
22 | ),
23 | },
24 | {
25 | name: 'LinkedIn',
26 | href: 'https://www.linkedin.com/company/flotiq/',
27 | icon: (props) => (
28 |
37 | ),
38 | },
39 | {
40 | name: 'Link',
41 | href: 'https://flotiq.com',
42 | icon: (props) => (
43 |
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 |
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 |
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 |
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 | [](https://heroku.com/deploy?template=https://github.com/flotiq/flotiq-gatsby-blog-1)
106 |
107 | Or to [Netlify](https://www.netlify.com/):
108 |
109 | [](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 | [](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 [](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 |
--------------------------------------------------------------------------------