├── 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 |
10 |
11 |

12 |
13 | 14 |
15 |

16 |
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 |
19 |
20 | 21 |
22 |
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 |
11 |
12 |
13 |
14 |

15 | 16 |

17 |
18 |
19 |
20 | 21 | -------------------------------------------------------------------------------- /src/layouts/components/TwSizeIndicator.astro: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | { 5 | process.env.NODE_ENV === "development" && ( 6 |
7 | all 8 | 9 | 10 | 11 | 12 | 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 |
17 |
18 | 19 | 20 |
21 |
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 |
10 |
11 | {/* footer menu */} 12 | 23 | {/* social icons */} 24 | 25 | {/* copyright */} 26 |

27 |

28 |
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 |
18 |
19 |

20 | 21 | 22 |

23 |
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 | {title} 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 |
13 |
14 |

Tags

15 | 30 |
31 |
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 | {title} 35 | {title} 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 |
12 | {author.data.image && ( 13 |
14 | {author.data.title} 21 |
22 | )} 23 |

24 | 25 | {author.data.title} 26 | 27 |

28 |

29 | 30 | Read More 31 | 32 |

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 |
36 |
37 | 38 | 39 |
40 |
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 |
37 |
38 |

39 | 40 | 45 |

46 |
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 | {post.data.title} 22 | 23 | )} 24 | 47 |

48 | 49 | {post.data.title} 50 | 51 |

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 |
22 | 100 |
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 | {post.data.title} 26 | 27 | )} 28 | 76 |

77 | 78 | {post.data.title} 79 | 80 |

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 | {post.data.title} 60 | 61 | )} 62 | 85 |

86 | 87 | {post.data.title} 88 | 89 |

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 |