├── CNAME
├── src
├── content
│ ├── posts
│ │ ├── -index.md
│ │ ├── post-2.md
│ │ ├── post-7.md
│ │ ├── post-3.md
│ │ ├── post-6.md
│ │ ├── post-1.md
│ │ ├── post-4.md
│ │ └── post-5.md
│ ├── authors
│ │ ├── -index.md
│ │ ├── john-doe.md
│ │ ├── mark-dinn.md
│ │ └── zakk.md
│ ├── pages
│ │ ├── 404.md
│ │ └── privacy-policy.md
│ ├── categories
│ │ ├── allo.md
│ │ ├── gitcoin.md
│ │ ├── passport.md
│ │ └── grants-stack.md
│ └── config.ts
├── env.d.ts
├── styles
│ ├── utilities.scss
│ ├── buttons.scss
│ ├── style.scss
│ ├── base.scss
│ ├── navigation.scss
│ └── components.scss
├── lib
│ ├── utils
│ │ ├── taxonomyFilter.ts
│ │ ├── dateFormat.ts
│ │ ├── sortFunctions.ts
│ │ ├── readingTime.ts
│ │ ├── similarItems.ts
│ │ └── textConverter.ts
│ ├── contentParser.astro
│ └── taxonomyParser.astro
├── layouts
│ ├── Default.astro
│ ├── components
│ │ ├── TwSizeIndicator.astro
│ │ ├── Logo.astro
│ │ ├── Share.astro
│ │ ├── SimilarPosts.astro
│ │ ├── Pagination.astro
│ │ └── Social.astro
│ ├── partials
│ │ ├── Footer.astro
│ │ └── Header.astro
│ ├── AuthorSingle.astro
│ ├── Authors.astro
│ ├── Posts.astro
│ ├── Base.astro
│ ├── PostSingle.astro
│ └── Search.tsx
├── pages
│ ├── search.astro
│ ├── 404.astro
│ ├── index.astro
│ ├── authors
│ │ ├── index.astro
│ │ ├── page
│ │ │ └── [slug].astro
│ │ └── [single].astro
│ ├── tags
│ │ ├── [tag].astro
│ │ └── index.astro
│ ├── [regular].astro
│ ├── categories
│ │ ├── index.astro
│ │ └── [category].astro
│ └── page
│ │ └── [slug].astro
└── config
│ ├── theme.json
│ ├── config.json
│ ├── menu.json
│ └── social.json
├── .markdownlint.json
├── public
├── robots.txt
├── images
│ ├── logo.png
│ ├── author.png
│ ├── favicon.png
│ ├── posts
│ │ ├── 01.jpg
│ │ ├── 02.jpg
│ │ ├── 03.jpg
│ │ ├── 04.jpg
│ │ ├── 05.jpg
│ │ ├── 06.jpg
│ │ └── 07.jpg
│ ├── authors
│ │ ├── john-doe.jpg
│ │ └── mark-dinn.jpg
│ ├── logo.svg
│ ├── favicon.svg
│ └── gitcoin-engineering.svg
└── .htaccess
├── postcss.config.js
├── .prettierrc
├── .editorconfig
├── .gitignore
├── netlify.toml
├── tsconfig.json
├── astro.config.mjs
├── SETUP.md
├── README.md
├── package.json
├── .github
└── workflows
│ └── deploy.yml
└── tailwind.config.js
/CNAME:
--------------------------------------------------------------------------------
1 | engineering.gitcoin.co
--------------------------------------------------------------------------------
/src/content/posts/-index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Blog
3 | ---
4 |
--------------------------------------------------------------------------------
/src/content/authors/-index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Authors"
3 | ---
4 |
--------------------------------------------------------------------------------
/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "MD033": false,
3 | "MD013": false
4 | }
5 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
3 |
4 | Disallow: /api/*
--------------------------------------------------------------------------------
/src/content/pages/404.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Error 404"
3 | ---
4 |
5 | ## Page Not Found
6 |
--------------------------------------------------------------------------------
/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/logo.png
--------------------------------------------------------------------------------
/public/images/author.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/author.png
--------------------------------------------------------------------------------
/public/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/favicon.png
--------------------------------------------------------------------------------
/public/images/posts/01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/posts/01.jpg
--------------------------------------------------------------------------------
/public/images/posts/02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/posts/02.jpg
--------------------------------------------------------------------------------
/public/images/posts/03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/posts/03.jpg
--------------------------------------------------------------------------------
/public/images/posts/04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/posts/04.jpg
--------------------------------------------------------------------------------
/public/images/posts/05.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/posts/05.jpg
--------------------------------------------------------------------------------
/public/images/posts/06.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/posts/06.jpg
--------------------------------------------------------------------------------
/public/images/posts/07.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/posts/07.jpg
--------------------------------------------------------------------------------
/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/public/images/authors/john-doe.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/authors/john-doe.jpg
--------------------------------------------------------------------------------
/public/images/authors/mark-dinn.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitcoinco/engineering/HEAD/public/images/authors/mark-dinn.jpg
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "overrides": [
3 | {
4 | "files": ["*.astro"],
5 | "options": {
6 | "parser": "astro"
7 | }
8 | }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/src/styles/utilities.scss:
--------------------------------------------------------------------------------
1 | b,
2 | strong {
3 | @apply font-semibold;
4 | }
5 |
6 | img {
7 | @apply inline-block;
8 | }
9 |
10 | .shadow {
11 | box-shadow: 0 10px 30px rgb(22 28 45 / 10%);
12 | }
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; https://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | indent_size = 2
9 | indent_style = space
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/src/lib/utils/taxonomyFilter.ts:
--------------------------------------------------------------------------------
1 | import { slugify } from "@lib/utils/textConverter";
2 |
3 | const taxonomyFilter = (posts: any[], name: string, key: any) =>
4 | posts.filter((post) =>
5 | post.data[name].map((name: string) => slugify(name)).includes(key)
6 | );
7 |
8 | export default taxonomyFilter;
9 |
--------------------------------------------------------------------------------
/src/styles/buttons.scss:
--------------------------------------------------------------------------------
1 | .btn {
2 | @apply inline-block rounded-lg border px-6 py-3 font-semibold transition;
3 | }
4 |
5 | .btn-primary {
6 | @apply bg-primary text-white;
7 | }
8 |
9 | .btn-outline-primary {
10 | @apply border-primary bg-transparent hover:bg-primary hover:text-white;
11 | }
12 |
--------------------------------------------------------------------------------
/src/styles/style.scss:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | @import "base";
7 | }
8 |
9 | @layer components {
10 | @import "components";
11 | @import "navigation";
12 | @import "buttons";
13 | }
14 |
15 | @layer utilities {
16 | @import "utilities";
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | .output/
4 |
5 | # dependencies
6 | node_modules/
7 |
8 | # logs
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 |
14 | # environment variables
15 | .env
16 | .env.production
17 |
18 | # macOS-specific files
19 | .DS_Store
20 |
21 | # ignore .astro directory
22 | .astro
23 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "dist"
3 | command = "yarn build"
4 |
5 | [[headers]]
6 | for = "/*" # This defines which paths this specific [[headers]] block will cover.
7 |
8 | [headers.values]
9 | X-Frame-Options = "DENY"
10 | X-XSS-Protection = "1; mode=block"
11 | Referrer-Policy = "same-origin"
12 | Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
13 |
--------------------------------------------------------------------------------
/src/lib/contentParser.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { getCollection } from "astro:content";
3 |
4 | export const getSinglePage = async (collection: any) => {
5 | const allPage = await getCollection(collection);
6 | const removeIndex = allPage.filter((data) => data.id.match(/^(?!-)/));
7 | const removeDrafts = removeIndex.filter((data) => !data.draft);
8 | return removeDrafts;
9 | };
10 | ---
11 |
--------------------------------------------------------------------------------
/src/layouts/Default.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { markdownify } from "@lib/utils/textConverter";
3 |
4 | const { data } = Astro.props;
5 | const { title } = data.data;
6 | const { Content } = await data.render();
7 | ---
8 |
9 |
17 |
--------------------------------------------------------------------------------
/src/lib/utils/dateFormat.ts:
--------------------------------------------------------------------------------
1 | const dateFormat = (datetime: string | Date) => {
2 | const dateTime = new Date(datetime);
3 |
4 | const date = dateTime.toLocaleDateString([], {
5 | year: "numeric",
6 | month: "long",
7 | day: "numeric",
8 | });
9 |
10 | const time = dateTime.toLocaleTimeString([], {
11 | hour: "2-digit",
12 | minute: "2-digit",
13 | });
14 |
15 | return date;
16 | };
17 |
18 | export default dateFormat;
19 |
--------------------------------------------------------------------------------
/src/content/authors/john-doe.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: John Doe
3 | image: /images/authors/john-doe.jpg
4 | description: this is meta description
5 | social:
6 | facebook: https://www.facebook.com/
7 | twitter: https://www.twitter.com/
8 | instagram: https://www.instagram.com/
9 | ---
10 |
11 | lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr navigation et dolore magna aliqua.
12 |
--------------------------------------------------------------------------------
/src/content/authors/mark-dinn.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Mark Dinn
3 | image: /images/authors/mark-dinn.jpg
4 | description: this is meta description
5 | social:
6 | facebook: https://www.facebook.com/
7 | twitter: https://www.twitter.com/
8 | instagram: https://www.instagram.com/
9 | ---
10 |
11 | lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr navigation et dolore magna aliqua.
12 |
--------------------------------------------------------------------------------
/src/content/authors/zakk.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 0xZakk
3 | image: /images/authors/john-doe.jpg
4 | description: this is meta description
5 | social:
6 | twitter: https://twitter.com/0xZakk
7 | github: https://github.com/0xZakk
8 | quests: https://quests.com/zakk
9 | twitch: https://www.twitch.tv/0xzakk
10 | youtube: https://www.youtube.com/@0xZakk
11 | ---
12 |
13 | Zakk leads Developer Relations at Gitcoin. Previously, he was a co-founder at
14 | Cabin, co-founder of the Solidity Guild, founder of Hawthorne Interactive, and
15 | faculty director at General Assembly.
16 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "resolveJsonModule": true,
6 | "allowSyntheticDefaultImports": true,
7 | "paths": {
8 | "@layouts/*": ["./src/layouts/*"],
9 | "@components/*": ["./src/layouts/components/*"],
10 | "@partials/*": ["./src/layouts/partials/*"],
11 | "@shortcodes/*": ["./src/layouts/shortcodes/*"],
12 | "@config/*": ["./src/config/*"],
13 | "@content/*": ["./src/content/*"],
14 | "@styles/*": ["./src/styles/*"],
15 | "@lib/*": ["./src/lib/*"]
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/pages/search.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Base from "@layouts/Base.astro";
3 | import Search from "@layouts/Search";
4 | import { getSinglePage } from "@lib/contentParser.astro";
5 |
6 | // Retrieve all articles
7 | const posts = await getSinglePage("posts");
8 |
9 | // List of items to search in
10 | const searchList = posts.map((item) => ({
11 | slug: item.slug,
12 | data: item.data,
13 | content: item.body,
14 | }));
15 | ---
16 |
17 |
18 |
23 |
24 |
--------------------------------------------------------------------------------
/src/styles/base.scss:
--------------------------------------------------------------------------------
1 | html {
2 | @apply text-base;
3 | }
4 |
5 | body {
6 | @apply bg-body font-primary font-normal leading-relaxed text-text;
7 | }
8 |
9 | h1,
10 | h2,
11 | h3,
12 | h4,
13 | h5,
14 | h6 {
15 | @apply font-primary font-bold leading-tight text-dark;
16 | }
17 |
18 | h1,
19 | .h1 {
20 | @apply text-h1-sm md:text-h1;
21 | }
22 |
23 | h2,
24 | .h2 {
25 | @apply text-h2-sm md:text-h2;
26 | }
27 |
28 | h3,
29 | .h3 {
30 | @apply text-h3-sm md:text-h3;
31 | }
32 |
33 | h4,
34 | .h4 {
35 | @apply text-h4;
36 | }
37 |
38 | h5,
39 | .h5 {
40 | @apply text-h5;
41 | }
42 |
43 | h6,
44 | .h6 {
45 | @apply text-h6;
46 | }
47 |
--------------------------------------------------------------------------------
/src/config/theme.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors": {
3 | "default": {
4 | "theme_color": {
5 | "primary": "#01AD9F",
6 | "body": "#fff",
7 | "border": "#D5D5D5",
8 | "theme_light": "#FAFAFA",
9 | "theme_dark": "#152035"
10 | },
11 | "text_color": {
12 | "default": "#747577",
13 | "dark": "#152035",
14 | "light": "#a1a5ae"
15 | }
16 | }
17 | },
18 | "fonts": {
19 | "font_family": {
20 | "primary": "Mulish:wght@400;600;700",
21 | "primary_type": "sans-serif"
22 | },
23 | "font_size": {
24 | "base": "16",
25 | "scale": "1.250"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/pages/404.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Base from "@layouts/Base.astro";
3 | import { markdownify } from "@lib/utils/textConverter";
4 | import { getEntryBySlug } from "astro:content";
5 | const entry = await getEntryBySlug("pages", "404");
6 | const { Content } = await entry.render();
7 | ---
8 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/src/layouts/components/TwSizeIndicator.astro:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | {
5 | process.env.NODE_ENV === "development" && (
6 |
7 | all
8 | sm
9 | md
10 | lg
11 | xl
12 | 2xl
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/src/lib/taxonomyParser.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { getSinglePage } from "./contentParser.astro";
3 | import { slugify } from "./utils/textConverter";
4 |
5 | // get all taxonomies from frontmatter
6 | export const getTaxonomy = async (collection: string, name: string) => {
7 | const singlePages = await getSinglePage(collection);
8 | const taxonomyPages = singlePages.map((page) => page.data[name]);
9 | let taxonomies = [];
10 | for (let i = 0; i < taxonomyPages.length; i++) {
11 | const categoryArray = taxonomyPages[i];
12 | for (let j = 0; j < categoryArray.length; j++) {
13 | taxonomies.push(slugify(categoryArray[j]));
14 | }
15 | }
16 | const taxonomy = [...new Set(taxonomies)];
17 | return taxonomy;
18 | };
19 | ---
20 |
--------------------------------------------------------------------------------
/src/config/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "site": {
3 | "title": "Gitcoin Engineering Blog",
4 | "base_url": "https://engineering.gitcoin.co",
5 | "base_path": "/",
6 | "trailing_slash": false,
7 | "favicon": "/images/favicon.svg",
8 | "logo": "/images/logo.svg",
9 | "logo_width": "27",
10 | "logo_height": "32",
11 | "logo_text": "/images/gitcoin-engineering.svg"
12 | },
13 |
14 | "settings": {
15 | "pagination": 5,
16 | "summary_length": 100
17 | },
18 |
19 | "metadata": {
20 | "meta_author": "Gitcoin",
21 | "meta_image": "/images/og-image.png",
22 | "meta_description": "The Gitcoin Engineering Blog"
23 | },
24 |
25 | "params": {
26 | "contact_form_action": "#",
27 | "copyright": "Copyright © 2023 Gitcoin"
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/config/menu.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": [
3 | {
4 | "name": "Allo",
5 | "url": "/categories/allo"
6 | },
7 | {
8 | "name": "Grants Stack",
9 | "url": "/categories/grants-stack"
10 | },
11 | {
12 | "name": "Passport",
13 | "url": "/categories/passport"
14 | }
15 | ],
16 | "footer": [
17 | {
18 | "name": "Gitcoin",
19 | "url": "https://gitcoin.co"
20 | },
21 | {
22 | "name": "Allo",
23 | "url": "/categories/allo"
24 | },
25 | {
26 | "name": "Grants Stack",
27 | "url": "/categories/grants-stack"
28 | },
29 | {
30 | "name": "Passport",
31 | "url": "/categories/passport"
32 | },
33 | {
34 | "name": "Privacy Policy",
35 | "url": "/privacy-policy"
36 | }
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import config from "@config/config.json";
3 | import Base from "@layouts/Base.astro";
4 | import Pagination from "@layouts/components/Pagination.astro";
5 | import Posts from "@layouts/Posts.astro";
6 | import { getSinglePage } from "@lib/contentParser.astro";
7 | import { sortByDate } from "@lib/utils/sortFunctions";
8 |
9 | const posts = await getSinglePage("posts");
10 | const sortedPosts = sortByDate(posts);
11 | const totalPages = Math.ceil(posts.length / config.settings.pagination);
12 | const currentPosts = sortedPosts.slice(0, config.settings.pagination);
13 | ---
14 |
15 |
16 |
22 |
23 |
--------------------------------------------------------------------------------
/src/config/social.json:
--------------------------------------------------------------------------------
1 | {
2 | "facebook": "",
3 | "twitter": "https://twitter.com/gitcoin",
4 | "instagram": "",
5 | "youtube": "https://www.youtube.com/@GitcoinMedia",
6 | "linkedin": "https://www.linkedin.com/company/getgitcoin/",
7 | "github": "https://github.com/gitcoinco",
8 | "gitlab": "",
9 | "medium": "",
10 | "codepen": "",
11 | "bitbucket": "",
12 | "dribbble": "",
13 | "behance": "",
14 | "pinterest": "",
15 | "soundcloud": "",
16 | "tumblr": "",
17 | "reddit": "",
18 | "vk": "",
19 | "whatsapp": "",
20 | "snapchat": "",
21 | "vimeo": "",
22 | "tiktok": "",
23 | "foursquare": "",
24 | "rss": "",
25 | "email": "",
26 | "phone": "",
27 | "address": "",
28 | "skype": "",
29 | "website": "https://gitcoin.co",
30 | "discord": "https://gitcoin.co/discord",
31 | "lenster": "https://lenster.xyz/u/gitcoin"
32 | }
33 |
--------------------------------------------------------------------------------
/src/lib/utils/sortFunctions.ts:
--------------------------------------------------------------------------------
1 | // sort by date
2 | export const sortByDate = (array: any[]) => {
3 | const sortedArray = array.sort(
4 | (a:any, b:any) =>
5 | new Date(b.data.date && b.data.date) -
6 | new Date(a.data.date && a.data.date)
7 | );
8 | return sortedArray;
9 | };
10 |
11 | // sort product by weight
12 | export const sortByWeight = (array: any[]) => {
13 | const withWeight = array.filter(
14 | (item: { data: { weight: any } }) => item.data.weight
15 | );
16 | const withoutWeight = array.filter(
17 | (item: { data: { weight: any } }) => !item.data.weight
18 | );
19 | const sortedWeightedArray = withWeight.sort(
20 | (a: { data: { weight: number } }, b: { data: { weight: number } }) =>
21 | a.data.weight - b.data.weight
22 | );
23 | const sortedArray = [...new Set([...sortedWeightedArray, ...withoutWeight])];
24 | return sortedArray;
25 | };
26 |
--------------------------------------------------------------------------------
/src/content/categories/allo.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Allo Protocol"
3 | image: "/images/posts/01.jpg"
4 | social:
5 | twitter: https://www.twitter.com/
6 | github: https://github.com/
7 | ---
8 |
9 | Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim
10 | labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. Nisi
11 | anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum Lorem est
12 | aliquip amet voluptate voluptate dolor minim nulla est proident. Nostrud officia
13 | pariatur ut officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit
14 | commodo officia dolor Lorem duis laboris cupidatat officia voluptate. Culpa
15 | proident adipisicing id nulla nisi laboris ex in Lorem sunt duis officia
16 | eiusmod. Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim.
17 | Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa
18 | duis.
19 |
--------------------------------------------------------------------------------
/src/content/categories/gitcoin.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Gitcoin"
3 | image: "/images/posts/01.jpg"
4 | social:
5 | twitter: https://www.twitter.com/
6 | github: https://github.com/
7 | ---
8 |
9 | Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim
10 | labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. Nisi
11 | anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum Lorem est
12 | aliquip amet voluptate voluptate dolor minim nulla est proident. Nostrud officia
13 | pariatur ut officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit
14 | commodo officia dolor Lorem duis laboris cupidatat officia voluptate. Culpa
15 | proident adipisicing id nulla nisi laboris ex in Lorem sunt duis officia
16 | eiusmod. Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim.
17 | Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa
18 | duis.
19 |
20 |
--------------------------------------------------------------------------------
/src/content/categories/passport.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Passport"
3 | image: "/images/posts/01.jpg"
4 | social:
5 | twitter: https://www.twitter.com/
6 | github: https://github.com/
7 | ---
8 |
9 | Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim
10 | labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. Nisi
11 | anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum Lorem est
12 | aliquip amet voluptate voluptate dolor minim nulla est proident. Nostrud officia
13 | pariatur ut officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit
14 | commodo officia dolor Lorem duis laboris cupidatat officia voluptate. Culpa
15 | proident adipisicing id nulla nisi laboris ex in Lorem sunt duis officia
16 | eiusmod. Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim.
17 | Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa
18 | duis.
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/content/categories/grants-stack.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Grants Stack"
3 | image: "/images/posts/01.jpg"
4 | social:
5 | twitter: https://www.twitter.com/
6 | github: https://github.com/
7 | ---
8 |
9 | Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim
10 | labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. Nisi
11 | anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum Lorem est
12 | aliquip amet voluptate voluptate dolor minim nulla est proident. Nostrud officia
13 | pariatur ut officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit
14 | commodo officia dolor Lorem duis laboris cupidatat officia voluptate. Culpa
15 | proident adipisicing id nulla nisi laboris ex in Lorem sunt duis officia
16 | eiusmod. Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim.
17 | Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa
18 | duis.
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/layouts/partials/Footer.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Social from "@components/Social.astro";
3 | import config from "@config/config.json";
4 | import menu from "@config/menu.json";
5 | import social from "@config/social.json";
6 | import { markdownify } from "@lib/utils/textConverter";
7 | ---
8 |
9 |
29 |
--------------------------------------------------------------------------------
/src/lib/utils/readingTime.ts:
--------------------------------------------------------------------------------
1 | // content reading
2 | const readingTime = (content: string) => {
3 | const WPS = 275 / 60;
4 |
5 | let images = 0;
6 | const regex = /\w/;
7 |
8 | let words = content.split(" ").filter((word) => {
9 | if (word.includes(" 3) {
22 | imageFactor -= 1;
23 | }
24 | images -= 1;
25 | }
26 |
27 | const minutes = Math.ceil(((words - imageAdjust) / WPS + imageSecs) / 60);
28 |
29 | if (minutes < 10) {
30 | if (minutes < 2) {
31 | return "0" + minutes + ` Min read`;
32 | } else {
33 | return "0" + minutes + ` Mins read`;
34 | }
35 | } else {
36 | return minutes + ` Mins read`;
37 | }
38 | };
39 |
40 | export default readingTime;
41 |
--------------------------------------------------------------------------------
/src/pages/authors/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import config from "@config/config.json";
3 | import Authors from "@layouts/Authors.astro";
4 | import Base from "@layouts/Base.astro";
5 | import Pagination from "@layouts/components/Pagination.astro";
6 | import { getSinglePage } from "@lib/contentParser.astro";
7 | import { sortByDate } from "@lib/utils/sortFunctions";
8 | import { markdownify } from "@lib/utils/textConverter";
9 |
10 | const authors = await getSinglePage("authors");
11 | const sortedPosts = sortByDate(authors);
12 | const totalPages = Math.ceil(authors.length / config.settings.pagination);
13 | const currentPosts = sortedPosts.slice(0, config.settings.pagination);
14 | ---
15 |
16 |
17 |
24 |
25 |
--------------------------------------------------------------------------------
/src/layouts/AuthorSingle.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Image } from "@astrojs/image/components";
3 | import Social from "@components/Social.astro";
4 | import { markdownify } from "@lib/utils/textConverter";
5 |
6 | const { author } = Astro.props;
7 | const { title, image, social } = author.data;
8 | const { Content } = await author.render();
9 | ---
10 |
11 |
12 |
13 |
14 | {
15 | image && (
16 |
17 |
24 |
25 | )
26 | }
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import image from "@astrojs/image";
2 | import mdx from "@astrojs/mdx";
3 | import react from "@astrojs/react";
4 | import sitemap from "@astrojs/sitemap";
5 | import tailwind from "@astrojs/tailwind";
6 | import { defineConfig } from "astro/config";
7 | import config from "./src/config/config.json";
8 |
9 | // https://astro.build/config
10 | export default defineConfig({
11 | site: config.site.base_url
12 | ? config.site.base_url
13 | : "https://engineering.gitcoin.co",
14 | base: config.site.base_path ? config.site.base_path : "/",
15 | trailingSlash: config.site.trailing_slash ? "always" : "never",
16 | integrations: [
17 | react(),
18 | sitemap(),
19 | tailwind({
20 | config: {
21 | applyBaseStyles: false,
22 | },
23 | }),
24 | image({
25 | serviceEntryPoint: "@astrojs/image/sharp",
26 | }),
27 | mdx(),
28 | ],
29 | markdown: {
30 | remarkPlugins: [],
31 | shikiConfig: {
32 | theme: "one-dark-pro",
33 | wrap: true,
34 | },
35 | extendDefaultPlugins: true,
36 | },
37 | });
38 |
--------------------------------------------------------------------------------
/SETUP.md:
--------------------------------------------------------------------------------
1 | # 🔧 Setup
2 |
3 | This guide walks you through setting up the Gitcoin Engineering blog locally. If
4 | you wish to contribute to this blog, either by writing an article or modifying
5 | the code for the blog site, you'll want to follow this guide first.
6 |
7 | ## Background
8 |
9 | This website is built using [Astro](https://astro.build/) and the
10 | [Bookworm](https://github.com/themefisher/bookworm-light-astro) theme.
11 |
12 | ## ⚙️ Install prerequisites (once for a machine)
13 |
14 | **Node Installation:** [Install node js](https://nodejs.org/en/download/) [Recommended LTS version]
15 |
16 | ## 🖥️ Local setup
17 |
18 | Install dependencies:
19 |
20 | ```sh
21 | npm install
22 | ```
23 |
24 | Run locally:
25 |
26 | ```sh
27 | npm run dev
28 | ```
29 |
30 | After that, it will open up a preview of the template in your default browser,
31 | watch for changes to source files, and live-reload the browser when changes are
32 | saved.
33 |
34 | ## 🔨Production Build
35 |
36 | If you want to create a production build, then run the build command:
37 |
38 | ```sh
39 | npm run build
40 | ```
41 |
--------------------------------------------------------------------------------
/src/pages/tags/[tag].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Base from "@layouts/Base.astro";
3 | import Posts from "@layouts/Posts.astro";
4 | import { getSinglePage } from "@lib/contentParser.astro";
5 | import { getTaxonomy } from "@lib/taxonomyParser.astro";
6 | import taxonomyFilter from "@lib/utils/taxonomyFilter";
7 | import { humanize } from "@lib/utils/textConverter";
8 |
9 | export async function getStaticPaths() {
10 | const tags = await getTaxonomy("posts", "tags");
11 |
12 | return tags.map((tag) => {
13 | return {
14 | params: { tag },
15 | };
16 | });
17 | }
18 |
19 | const { tag } = Astro.params;
20 |
21 | const posts = await getSinglePage("posts");
22 | const filterByTags = taxonomyFilter(posts, "tags", tag);
23 |
24 | const title = humanize(tag || "");
25 | ---
26 |
27 |
28 |
29 |
30 |
Showing Posts From
31 |
{title}
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/pages/tags/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Base from "@layouts/Base.astro";
3 | import { getTaxonomy } from "@lib/taxonomyParser.astro";
4 | import { humanize } from "@lib/utils/textConverter";
5 |
6 | import { FaHashtag } from "react-icons/fa/index.js";
7 |
8 | const tags = await getTaxonomy("posts", "tags");
9 | ---
10 |
11 |
12 |
32 |
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Engineering @ Gitcoin
2 |
3 | Welcome to Gitcoin's engineering blog. This repository contains the code for
4 | running the engineering blog and the content we've published. The purpose of
5 | this blog is to share how we're approaching engineering at Gitcoin. It is built
6 | by our engineering teams (Passport, Grants Stack, and Allo) and is intended for
7 | engineers across web3.
8 |
9 | [Blog](https://engineering.gitcoin.co) | [Twitter](https://twitter.com/gitcoin) | [Discord](https://gitcoin.co/discord)
10 |
11 | ## Join Our Team
12 |
13 | Gitcoin is the heart of the public goods narrative in web3 and are at the
14 | forefront of advancing crypto in the world. We're constantly growing as
15 | a technical organization and are looking for skilled engineers to join our team.
16 |
17 | You can find open positions on our [wellfound
18 | page](https://wellfound.com/company/gitcoin). There are many other ways to get
19 | involved, other than working directly for the DAO. Join our Discord server and
20 | introduce yourself to the team if you're interested in work, contributing to
21 | open source, bounties, or just saying hi.
22 |
--------------------------------------------------------------------------------
/src/pages/[regular].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Base from "@layouts/Base.astro";
3 | import Default from "@layouts/Default.astro";
4 | import PostSingle from "@layouts/PostSingle.astro";
5 | import { getSinglePage } from "@lib/contentParser.astro";
6 |
7 | const getPosts = await getSinglePage("posts");
8 | const postsSlug = getPosts.map((item) => item.slug);
9 |
10 | export async function getStaticPaths() {
11 | const posts = await getSinglePage("posts");
12 | const pages = await getSinglePage("pages");
13 | const allPages = [...pages, ...posts];
14 |
15 | const paths = allPages.map((page) => ({
16 | params: {
17 | regular: page.slug,
18 | },
19 | props: { page },
20 | }));
21 | return paths;
22 | }
23 |
24 | const { page } = Astro.props;
25 | const { title, meta_title, description, image } = page.data;
26 | ---
27 |
28 |
34 | {
35 | postsSlug.includes(page.slug) ? (
36 |
37 | ) : (
38 |
39 | )
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/src/lib/utils/similarItems.ts:
--------------------------------------------------------------------------------
1 | // similer products
2 | const similerItems = (currentItem: any, allItems: any, slug: string) => {
3 | let categories: [] = [];
4 | let tags: [] = [];
5 |
6 | // set categories
7 | if (currentItem.data.categories.length > 0) {
8 | categories = currentItem.data.categories;
9 | }
10 |
11 | // set tags
12 | if (currentItem.data.tags.length > 0) {
13 | tags = currentItem.data.tags;
14 | }
15 |
16 | // filter by categories
17 | const filterByCategories = allItems.filter(
18 | (item: { data: { categories: string } }) =>
19 | categories.find((category) => item.data.categories.includes(category))
20 | );
21 |
22 | // filter by tags
23 | const filterByTags = allItems.filter((item: { data: { tags: string } }) =>
24 | tags.find((tag) => item.data.tags.includes(tag))
25 | );
26 |
27 | // merged after filter
28 | const mergedItems = [...new Set([...filterByCategories, ...filterByTags])];
29 |
30 | // filter by slug
31 | const filterBySlug = mergedItems.filter((product) => product.slug !== slug);
32 |
33 | return filterBySlug;
34 | };
35 |
36 | export default similerItems;
37 |
--------------------------------------------------------------------------------
/src/pages/categories/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Base from "@layouts/Base.astro";
3 | import { getTaxonomy } from "@lib/taxonomyParser.astro";
4 | import { humanize } from "@lib/utils/textConverter";
5 |
6 | const categories = await getTaxonomy("posts", "categories");
7 |
8 | import { BiCategoryAlt } from "react-icons/bi/index.js";
9 | ---
10 |
11 |
12 |
13 |
14 |
Categories
15 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "engineering.gitcoin.co",
3 | "version": "1.0.0",
4 | "license": "MIT",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "build": "astro build",
8 | "format": "prettier -w ."
9 | },
10 | "dependencies": {
11 | "@astrojs/image": "^0.14.1",
12 | "@astrojs/mdx": "^0.16.0",
13 | "@astrojs/rss": "^2.1.0",
14 | "astro": "^2.0.11",
15 | "date-fns": "^2.29.3",
16 | "date-fns-tz": "^2.0.0",
17 | "fuse.js": "^6.6.2",
18 | "github-slugger": "^2.0.0",
19 | "marked": "^4.2.12",
20 | "react-icons": "^4.7.1"
21 | },
22 | "devDependencies": {
23 | "@astrojs/react": "^2.0.2",
24 | "@astrojs/sitemap": "^1.0.1",
25 | "@astrojs/tailwind": "^3.0.1",
26 | "@tailwindcss/forms": "^0.5.3",
27 | "@tailwindcss/typography": "^0.5.9",
28 | "@types/marked": "^4.0.8",
29 | "@types/react": "^18.0.28",
30 | "postcss": "^8.4.20",
31 | "prettier": "^2.8.4",
32 | "prettier-plugin-astro": "^0.8.0",
33 | "prettier-plugin-tailwindcss": "^0.2.2",
34 | "react": "^18.2.0",
35 | "react-dom": "^18.2.0",
36 | "sass": "^1.58.1",
37 | "sharp": "^0.31.3",
38 | "tailwind-bootstrap-grid": "^5.0.1",
39 | "tailwindcss": "^3.2.6"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/layouts/components/Logo.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Image } from "@astrojs/image/components";
3 | import config from "@config/config.json";
4 | const { src } = Astro.props;
5 | const {
6 | logo,
7 | logo_width,
8 | logo_height,
9 | logo_text,
10 | title,
11 | }: {
12 | logo: string;
13 | logo_width: any;
14 | logo_height: any;
15 | logo_text: string;
16 | title: string;
17 | } = config.site;
18 | ---
19 |
20 |
21 | {
22 | src || logo ? (
23 | <>
24 |
35 |
45 | >
46 | ) : logo_text ? (
47 | logo_text
48 | ) : (
49 | title
50 | )
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/src/layouts/Authors.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Image } from "@astrojs/image/components";
3 | import { markdownify } from "@lib/utils/textConverter";
4 | import { BsArrowRightCircle } from "react-icons/bs/index.js";
5 | const { authors } = Astro.props;
6 | ---
7 |
8 |
9 | {
10 | authors.map((author: any) => (
11 |
33 | ))
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/src/layouts/components/Share.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import config from "@config/config.json";
3 | import {
4 | IoLogoFacebook,
5 | IoLogoLinkedin,
6 | IoLogoPinterest,
7 | IoLogoTwitter,
8 | } from "react-icons/io5/index.js";
9 |
10 | const { base_url } = config.site;
11 | const { title, description, slug, className } = Astro.props;
12 | ---
13 |
14 |
46 |
--------------------------------------------------------------------------------
/src/content/posts/post-2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Why a balloon is a flexible bag
3 | description: "meta description"
4 | date: 2022-04-04T05:00:00Z
5 | image: "/images/posts/02.jpg"
6 | categories: ["passport"]
7 | authors: ["John Doe"]
8 | tags: ["diy", "toy"]
9 | draft: false
10 | ---
11 |
12 | Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
13 |
14 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
15 |
16 | ## Creative Design
17 |
18 | Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
19 |
20 | > Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
21 |
22 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
23 |
--------------------------------------------------------------------------------
/src/pages/categories/[category].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Base from "@layouts/Base.astro";
3 | import Posts from "@layouts/Posts.astro";
4 | import { getEntry } from "astro:content";
5 | import { getSinglePage } from "@lib/contentParser.astro";
6 | import { getTaxonomy } from "@lib/taxonomyParser.astro";
7 | import taxonomyFilter from "@lib/utils/taxonomyFilter";
8 | import { humanize } from "@lib/utils/textConverter";
9 |
10 | export async function getStaticPaths() {
11 | const categories = await getTaxonomy("posts", "categories");
12 |
13 | return categories.map((category) => {
14 | return {
15 | params: { category },
16 | };
17 | });
18 | }
19 |
20 | const { category } = Astro.params;
21 |
22 | const posts = await getSinglePage("posts");
23 | const filterByCategory = taxonomyFilter(posts, "categories", category);
24 | const categoryPage = await getEntry('categories', category);
25 | const { Content } = await categoryPage.render();
26 |
27 | console.log(categoryPage);
28 | ---
29 |
30 |
31 |
32 |
33 |
Showing Posts For:
34 |
{categoryPage.data.title}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/content/posts/post-7.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "How to make toys from old Olarpaper"
3 | description: "meta description"
4 | date: 2022-04-04T05:00:00Z
5 | image: "/images/posts/01.jpg"
6 | categories: ["grants-stack"]
7 | authors: ["Mark Dinn"]
8 | tags: ["diy", "toy"]
9 | draft: false
10 | ---
11 |
12 | Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
13 |
14 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
15 |
16 | ## Creative Design
17 |
18 | Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
19 |
20 | > Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
21 |
22 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
23 |
--------------------------------------------------------------------------------
/src/content/posts/post-3.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: What you need to know about Photography
3 | description: "meta description"
4 | date: 2022-04-02T06:00:00+00:00
5 | image: "/images/posts/03.jpg"
6 | categories: ["grants-stack"]
7 | authors: ["Mark Dinn"]
8 | tags: ["diy", "toy"]
9 | draft: false
10 | ---
11 |
12 | Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
13 |
14 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
15 |
16 | ## Creative Design
17 |
18 | Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
19 |
20 | > Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
21 |
22 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
23 |
--------------------------------------------------------------------------------
/src/content/posts/post-6.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Become a morning person with the help of alarm clock"
3 | description: "meta description"
4 | image: "/images/posts/06.jpg"
5 | date: 2021-02-03T16:56:47+06:00
6 | draft: false
7 | authors: ["Mark Dinn"]
8 | tags: ["Alarm", "Clock"]
9 | categories: ["allo"]
10 | ---
11 |
12 | Almost every day for the past nine or so months has felt like March 13, and that can sometimes make it difficult to want to wake up for the day ahead of you.
13 |
14 | To make a morning person out of you, the wake-up light simulates the sunrise to gradually ease you awake. This allows you to wake up more naturally rather than being jolted awake by the default iPhone alarm sound, which honestly triggers my fight or flight response.
15 |
16 | ### Creative Design
17 |
18 | Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
19 |
20 | > Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
21 |
22 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
23 |
--------------------------------------------------------------------------------
/src/content/posts/post-1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "How to make toys from old Olarpaper"
3 | description: "meta description"
4 | date: 2022-04-04T05:00:00Z
5 | image: "/images/posts/01.jpg"
6 | categories: ["gitcoin", "allo"]
7 | authors: ["Mark Dinn", "John Doe"]
8 | tags: ["diy", "toy"]
9 | draft: false
10 | ---
11 |
12 | Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
13 |
14 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
15 |
16 | ## Creative Design
17 |
18 | Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
19 |
20 | > Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
21 |
22 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
23 |
--------------------------------------------------------------------------------
/src/styles/navigation.scss:
--------------------------------------------------------------------------------
1 | // navbar toggler
2 | input#nav-toggle:checked ~ label#show-button {
3 | @apply hidden;
4 | }
5 |
6 | input#nav-toggle:checked ~ label#hide-button {
7 | @apply flex md:hidden;
8 | }
9 |
10 | input#nav-toggle:checked ~ #nav-menu {
11 | @apply block md:flex;
12 | }
13 |
14 | // navbar items
15 | .navbar {
16 | @apply relative flex max-w-[1260px] flex-wrap items-center;
17 | }
18 |
19 | .navbar-brand img {
20 | @apply h-auto max-w-[170px] sm:h-auto sm:max-w-full #{!important};
21 | }
22 |
23 | .navbar-nav {
24 | @apply text-center md:text-left;
25 | }
26 |
27 | .nav-item {
28 | @apply mx-1;
29 | }
30 |
31 | .nav-link {
32 | @apply p-3 text-lg font-semibold text-dark transition hover:text-primary md:p-4;
33 | }
34 |
35 | .nav-dropdown-list {
36 | @apply z-10 rounded-lg bg-white px-6 py-3 shadow transition;
37 | }
38 |
39 | .nav-dropdown-item {
40 | @apply mb-1;
41 | }
42 |
43 | .nav-dropdown-link {
44 | @apply block min-w-[150px] py-1 text-[17px] font-semibold text-dark transition hover:text-primary;
45 | }
46 |
47 | // search style
48 | .search-modal {
49 | @apply invisible absolute top-0 left-0 right-0 z-10 h-10 bg-white opacity-0 transition md:h-full;
50 | .form-input {
51 | @apply h-full w-full border-0 text-lg;
52 | }
53 | .search-close {
54 | @apply absolute top-1/2 right-2 -translate-y-1/2 p-3 text-h4;
55 | }
56 | &.open {
57 | @apply visible opacity-100;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/content/posts/post-4.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Why a balloon is a flexible bag that can be inflated with a gas"
3 | description: "meta description"
4 | image: "/images/posts/04.jpg"
5 | date: 2021-02-02T16:56:47+06:00
6 | draft: false
7 | authors: ["Mark Dinn"]
8 | tags: ["Balloon", "Gas"]
9 | categories: ["gitcoin"]
10 | ---
11 |
12 | A balloon is a flexible bag that can be inflated with a gas, such as helium, hydrogen, nitrous oxide, oxygen, and air. For special tasks, balloons can be filled with smoke, liquid water, granular media, or light sources.
13 |
14 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
15 |
16 | ### Creative Design
17 |
18 | Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
19 |
20 | > Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
21 |
22 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
23 |
--------------------------------------------------------------------------------
/src/content/posts/post-5.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Banana is the best meal packages in the UK spark outrage online"
3 | description: "meta description"
4 | image: "/images/posts/05.jpg"
5 | date: 2021-01-25T16:56:47+06:00
6 | draft: false
7 | authors: ["John Doe"]
8 | tags: ["Food", "Gold"]
9 | categories: ["gitcoin"]
10 | ---
11 |
12 | A banana is an elongated, edible fruit – botanically a berry – produced by several kinds of large herbaceous flowering plants in the genus Musa. In some countries, bananas used for cooking may be called "plantains", distinguishing them from dessert bananas.
13 |
14 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
15 |
16 | ### Creative Design
17 |
18 | Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.
19 |
20 | > Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
21 |
22 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
23 |
--------------------------------------------------------------------------------
/src/pages/page/[slug].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import config from "@config/config.json";
3 | import Base from "@layouts/Base.astro";
4 | import Pagination from "@layouts/components/Pagination.astro";
5 | import Posts from "@layouts/Posts.astro";
6 | import { getSinglePage } from "@lib/contentParser.astro";
7 | import { sortByDate } from "@lib/utils/sortFunctions";
8 |
9 | export async function getStaticPaths() {
10 | const posts = await getSinglePage("posts");
11 | const totalPages = Math.ceil(posts.length / config.settings.pagination);
12 | const paths = [];
13 |
14 | for (let i = 1; i < totalPages; i++) {
15 | paths.push({
16 | params: {
17 | slug: (i + 1).toString(),
18 | },
19 | });
20 | }
21 | return paths;
22 | }
23 |
24 | const { slug } = Astro.params;
25 | const posts = await getSinglePage("posts");
26 | const sortedPosts = sortByDate(posts);
27 | const totalPages = Math.ceil(posts.length / config.settings.pagination);
28 | const currentPage = slug && !isNaN(Number(slug)) ? Number(slug) : 1;
29 | const indexOfLastPost = currentPage * config.settings.pagination;
30 | const indexOfFirstPost = indexOfLastPost - config.settings.pagination;
31 | const currentPosts = sortedPosts.slice(indexOfFirstPost, indexOfLastPost);
32 | ---
33 |
34 |
35 |
41 |
42 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy to GitHub Pages
2 |
3 | on:
4 | # Trigger the workflow every time you push to the `main` branch
5 | # Using a different branch name? Replace `main` with your branch’s name
6 | push:
7 | branches: [ main ]
8 | # Allows you to run this workflow manually from the Actions tab on GitHub.
9 | workflow_dispatch:
10 |
11 | # Allow this job to clone the repo and create a page deployment
12 | permissions:
13 | contents: read
14 | pages: write
15 | id-token: write
16 |
17 | jobs:
18 | build:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: Checkout your repository using git
22 | uses: actions/checkout@v3
23 | - name: Install, build, and upload your site
24 | uses: withastro/action@v0
25 | # with:
26 | # path: . # The root location of your Astro project inside the repository. (optional)
27 | # node-version: 16 # The specific version of Node that should be used to build your site. Defaults to 16. (optional)
28 | # package-manager: yarn # The Node package manager that should be used to install dependencies and build your site. Automatically detected based on your lockfile. (optional)
29 |
30 | deploy:
31 | needs: build
32 | runs-on: ubuntu-latest
33 | environment:
34 | name: github-pages
35 | url: ${{ steps.deployment.outputs.page_url }}
36 | steps:
37 | - name: Deploy to GitHub Pages
38 | id: deployment
39 | uses: actions/deploy-pages@v1
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/lib/utils/textConverter.ts:
--------------------------------------------------------------------------------
1 | import { slug } from 'github-slugger';
2 | import { marked } from "marked";
3 |
4 | // slugify
5 | export const slugify = (content: string) => {
6 | if (!content) return null;
7 |
8 | return slug(content);
9 | };
10 |
11 | // markdownify
12 | export const markdownify = (content: string) => {
13 | if (!content) return null;
14 |
15 | return marked.parseInline(content);
16 | };
17 |
18 | // humanize
19 | export const humanize = (content: string) => {
20 | if (!content) return null;
21 |
22 | return content
23 | .replace(/^[\s_]+|[\s_]+$/g, "")
24 | .replace(/[-_\s]+/g, " ")
25 | .replace(/^[a-z]/, function(m) {
26 | return m.toUpperCase();
27 | })
28 | };
29 |
30 | // plainify
31 | export const plainify = (content: string) => {
32 | if (!content) return null;
33 |
34 | const filterBrackets = content.replace(/<\/?[^>]+(>|$)/gm, "");
35 | const filterSpaces = filterBrackets.replace(/[\r\n]\s*[\r\n]/gm, "");
36 | const stripHTML = htmlEntityDecoder(filterSpaces);
37 | return stripHTML;
38 | };
39 |
40 | // strip entities for plainify
41 | const htmlEntityDecoder = (htmlWithEntities: string): string => {
42 | let entityList: { [key: string]: string } = {
43 | " ": " ",
44 | "<": "<",
45 | ">": ">",
46 | "&": "&",
47 | """: '"',
48 | "'": "'",
49 | };
50 | let htmlWithoutEntities: string = htmlWithEntities.replace(
51 | /(&|<|>|"|')/g,
52 | (entity: string): string => {
53 | return entityList[entity];
54 | }
55 | );
56 | return htmlWithoutEntities;
57 | };
58 |
--------------------------------------------------------------------------------
/src/pages/authors/page/[slug].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import config from "@config/config.json";
3 | import Authors from "@layouts/Authors.astro";
4 | import Base from "@layouts/Base.astro";
5 | import Pagination from "@layouts/components/Pagination.astro";
6 | import { getSinglePage } from "@lib/contentParser.astro";
7 | import { sortByDate } from "@lib/utils/sortFunctions";
8 | import { markdownify } from "@lib/utils/textConverter";
9 |
10 | export async function getStaticPaths() {
11 | const authors = await getSinglePage("authors");
12 | const totalPages = Math.ceil(authors.length / config.settings.pagination);
13 | const paths = [];
14 |
15 | for (let i = 1; i < totalPages; i++) {
16 | paths.push({
17 | params: {
18 | slug: (i + 1).toString(),
19 | },
20 | });
21 | }
22 | return paths;
23 | }
24 |
25 | const { slug } = Astro.params;
26 | const authors = await getSinglePage("authors");
27 | const sortedPosts = sortByDate(authors);
28 | const totalPages = Math.ceil(authors.length / config.settings.pagination);
29 | const currentPage = slug && !isNaN(Number(slug)) ? Number(slug) : 1;
30 | const indexOfLastPost = currentPage * config.settings.pagination;
31 | const indexOfFirstPost = indexOfLastPost - config.settings.pagination;
32 | const currentPosts = sortedPosts.slice(indexOfFirstPost, indexOfLastPost);
33 | ---
34 |
35 |
36 |
47 |
48 |
--------------------------------------------------------------------------------
/src/layouts/components/SimilarPosts.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Image } from "@astrojs/image/components";
3 | import dateFormat from "@lib/utils/dateFormat";
4 | import { humanize,slugify } from "@lib/utils/textConverter";
5 | import { BiCalendarEdit,BiCategoryAlt } from "react-icons/bi/index.js";
6 | const { posts } = Astro.props;
7 | ---
8 |
9 |
10 | {
11 | posts.map((post: any, i: number) => (
12 |
13 | {post.data.image && (
14 |
15 |
22 |
23 | )}
24 |
25 |
26 |
27 | <>{dateFormat(post.data.date)}>
28 |
29 |
30 |
31 | <>
32 |
44 | >
45 |
46 |
47 |
52 |
53 | ))
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/src/content/pages/privacy-policy.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Privacy"
3 | description: "this is meta description"
4 | draft: false
5 | ---
6 |
7 | #### Responsibility of Contributors
8 |
9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Purus, donec nunc eros, ullamcorper id feugiat quisque aliquam sagittis. Sem turpis sed viverra massa gravida pharetra. Non dui dolor potenti eu dignissim fusce. Ultrices amet, in curabitur a arcu a lectus morbi id. Iaculis erat sagittis in tortor cursus. Molestie urna eu tortor, erat scelerisque eget. Nunc hendrerit sed interdum lacus. Lorem quis viverra sed
10 |
11 | pretium, aliquam sit. Praesent elementum magna amet, tincidunt eros, nibh in leo. Malesuada purus, lacus, at aliquam suspendisse tempus. Quis tempus amet, velit nascetur sollicitudin. At sollicitudin eget amet in. Eu velit nascetur sollicitudin erhdfvssfvrgss eget viverra nec elementum. Lacus, facilisis tristique lectus in.
12 |
13 | #### Gathering of Personal Information
14 |
15 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Purus, donec nunc eros, ullamcorper id feugiat quisque aliquam sagittis. Sem turpis sed viverra massa gravida pharetra. Non dui dolor potenti eu dignissim fusce. Ultrices amet, in curabitur a arcu a lectus morbi id. Iaculis erat sagittis in tortor cursus. Molestie urna eu tortor, erat scelerisque eget. Nunc hendrerit sed interdum lacus. Lorem quis viverra sed
16 |
17 | #### Protection of Personal- Information
18 |
19 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Purus, donec nunc eros, ullamcorper id feugiat quisque aliquam sagittis. Sem turpis sed viverra massa gravida pharetra. Non dui dolor potenti eu dignissim fusce. Ultrices amet, in curabitur a arcu a lectus morbi id. Iaculis erat sagittis in tortor cursus.
20 |
21 | Molestie urna eu tortor, erat scelerisque eget. Nunc hendrerit sed interdum lacus. Lorem quis viverra sed
22 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Purus, donec nunc eros, ullamcorper id feugiat
23 |
24 | #### Privacy Policy Changes
25 |
26 | 1. Sll the Themefisher items are designed to be with the latest , We check all
27 | 2. comments that threaten or harm the reputation of any person or organization
28 | 3. personal information including, but limited to, email addresses, telephone numbers
29 | 4. Any Update come in The technology Customer will get automatic Notification.
30 |
--------------------------------------------------------------------------------
/src/content/config.ts:
--------------------------------------------------------------------------------
1 | import { defineCollection, z } from "astro:content";
2 |
3 | // Post collection schema
4 | const postsCollection = defineCollection({
5 | schema: z.object({
6 | id: z.string().optional(),
7 | title: z.string(),
8 | meta_title: z.string().optional(),
9 | description: z.string().optional(),
10 | date: z.date().optional(),
11 | image: z.string().optional(),
12 | authors: z.array(z.string()).default(["admin"]),
13 | categories: z.array(z.enum(["passport", "grants-stack", "allo", "gitcoin"])).optional(),
14 | tags: z.array(z.string()).default(["others"]),
15 | draft: z.boolean().optional(),
16 | }),
17 | });
18 |
19 | const categoryCollection = defineCollection({
20 | schema: z.object({
21 | id: z.string().optional(),
22 | title: z.string(),
23 | meta_title: z.string().optional(),
24 | image: z.string().optional(),
25 | social: z
26 | .object({
27 | twitter: z.string().optional(),
28 | github: z.string().optional(),
29 | })
30 | .optional(),
31 | draft: z.boolean().optional()
32 | })
33 | });
34 |
35 | // Author collection schema
36 | const authorsCollection = defineCollection({
37 | schema: z.object({
38 | id: z.string().optional(),
39 | title: z.string(),
40 | meta_title: z.string().optional(),
41 | image: z.string().optional(),
42 | description: z.string().optional(),
43 | social: z
44 | .object({
45 | facebook: z.string().optional(),
46 | twitter: z.string().optional(),
47 | instagram: z.string().optional(),
48 | github: z.string().optional(),
49 | quests: z.string().optional(),
50 | twitch: z.string().optional(),
51 | youtube: z.string().optional(),
52 | })
53 | .optional(),
54 | draft: z.boolean().optional(),
55 | }),
56 | });
57 |
58 | // Pages collection schema
59 | const pagesCollection = defineCollection({
60 | schema: z.object({
61 | id: z.string().optional(),
62 | title: z.string(),
63 | meta_title: z.string().optional(),
64 | description: z.string().optional(),
65 | image: z.string().optional(),
66 | layout: z.string().optional(),
67 | draft: z.boolean().optional(),
68 | }),
69 | });
70 |
71 | // Export collections
72 | export const collections = {
73 | posts: postsCollection,
74 | pages: pagesCollection,
75 | authors: authorsCollection,
76 | categories: categoryCollection,
77 | };
78 |
--------------------------------------------------------------------------------
/src/styles/components.scss:
--------------------------------------------------------------------------------
1 | // section style
2 | .section {
3 | @apply py-20;
4 | }
5 |
6 | // container
7 | .container {
8 | @apply max-w-[1000px] px-4 md:px-8;
9 | }
10 |
11 | // page heading
12 | .page-heading {
13 | @apply mb-20 text-center font-bold leading-10;
14 | &:after {
15 | @apply mx-auto mt-4 block h-1 w-10 rounded-full bg-primary content-[''];
16 | }
17 | }
18 |
19 | // form style
20 | .form-inputs * {
21 | @apply mb-5 leading-10;
22 | }
23 |
24 | // image cover
25 | .img-cover {
26 | @apply leading-none;
27 | span {
28 | @apply h-full w-full;
29 | }
30 | img {
31 | @apply object-cover;
32 | }
33 | }
34 |
35 | // author-image
36 | .author-image {
37 | @apply mr-2 align-top;
38 | img {
39 | @apply max-h-[25px] max-w-[25px] rounded-full;
40 | }
41 | }
42 |
43 | // social icon style
44 | .social-icons {
45 | @apply space-x-4;
46 | li {
47 | @apply inline-block;
48 | a {
49 | @apply block h-11 w-11 rounded-lg border border-light bg-transparent text-center text-white transition hover:border-primary hover:bg-primary;
50 | svg {
51 | @apply m-auto h-11 text-base;
52 | }
53 | }
54 | }
55 | }
56 |
57 | .social-icons-simple {
58 | @apply space-x-2;
59 | li {
60 | @apply inline-block;
61 | a {
62 | @apply block p-3 text-dark transition hover:text-primary;
63 | svg {
64 | @apply text-lg;
65 | }
66 | }
67 | }
68 | }
69 |
70 | .social-share {
71 | @apply space-x-1;
72 | li {
73 | @apply inline-block;
74 | a {
75 | @apply block p-3 transition transition duration-300 hover:text-primary;
76 | }
77 | }
78 | }
79 |
80 | // form style
81 | .form-input,
82 | .form-textarea {
83 | @apply rounded-md border-border py-3 text-text focus:border-primary focus:ring-transparent;
84 | }
85 |
86 | // content style
87 | .content {
88 | @apply prose max-w-none prose-headings:font-bold prose-h1:mb-4 prose-h1:text-h1-sm prose-h2:mb-4 prose-h2:mt-4 prose-h2:text-h2-sm prose-h3:mt-4 prose-h3:text-h3-sm prose-h4:mt-4 prose-h5:mb-4 prose-h6:mb-6 prose-blockquote:rounded-lg prose-blockquote:border-primary prose-blockquote:bg-theme-light prose-blockquote:px-7 prose-blockquote:py-3 prose-blockquote:text-lg prose-blockquote:leading-8 prose-pre:px-6 prose-pre:py-5 md:prose-h1:text-h1 md:prose-h2:text-h2 md:prose-h3:text-h3;
89 | }
90 |
91 | // footer
92 | footer p a {
93 | @apply transition-all duration-200 hover:text-white;
94 | }
95 |
--------------------------------------------------------------------------------
/public/images/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/public/images/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const theme = require("./src/config/theme.json");
2 |
3 | let font_base = Number(theme.fonts.font_size.base.replace("px", ""));
4 | let font_scale = Number(theme.fonts.font_size.scale);
5 | let h6 = font_base / font_base;
6 | let h5 = h6 * font_scale;
7 | let h4 = h5 * font_scale;
8 | let h3 = h4 * font_scale;
9 | let h2 = h3 * font_scale;
10 | let h1 = h2 * font_scale;
11 | let fontPrimary, fontPrimaryType, fontSecondary, fontSecondaryType;
12 | if (theme.fonts.font_family.primary) {
13 | fontPrimary = theme.fonts.font_family.primary
14 | .replace(/\+/g, " ")
15 | .replace(/:[ital,]*[ital@]*[wght@]*[0-9,;]+/gi, "");
16 | fontPrimaryType = theme.fonts.font_family.primary_type;
17 | }
18 | if (theme.fonts.font_family.secondary) {
19 | fontSecondary = theme.fonts.font_family.secondary
20 | .replace(/\+/g, " ")
21 | .replace(/:[ital,]*[ital@]*[wght@]*[0-9,;]+/gi, "");
22 | fontSecondaryType = theme.fonts.font_family.secondary_type;
23 | }
24 |
25 | /** @type {import('tailwindcss').Config} */
26 | module.exports = {
27 | content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
28 | theme: {
29 | screens: {
30 | sm: "540px",
31 | md: "768px",
32 | lg: "1024px",
33 | xl: "1280px",
34 | "2xl": "1536px",
35 | },
36 | container: {
37 | center: true,
38 | padding: "2rem",
39 | },
40 | extend: {
41 | colors: {
42 | text: theme.colors.default.text_color.default,
43 | light: theme.colors.default.text_color.light,
44 | dark: theme.colors.default.text_color.dark,
45 | primary: theme.colors.default.theme_color.primary,
46 | secondary: theme.colors.default.theme_color.secondary,
47 | body: theme.colors.default.theme_color.body,
48 | border: theme.colors.default.theme_color.border,
49 | "theme-light": theme.colors.default.theme_color.theme_light,
50 | "theme-dark": theme.colors.default.theme_color.theme_dark,
51 | },
52 | fontSize: {
53 | base: font_base + "px",
54 | h1: h1 + "rem",
55 | "h1-sm": h1 * 0.8 + "rem",
56 | h2: h2 + "rem",
57 | "h2-sm": h2 * 0.8 + "rem",
58 | h3: h3 + "rem",
59 | "h3-sm": h3 * 0.8 + "rem",
60 | h4: h4 + "rem",
61 | h5: h5 + "rem",
62 | h6: h6 + "rem",
63 | },
64 | fontFamily: {
65 | primary: [fontPrimary, fontPrimaryType],
66 | secondary: [fontSecondary, fontSecondaryType],
67 | },
68 | },
69 | },
70 | plugins: [
71 | require("@tailwindcss/typography"),
72 | require("@tailwindcss/forms"),
73 | require("tailwind-bootstrap-grid")({
74 | generateContainer: false,
75 | gridGutters: {
76 | 1: "0.5rem",
77 | 2: "0.75rem",
78 | 3: "1.25rem",
79 | 4: "2rem",
80 | 5: "3.5rem",
81 | },
82 | }),
83 | ],
84 | };
85 |
--------------------------------------------------------------------------------
/src/layouts/partials/Header.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Logo from "@components/Logo.astro";
3 | import menu from "@config/menu.json";
4 | import { IoSearch } from "react-icons/io5/index.js";
5 |
6 | export interface ChildNavigationLink {
7 | name: string;
8 | url: string;
9 | }
10 |
11 | export interface NavigationLink {
12 | name: string;
13 | url: string;
14 | hasChildren?: boolean;
15 | children?: ChildNavigationLink[];
16 | }
17 |
18 | const { main }: { main: NavigationLink[] } = menu;
19 | ---
20 |
21 |
101 |
--------------------------------------------------------------------------------
/src/layouts/Posts.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Image } from "@astrojs/image/components";
3 | import config from "@config/config.json";
4 | import { getSinglePage } from "@lib/contentParser.astro";
5 | import dateFormat from "@lib/utils/dateFormat";
6 | import { humanize,slugify } from "@lib/utils/textConverter";
7 | import { BiCalendarEdit,BiCategoryAlt } from "react-icons/bi/index.js";
8 | const authors = await getSinglePage("authors");
9 | const { summary_length } = config.settings;
10 | const { className, posts, fluid } = Astro.props;
11 | ---
12 |
13 |
14 | {
15 | posts.map((post: any, i: number) => (
16 |
17 | {post.data.image && (
18 |
19 |
26 |
27 | )}
28 |
29 |
30 | {authors
31 | .filter((author) =>
32 | post.data.authors
33 | .map((author: string) => slugify(author))
34 | .includes(slugify(author.data.title))
35 | )
36 | .map((author) => (
37 |
41 | {author.data.image && (
42 |
49 | )}
50 | {author.data.title}
51 |
52 | ))}
53 |
54 |
55 |
56 | <>{dateFormat(post.data.date)}>
57 |
58 |
59 |
60 | <>
61 |
73 | >
74 |
75 |
76 |
81 |
82 | {post.body?.slice(0, Number(i === 0 && fluid != false ? summary_length * 2 : summary_length))}...
83 |
84 |
85 | ))
86 | }
87 |
88 |
--------------------------------------------------------------------------------
/src/pages/authors/[single].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Image } from "@astrojs/image/components";
3 |
4 | import AuthorSingle from "@layouts/AuthorSingle.astro";
5 | import Base from "@layouts/Base.astro";
6 | import { getSinglePage } from "@lib/contentParser.astro";
7 | import dateFormat from "@lib/utils/dateFormat";
8 |
9 | import { sortByDate } from "@lib/utils/sortFunctions";
10 | import { humanize,slugify } from "@lib/utils/textConverter";
11 | import { BiCalendarEdit,BiCategoryAlt } from "react-icons/bi/index.js";
12 |
13 | export async function getStaticPaths() {
14 | const authors = await getSinglePage("authors");
15 |
16 | const paths = authors.map((author) => ({
17 | params: {
18 | single: author.slug,
19 | },
20 | props: { author },
21 | }));
22 | return paths;
23 | }
24 |
25 | const { author } = Astro.props;
26 | const { title, meta_title, description, image } = author.data;
27 |
28 | // Author Posts
29 | const posts = await getSinglePage("posts");
30 | const sortPostsByDate = sortByDate(posts);
31 | const currentPosts = sortPostsByDate.filter((post) => {
32 | return post.data.authors.map((author: string) => slugify(author)).includes(slugify(title))
33 | });
34 | ---
35 |
36 |
42 |
43 |
44 | {currentPosts.length > 0 && (
45 |
46 |
47 |
Recent Posts
48 |
49 | {currentPosts.map((post: any, i: number) => (
50 |
51 | {post.data.image && (
52 |
53 |
60 |
61 | )}
62 |
63 |
64 |
65 | <>{dateFormat(post.data.date)}>
66 |
67 |
68 |
69 | <>
70 |
82 | >
83 |
84 |
85 |
90 |
91 | ))}
92 |
93 |
94 |
95 | )}
96 |
97 |
--------------------------------------------------------------------------------
/public/.htaccess:
--------------------------------------------------------------------------------
1 | ##### Optimize default expiration time - BEGIN
2 |
3 |
4 | ## Enable expiration control
5 | ExpiresActive On
6 |
7 | ## CSS and JS expiration: 1 week after request
8 | ExpiresByType text/css "now plus 1 week"
9 | ExpiresByType application/javascript "now plus 1 week"
10 | ExpiresByType application/x-javascript "now plus 1 week"
11 |
12 | ## Image files expiration: 1 month after request
13 | ExpiresByType image/bmp "now plus 1 month"
14 | ExpiresByType image/gif "now plus 1 month"
15 | ExpiresByType image/jpeg "now plus 1 month"
16 | ExpiresByType image/webp "now plus 1 month"
17 | ExpiresByType image/jp2 "now plus 1 month"
18 | ExpiresByType image/pipeg "now plus 1 month"
19 | ExpiresByType image/png "now plus 1 month"
20 | ExpiresByType image/svg+xml "now plus 1 month"
21 | ExpiresByType image/tiff "now plus 1 month"
22 | ExpiresByType image/x-icon "now plus 1 month"
23 | ExpiresByType image/ico "now plus 1 month"
24 | ExpiresByType image/icon "now plus 1 month"
25 | ExpiresByType text/ico "now plus 1 month"
26 | ExpiresByType application/ico "now plus 1 month"
27 | ExpiresByType image/vnd.wap.wbmp "now plus 1 month"
28 |
29 | ## Font files expiration: 1 month after request
30 | ExpiresByType application/x-font-ttf "now plus 1 month"
31 | ExpiresByType application/x-font-opentype "now plus 1 month"
32 | ExpiresByType application/x-font-woff "now plus 1 month"
33 | ExpiresByType font/woff2 "now plus 1 month"
34 | ExpiresByType image/svg+xml "now plus 1 month"
35 |
36 | ## Audio files expiration: 1 month after request
37 | ExpiresByType audio/ogg "now plus 1 month"
38 | ExpiresByType application/ogg "now plus 1 month"
39 | ExpiresByType audio/basic "now plus 1 month"
40 | ExpiresByType audio/mid "now plus 1 month"
41 | ExpiresByType audio/midi "now plus 1 month"
42 | ExpiresByType audio/mpeg "now plus 1 month"
43 | ExpiresByType audio/mp3 "now plus 1 month"
44 | ExpiresByType audio/x-aiff "now plus 1 month"
45 | ExpiresByType audio/x-mpegurl "now plus 1 month"
46 | ExpiresByType audio/x-pn-realaudio "now plus 1 month"
47 | ExpiresByType audio/x-wav "now plus 1 month"
48 |
49 | ## Movie files expiration: 1 month after request
50 | ExpiresByType application/x-shockwave-flash "now plus 1 month"
51 | ExpiresByType x-world/x-vrml "now plus 1 month"
52 | ExpiresByType video/x-msvideo "now plus 1 month"
53 | ExpiresByType video/mpeg "now plus 1 month"
54 | ExpiresByType video/mp4 "now plus 1 month"
55 | ExpiresByType video/quicktime "now plus 1 month"
56 | ExpiresByType video/x-la-asf "now plus 1 month"
57 | ExpiresByType video/x-ms-asf "now plus 1 month"
58 |
59 | ##### Optimize default expiration time - END
60 |
61 | ##### 1 Month for most static resources
62 |
63 | Header set Cache-Control "max-age=2592000, public"
64 |
65 |
66 | ##### Enable gzip compression for resources
67 |
68 | mod_gzip_on Yes
69 | mod_gzip_dechunk Yes
70 | mod_gzip_item_include file .(html?|txt|css|js|php)$
71 | mod_gzip_item_include handler ^cgi-script$
72 | mod_gzip_item_include mime ^text/.*
73 | mod_gzip_item_include mime ^application/x-javascript.*
74 | mod_gzip_item_exclude mime ^image/.*
75 | mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
76 |
77 |
78 | ##### Or, compress certain file types by extension:
79 |
80 | SetOutputFilter DEFLATE
81 |
82 |
83 | ##### Set Header Vary: Accept-Encoding
84 |
85 |
86 | Header append Vary: Accept-Encoding
87 |
88 |
--------------------------------------------------------------------------------
/src/layouts/Base.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import TwSizeIndicator from "@components/TwSizeIndicator.astro";
3 | import config from "@config/config.json";
4 | import theme from "@config/theme.json";
5 | import { plainify } from "@lib/utils/textConverter";
6 | import Footer from "@partials/Footer.astro";
7 | import Header from "@partials/Header.astro";
8 | import "@styles/style.scss";
9 |
10 | // font families
11 | const pf = theme.fonts.font_family.primary;
12 | const sf = theme.fonts.font_family.secondary;
13 |
14 | // types for frontmatters
15 | export interface Props {
16 | title?: string;
17 | meta_title?: string;
18 | description?: string;
19 | image?: string;
20 | noindex?: boolean;
21 | canonical?: string;
22 | }
23 |
24 | // distructure frontmatters
25 | const { title, meta_title, description, image, noindex, canonical } =
26 | Astro.props;
27 | ---
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
65 |
66 |
67 |
68 | {plainify(meta_title ? meta_title : title ? title : config.site.title)}
69 |
70 |
71 |
72 | {canonical && }
73 |
74 |
75 | {noindex && }
76 |
77 |
78 |
84 |
85 |
86 |
87 |
88 |
89 |
95 |
96 |
97 |
103 |
104 |
108 |
109 |
110 |
116 |
117 |
118 |
124 |
125 |
126 |
132 |
133 |
134 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/src/layouts/PostSingle.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Image } from "@astrojs/image/components";
3 | import Share from "@components/Share.astro";
4 | import SimilarPosts from "@components/SimilarPosts.astro";
5 | import { getSinglePage } from "@lib/contentParser.astro";
6 | import dateFormat from "@lib/utils/dateFormat";
7 | import similerItems from "@lib/utils/similarItems";
8 | import { humanize,markdownify,slugify } from "@lib/utils/textConverter";
9 | import { BiCalendarEdit,BiCategoryAlt } from "react-icons/bi/index.js";
10 |
11 | const allAuthors = await getSinglePage("authors");
12 | const posts = await getSinglePage("posts");
13 | const { post } = Astro.props;
14 | const similarPosts = similerItems(post, posts, post.slug);
15 | const { Content } = await post.render();
16 | const { title, description, authors, categories, image, date, tags } =
17 | post.data;
18 | ---
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | {
28 | allAuthors
29 | .filter((author) =>
30 | authors
31 | .map((author: string) => slugify(author))
32 | .includes(slugify(author.data.title))
33 | )
34 | .map((author, i) => (
35 |
39 | {author.data.image && (
40 |
47 | )}
48 | {author.data.title}
49 |
50 | ))
51 | }
52 |
53 |
54 |
55 | <>{dateFormat(date)}>
56 |
57 |
58 |
59 | <>
60 |
74 | >
75 |
76 |
77 |
78 |
79 |
80 | {image && (
81 |
88 | )}
89 |
90 |
91 |
92 |
93 |
94 |
95 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | {
124 | similarPosts.length > 0 && (
125 |
126 |
127 |
Similar Posts
128 |
129 |
130 |
131 | )
132 | }
133 |
--------------------------------------------------------------------------------
/src/layouts/components/Pagination.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { section, currentPage, totalPages } = Astro.props;
3 |
4 | const indexPageLink = currentPage === 2;
5 | const hasPrevPage = currentPage > 1;
6 | const hasNextPage = totalPages > currentPage;
7 |
8 | let pageList = [];
9 | for (let i = 1; i <= totalPages; i++) {
10 | pageList.push(i);
11 | }
12 | ---
13 |
14 | {
15 | totalPages > 1 && (
16 |
17 | {/* previous */}
18 | {hasPrevPage ? (
19 |
27 | Previous
28 |
35 |
40 |
41 |
42 | ) : (
43 |
44 | Previous
45 |
52 |
57 |
58 |
59 | )}
60 |
61 | {/* page index */}
62 | {pageList.map((pagination, i) =>
63 | pagination === currentPage ? (
64 |
68 | {pagination}
69 |
70 | ) : (
71 |
80 | {pagination}
81 |
82 | )
83 | )}
84 |
85 | {/* next page */}
86 | {hasNextPage ? (
87 |
91 | Next
92 |
99 |
104 |
105 |
106 | ) : (
107 |
108 | Next
109 |
116 |
121 |
122 |
123 | )}
124 |
125 | )
126 | }
127 |
--------------------------------------------------------------------------------
/src/layouts/Search.tsx:
--------------------------------------------------------------------------------
1 | import config from "@config/config.json";
2 | import dateFormat from "@lib/utils/dateFormat";
3 | import { humanize, slugify } from "@lib/utils/textConverter";
4 | import Fuse from "fuse.js";
5 | import { useEffect, useRef, useState } from "react";
6 | import { BiCalendarEdit, BiCategoryAlt } from "react-icons/bi/index.js";
7 | const { summary_length } = config.settings;
8 |
9 | export type SearchItem = {
10 | slug: string;
11 | data: any;
12 | content: any;
13 | };
14 |
15 | interface Props {
16 | searchList: SearchItem[];
17 | }
18 |
19 | interface SearchResult {
20 | item: SearchItem;
21 | refIndex: number;
22 | }
23 |
24 | export default function SearchBar({ searchList }: Props) {
25 | const inputRef = useRef(null);
26 | const [inputVal, setInputVal] = useState("");
27 | const [searchResults, setSearchResults] = useState(
28 | null
29 | );
30 |
31 | const handleChange = (e: React.FormEvent) => {
32 | setInputVal(e.currentTarget.value);
33 | };
34 |
35 | const fuse = new Fuse(searchList, {
36 | keys: ["data.title", "data.categories", "data.tags"],
37 | includeMatches: true,
38 | minMatchCharLength: 2,
39 | threshold: 0.5,
40 | });
41 |
42 | useEffect(() => {
43 | const searchUrl = new URLSearchParams(window.location.search);
44 | const searchStr = searchUrl.get("q");
45 | if (searchStr) setInputVal(searchStr);
46 |
47 | setTimeout(function () {
48 | inputRef.current!.selectionStart = inputRef.current!.selectionEnd =
49 | searchStr?.length || 0;
50 | }, 50);
51 | }, []);
52 |
53 | useEffect(() => {
54 | let inputResult = inputVal.length > 2 ? fuse.search(inputVal) : [];
55 | setSearchResults(inputResult);
56 |
57 | if (inputVal.length > 0) {
58 | const searchParams = new URLSearchParams(window.location.search);
59 | searchParams.set("q", inputVal);
60 | const newRelativePathQuery =
61 | window.location.pathname + "?" + searchParams.toString();
62 | history.pushState(null, "", newRelativePathQuery);
63 | } else {
64 | history.pushState(null, "", window.location.pathname);
65 | }
66 | }, [inputVal]);
67 |
68 | return (
69 |
70 |
81 |
82 | {inputVal.length > 1 && (
83 |
84 | Found {searchResults?.length}
85 | {searchResults?.length && searchResults?.length === 1
86 | ? " result"
87 | : " results"}{" "}
88 | for '{inputVal}'
89 |
90 | )}
91 |
92 |
93 | {searchResults?.map(({ item }) => (
94 |
95 | {item.data.image && (
96 |
97 |
104 |
105 | )}
106 |
107 |
108 |
109 |
110 | <>{dateFormat(item.data.date)}>
111 |
112 |
113 |
114 | <>
115 |
127 | >
128 |
129 |
130 |
131 |
136 |
137 | {item.content?.slice(0, Number(summary_length))}...
138 |
139 |
140 | ))}
141 |
142 |
143 | );
144 | }
145 |
--------------------------------------------------------------------------------
/public/images/gitcoin-engineering.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/layouts/components/Social.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { source, className } = Astro.props;
3 |
4 | import {
5 | IoCall,
6 | IoGlobeOutline,
7 | IoLocation,
8 | IoLogoBehance,
9 | IoLogoBitbucket,
10 | IoLogoCodepen,
11 | IoLogoDiscord,
12 | IoLogoDribbble,
13 | IoLogoFacebook,
14 | IoLogoFoursquare,
15 | IoLogoGithub,
16 | IoLogoGitlab,
17 | IoLogoInstagram,
18 | IoLogoLinkedin,
19 | IoLogoMastodon,
20 | IoLogoMedium,
21 | IoLogoPinterest,
22 | IoLogoReddit,
23 | IoLogoRss,
24 | IoLogoSkype,
25 | IoLogoSlack,
26 | IoLogoSnapchat,
27 | IoLogoSoundcloud,
28 | IoLogoTiktok,
29 | IoLogoTumblr,
30 | IoLogoTwitter,
31 | IoLogoVimeo,
32 | IoLogoVk,
33 | IoLogoWhatsapp,
34 | IoLogoYoutube,
35 | IoMail,
36 | IoLogoTwitch,
37 | } from "react-icons/io5/index.js";
38 |
39 | const {
40 | facebook,
41 | twitter,
42 | mastodon,
43 | instagram,
44 | youtube,
45 | linkedin,
46 | github,
47 | gitlab,
48 | discord,
49 | slack,
50 | medium,
51 | codepen,
52 | bitbucket,
53 | dribbble,
54 | behance,
55 | pinterest,
56 | soundcloud,
57 | tumblr,
58 | reddit,
59 | vk,
60 | whatsapp,
61 | snapchat,
62 | vimeo,
63 | tiktok,
64 | foursquare,
65 | rss,
66 | email,
67 | phone,
68 | address,
69 | skype,
70 | website,
71 | twitch,
72 | } = source;
73 | ---
74 |
75 |
76 | {
77 | facebook && (
78 |
79 |
85 |
86 |
87 |
88 | )
89 | }
90 | {
91 | twitter && (
92 |
93 |
99 |
100 |
101 |
102 | )
103 | }
104 | {
105 | mastodon && (
106 |
107 |
113 |
114 |
115 |
116 | )
117 | }
118 | {
119 | instagram && (
120 |
121 |
127 |
128 |
129 |
130 | )
131 | }
132 | {
133 | youtube && (
134 |
135 |
141 |
142 |
143 |
144 | )
145 | }
146 | {
147 | linkedin && (
148 |
149 |
155 |
156 |
157 |
158 | )
159 | }
160 | {
161 | github && (
162 |
163 |
169 |
170 |
171 |
172 | )
173 | }
174 | {
175 | gitlab && (
176 |
177 |
183 |
184 |
185 |
186 | )
187 | }
188 | {
189 | discord && (
190 |
191 |
197 |
198 |
199 |
200 | )
201 | }
202 | {
203 | slack && (
204 |
205 |
211 |
212 |
213 |
214 | )
215 | }
216 | {
217 | medium && (
218 |
219 |
225 |
226 |
227 |
228 | )
229 | }
230 | {
231 | codepen && (
232 |
233 |
239 |
240 |
241 |
242 | )
243 | }
244 | {
245 | bitbucket && (
246 |
247 |
253 |
254 |
255 |
256 | )
257 | }
258 | {
259 | dribbble && (
260 |
261 |
267 |
268 |
269 |
270 | )
271 | }
272 | {
273 | behance && (
274 |
275 |
281 |
282 |
283 |
284 | )
285 | }
286 | {
287 | pinterest && (
288 |
289 |
295 |
296 |
297 |
298 | )
299 | }
300 | {
301 | soundcloud && (
302 |
303 |
309 |
310 |
311 |
312 | )
313 | }
314 | {
315 | tumblr && (
316 |
317 |
323 |
324 |
325 |
326 | )
327 | }
328 | {
329 | reddit && (
330 |
331 |
337 |
338 |
339 |
340 | )
341 | }
342 | {
343 | vk && (
344 |
345 |
351 |
352 |
353 |
354 | )
355 | }
356 | {
357 | whatsapp && (
358 |
359 |
365 |
366 |
367 |
368 | )
369 | }
370 | {
371 | snapchat && (
372 |
373 |
379 |
380 |
381 |
382 | )
383 | }
384 | {
385 | vimeo && (
386 |
387 |
393 |
394 |
395 |
396 | )
397 | }
398 | {
399 | tiktok && (
400 |
401 |
407 |
408 |
409 |
410 | )
411 | }
412 | {
413 | foursquare && (
414 |
415 |
421 |
422 |
423 |
424 | )
425 | }
426 | {
427 | skype && (
428 |
429 |
435 |
436 |
437 |
438 | )
439 | }
440 | {
441 | website && (
442 |
443 |
449 |
450 |
451 |
452 | )
453 | }
454 | {
455 | rss && (
456 |
457 |
463 |
464 |
465 |
466 | )
467 | }
468 | {
469 | email && (
470 |
471 |
472 |
473 |
474 |
475 | )
476 | }
477 | {
478 | phone && (
479 |
480 |
481 |
482 |
483 |
484 | )
485 | }
486 | {
487 | address && (
488 |
489 |
495 |
496 |
497 |
498 | )
499 | }
500 | {
501 | twitch && (
502 |
503 |
509 |
510 |
511 |
512 | )
513 | }
514 |
515 |
--------------------------------------------------------------------------------