├── .nvmrc ├── .DS_Store ├── public ├── favicon.ico ├── favicon.png ├── Screenshot.png ├── fonts │ ├── .DS_Store │ ├── Roboto-Regular.ttf │ ├── Inconsolata-Black.ttf │ └── Inconsolata-Bold.ttf ├── images │ ├── .DS_Store │ └── x-icon.svg ├── zemerik_profile.png ├── profile_directory.png ├── screenshot_laptop.png ├── screenshot_phone.png ├── robots.txt └── prism-dracula.css ├── .astro ├── settings.json └── types.d.ts ├── src ├── env.d.ts ├── utils │ ├── days.js │ ├── years.js │ ├── months.js │ ├── colors.js │ ├── format-number.js │ ├── format-slug.js │ ├── is-new-content.js │ ├── create-excerpt.js │ ├── format-date.js │ ├── all-collections.js │ └── create-tags-collection.js ├── pages │ ├── api │ │ ├── happy-by-city.ts │ │ ├── reactions-by-slug.ts │ │ ├── add-reaction.ts │ │ └── page-view.ts │ ├── tags.astro │ ├── profiles.astro │ ├── index.astro │ ├── tags │ │ ├── [...tag].astro │ │ └── [tag] │ │ │ └── og.png.ts │ ├── posts │ │ └── [...slug].astro │ └── dashboard.astro ├── components │ ├── aside.astro │ ├── video-player.astro │ ├── powered-by-mdx.astro │ ├── astro-image.astro │ ├── cta-internal.astro │ ├── cta-external.astro │ ├── code-sandbox.astro │ ├── new-label.tsx │ ├── list-top-ten-cities.astro │ ├── table-of-contents.astro │ ├── list-popular.astro │ ├── list-top-referrers.astro │ ├── tags-list.astro │ ├── search-trigger.tsx │ ├── stackblitz-embed.tsx │ ├── featured-image-card.astro │ ├── search-input.tsx │ ├── nav-link.tsx │ ├── loading.tsx │ ├── click-to-copy-email.jsx │ ├── audio-feed-embed.astro │ ├── search-tags.tsx │ ├── line-chart-visits.astro │ ├── donut-chart-tags.astro │ ├── profile-card.astro │ ├── collections-list.astro │ ├── happy-all-cities.tsx │ ├── search-modal.tsx │ ├── line-chart-years.astro │ └── bar-chart-days.astro ├── content │ ├── profiles │ │ ├── harrysingh100.mdx │ │ ├── axorax.mdx │ │ ├── calllme-shadow.mdx │ │ ├── sankitdev.mdx │ │ ├── parthivkapoor0101.mdx │ │ ├── Developer-Utkarsh.mdx │ │ ├── rohitshah09.mdx │ │ └── zemerik.mdx │ └── config.js ├── services │ └── resize-image.ts └── layouts │ ├── nav-links.ts │ ├── main.astro │ └── layout.tsx ├── SECURITY.md ├── tsconfig.json ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── style.yml │ ├── documentation.yml │ └── bug.yml ├── pull_request_template.md └── workflows │ └── greetings.yml ├── LICENCE ├── package.json ├── astro.config.mjs ├── .gitignore ├── CONTRIBUTING.md ├── README.md ├── CODE_OF_CONDUCT.md └── tailwind.config.cjs /.nvmrc: -------------------------------------------------------------------------------- 1 | v18.14.1 -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/.DS_Store -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/favicon.png -------------------------------------------------------------------------------- /.astro/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "_variables": { 3 | "lastUpdateCheck": 1726855220054 4 | } 5 | } -------------------------------------------------------------------------------- /public/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/Screenshot.png -------------------------------------------------------------------------------- /public/fonts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/fonts/.DS_Store -------------------------------------------------------------------------------- /public/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/images/.DS_Store -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// -------------------------------------------------------------------------------- /public/zemerik_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/zemerik_profile.png -------------------------------------------------------------------------------- /public/profile_directory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/profile_directory.png -------------------------------------------------------------------------------- /public/screenshot_laptop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/screenshot_laptop.png -------------------------------------------------------------------------------- /public/screenshot_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/screenshot_phone.png -------------------------------------------------------------------------------- /public/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /src/utils/days.js: -------------------------------------------------------------------------------- 1 | const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; 2 | 3 | export default days; 4 | -------------------------------------------------------------------------------- /src/utils/years.js: -------------------------------------------------------------------------------- 1 | const years = ['2019', '2020', '2021', '2022', '2023', '2024']; 2 | 3 | export default years; 4 | -------------------------------------------------------------------------------- /public/fonts/Inconsolata-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/fonts/Inconsolata-Black.ttf -------------------------------------------------------------------------------- /public/fonts/Inconsolata-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zemerik/ZemProfiles/HEAD/public/fonts/Inconsolata-Bold.ttf -------------------------------------------------------------------------------- /src/pages/api/happy-by-city.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from 'astro'; 2 | 3 | export const config = { 4 | runtime: 'edge', 5 | }; 6 | -------------------------------------------------------------------------------- /src/pages/api/reactions-by-slug.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from 'astro'; 2 | 3 | export const config = { 4 | runtime: 'edge', 5 | }; 6 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /ghosts/ 3 | Allow: /ghosts$ 4 | Allow: / 5 | 6 | Sitemap: https://zemprofiles.vercel.app/sitemap-index.xml -------------------------------------------------------------------------------- /src/utils/months.js: -------------------------------------------------------------------------------- 1 | const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 2 | 3 | export default months; 4 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | > To Report a Vulnerability, kindly email at [zemerikY@gmail.com](mailto:zemeriky@gmail.com) 6 | -------------------------------------------------------------------------------- /src/utils/colors.js: -------------------------------------------------------------------------------- 1 | const colors = ['teal', 'mauve', 'salmon', 'yellow', 'lime', 'blood', 'electric', 'pink', 'starfleet', 'fuchsia']; 2 | 3 | export default colors; 4 | -------------------------------------------------------------------------------- /src/utils/format-number.js: -------------------------------------------------------------------------------- 1 | export const formatNumber = (number) => { 2 | const formatter = new Intl.NumberFormat(); 3 | 4 | return formatter.format(number); 5 | }; 6 | -------------------------------------------------------------------------------- /src/pages/api/add-reaction.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from 'astro'; 2 | import { geolocation } from '@vercel/edge'; 3 | 4 | export const config = { 5 | runtime: 'edge', 6 | }; 7 | -------------------------------------------------------------------------------- /src/pages/api/page-view.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from 'astro'; 2 | import { geolocation } from '@vercel/edge'; 3 | 4 | export const config = { 5 | runtime: 'edge', 6 | }; 7 | -------------------------------------------------------------------------------- /src/components/aside.astro: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/utils/format-slug.js: -------------------------------------------------------------------------------- 1 | import slugify from 'slugify'; 2 | 3 | export const formatSlug = (string) => { 4 | return slugify(string.replace(/\./g, '-'), { 5 | lower: true, 6 | strict: true, 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/base", 3 | "compilerOptions": { 4 | "checkJs": false, 5 | "allowJs": true, 6 | "jsx": "react-jsx", 7 | "jsxImportSource": "@builder.io/qwik" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/content/profiles/harrysingh100.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | base: posts 3 | title: Harry Singh 4 | tags: [Python, Javascript, HTML] 5 | date: 2024-05-09 6 | author: Harry Singh 7 | featuredImage: https://avatars.githubusercontent.com/u/167010005?v=4 8 | --- 9 | 10 | I HACK -------------------------------------------------------------------------------- /src/components/video-player.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { src } = Astro.props; 3 | --- 4 | 5 | 9 | -------------------------------------------------------------------------------- /src/content/profiles/axorax.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | base: posts 3 | title: Axorax 4 | tags: [Javascript, Python, HTML, CSS, Typescript, Lua] 5 | date: 2024-08-18 6 | author: Axorax 7 | featuredImage: https://avatars.githubusercontent.com/u/78349410?v=4 8 | --- 9 | 10 | I like to do stuff... 😗 -------------------------------------------------------------------------------- /public/images/x-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/services/resize-image.ts: -------------------------------------------------------------------------------- 1 | // https://cloudinary.com/documentation/image_transformations 2 | // https://cloudinary.com/documentation/media_optimization 3 | export const resizeImage = (url, width, height): string => { 4 | const string = url.split(/upload(?=.)/); 5 | const newUrl = `${string[0]}upload/h_${height},w_${width}/q_100/f_auto${string[1]}`; 6 | return newUrl; 7 | }; 8 | -------------------------------------------------------------------------------- /src/utils/is-new-content.js: -------------------------------------------------------------------------------- 1 | const isNewContent = (inputDate) => { 2 | const currentDate = new Date(); 3 | const inputDateObj = new Date(inputDate); 4 | 5 | const timeDifference = currentDate - inputDateObj; 6 | 7 | const daysDifference = timeDifference / (1000 * 60 * 60 * 24); 8 | 9 | return daysDifference < 30; 10 | }; 11 | 12 | export default isNewContent; 13 | -------------------------------------------------------------------------------- /src/content/profiles/calllme-shadow.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | base: posts 3 | title: Shadow 4 | tags: [Python, Javascript, Html, Css, GFX Designer] 5 | date: 2024-05-08 6 | author: Shadow 7 | featuredImage: https://avatars.githubusercontent.com/u/166983377?v=4 8 | --- 9 | 10 | Hey, it is Shadow I'm a GFX Designer and a Python & JavaScript Developer. I like to Watch Anime and Do some GFX Projects for free -------------------------------------------------------------------------------- /src/components/powered-by-mdx.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { period, className } = Astro.props; 3 | --- 4 | 5 |
6 | {period ? : null} 7 | Powered by{' '} 8 | MDX 9 |
10 | -------------------------------------------------------------------------------- /src/components/astro-image.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Image } from 'astro:assets'; 3 | import { resizeImage } from '../services/resize-image'; 4 | 5 | const { width, height, alt, url, className = 'w-full' } = Astro.props; 6 | --- 7 | 8 | {alt} 15 | -------------------------------------------------------------------------------- /src/content/profiles/sankitdev.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | base: posts 3 | title: Ankit Singh 4 | tags: [JavaScript, TypeScript, React, Node, Next Js] 5 | date: 2024-09-20 6 | author: sankitdev 7 | featuredImage: https://avatars.githubusercontent.com/u/56855070?v=4 8 | --- 9 | 10 | # Hi I am Ankit Singh 11 | 12 | ## I love building web apps with the MERN stack—React, Node.js, Express, and MongoDB. Coding is my playground, where I turn ideas into real, functional projects! 13 | -------------------------------------------------------------------------------- /src/utils/create-excerpt.js: -------------------------------------------------------------------------------- 1 | import MarkdownIt from 'markdown-it'; 2 | import sanitizeHtml from 'sanitize-html'; 3 | const parser = new MarkdownIt(); 4 | 5 | export const createExcerpt = (body) => { 6 | return sanitizeHtml( 7 | parser 8 | .render(body) 9 | .split('\n') 10 | .slice(0, 6) 11 | .map((str) => { 12 | return str.replace(/<\/?[^>]+(>|$)/g, '').split('\n'); 13 | }) 14 | .flat() 15 | .join(' ') 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /src/components/cta-internal.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { href, classNames = 'my-12 justify-center' } = Astro.props; 3 | --- 4 | 5 |
6 | 10 | 11 | 12 |
13 | -------------------------------------------------------------------------------- /src/utils/format-date.js: -------------------------------------------------------------------------------- 1 | import days from './days'; 2 | 3 | export const formatDate = (dateString, showTime = false) => { 4 | const date = new Date(dateString); 5 | 6 | const dateStamp = new Date(dateString).toLocaleString('en-US', { 7 | timeZone: 'UTC', 8 | day: 'numeric', 9 | month: 'long', 10 | weekday: 'long', 11 | year: 'numeric', 12 | }); 13 | const timeStamp = date.toLocaleTimeString(); 14 | 15 | return `${dateStamp} ${showTime ? `@${timeStamp}` : ''}`; 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/cta-external.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { href, className = 'my-24' } = Astro.props; 3 | --- 4 | 5 |
6 | 12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /src/utils/all-collections.js: -------------------------------------------------------------------------------- 1 | import { getCollection } from 'astro:content'; 2 | 3 | export const profiles = await getCollection('profiles'); 4 | 5 | export const collections = [...profiles]; 6 | 7 | export const search = collections 8 | .filter((item) => item.data.draft !== true) 9 | .map((data) => { 10 | const { 11 | slug, 12 | data: { base, title, date }, 13 | } = data; 14 | 15 | return { 16 | date: date, 17 | title: title, 18 | base: base, 19 | path: `/${base}/${slug}`, 20 | }; 21 | }) 22 | .sort((a, b) => b.date - a.date); 23 | -------------------------------------------------------------------------------- /src/components/code-sandbox.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { id } = Astro.props; 3 | --- 4 | 5 | 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /src/content/profiles/parthivkapoor0101.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | base: posts 3 | title: Parthiv Kapoor 4 | tags: [DSA, Python, Java] 5 | date: 2024-10-26 6 | author: parthivkapoor0101 7 | featuredImage: https://avatars.githubusercontent.com/u/182854493?v=4 8 | --- 9 | 10 | DSA expert specialising in machine learning with a B - Tech degree 11 | 12 | 13 | Hey, I am Parthiv, 14 | 15 | I recently completed my b-tech degree from Agra, India. I have a deep knowledge of data structures and backend languages like Python and Java. Feel free to contact me if you would like to hire me!! 16 | 17 | Thank you for reading. If you have any job ideas or suggestions, feel free to let me know! 18 | 19 | Regards, 20 | Parthiv Kapoor 21 | -------------------------------------------------------------------------------- /src/content/profiles/Developer-Utkarsh.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | base: posts 3 | title: Utkarsh Tiwari 4 | tags: [JavaScript, TypeScript, Python, MERN Stack,Next JS] 5 | date: 2024-09-02 6 | author: Developer-Utkarsh 7 | featuredImage: https://avatars.githubusercontent.com/u/128823414?s=400&u=84399792b7ad20c08d527467d9aea4f8ae561b44&v=4 8 | --- 9 | 10 | # Hi I'm Utkarsh Tiwari 11 | A passionate Full Stack developer from India | Skilled MERN Stack Developer | Crafting High-Quality, User-Friendly Web Apps | Passionate About AI Projects That Drive Impact 12 | 13 | 14 | #### Full Stack Web Developer | Skilled in MERN Stack | Passionate about Success & AI Projects 15 | 16 | Thank You For Viewing my profile 17 | 18 | # 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/utils/create-tags-collection.js: -------------------------------------------------------------------------------- 1 | import { formatSlug } from './format-slug'; 2 | 3 | export const createTagsCollection = (collections) => { 4 | return collections 5 | .map((collection) => { 6 | const tags = collection.data?.tags || []; 7 | 8 | return tags 9 | .map((tag) => { 10 | const slug = formatSlug(tag) || ''; 11 | return { 12 | name: tag || '', 13 | slug, 14 | }; 15 | }) 16 | .flat(); 17 | }) 18 | .flat() 19 | .filter((item, index, self) => { 20 | const { name } = item; 21 | return name && index === self.findIndex((obj) => obj.name === name); 22 | }) 23 | .sort((a, b) => a.name.localeCompare(b.name)); 24 | }; 25 | -------------------------------------------------------------------------------- /src/components/new-label.tsx: -------------------------------------------------------------------------------- 1 | import { component$, useSignal, useTask$ } from '@builder.io/qwik'; 2 | import isNewContent from '../utils/is-new-content'; 3 | 4 | interface Props { 5 | date: Date; 6 | } 7 | 8 | const NewLabel = component$(({ date }) => { 9 | const isNew = useSignal(false); 10 | 11 | useTask$(() => { 12 | isNew.value = isNewContent(date); 13 | }); 14 | 15 | return ( 16 |
17 |
18 | NEW 19 |
20 |
21 | ); 22 | }); 23 | 24 | export default NewLabel; 25 | -------------------------------------------------------------------------------- /src/components/list-top-ten-cities.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { data } = Astro.props; 3 | 4 | const listData = data.sort((a, b) => b.total - a.total).slice(0, 10); 5 | --- 6 | 7 |
    8 | { 9 | listData.map((item) => { 10 | const { flag, city, total } = item; 11 | 12 | return ( 13 |
  • 14 |
    15 | {flag} 16 | {city} 17 |
    18 | {`x${total}`} 19 |
  • 20 | ); 21 | }) 22 | } 23 |
24 | -------------------------------------------------------------------------------- /src/components/table-of-contents.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { headings } = Astro.props; 3 | --- 4 | 5 | { 6 | headings.length > 0 ? ( 7 |
8 |
on this page
9 |
    10 | {headings.map((heading) => { 11 | const { depth, slug, text } = heading; 12 | 13 | const getPaddingDepth = { 14 | [2]: '4', 15 | [3]: '6', 16 | [4]: '8', 17 | [5]: '10', 18 | [6]: '12', 19 | }; 20 | 21 | return ( 22 |
  • 23 | 24 | {text} 25 | 26 |
  • 27 | ); 28 | })} 29 |
30 |
31 | ) : null 32 | } 33 | -------------------------------------------------------------------------------- /src/components/list-popular.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { data } = Astro.props; 3 | --- 4 | 5 |
    6 | { 7 | data.map((item, index) => { 8 | const { slug, title, total } = item; 9 | 10 | return ( 11 |
  • 12 | 13 | {index + 1} 14 | 15 | 16 | 21 | {`x${total}`} 22 |
  • 23 | ); 24 | }) 25 | } 26 |
27 | -------------------------------------------------------------------------------- /src/pages/tags.astro: -------------------------------------------------------------------------------- 1 | --- 2 | export const prerender = true; 3 | 4 | import Main from '../layouts/main.astro'; 5 | import Aside from '../components/aside.astro'; 6 | import ProfileCard from '../components/profile-card.astro'; 7 | import SearchTags from '../components/search-tags'; 8 | 9 | import { createTagsCollection } from '../utils/create-tags-collection'; 10 | 11 | import { collections } from '../utils/all-collections'; 12 | 13 | const tags = createTagsCollection(collections); 14 | --- 15 | 16 |
17 | Tags 19 | {`x${tags.length}`} 20 | 21 |

Tags Search

22 | {tags ? : null} 23 | 26 |
27 | -------------------------------------------------------------------------------- /src/pages/profiles.astro: -------------------------------------------------------------------------------- 1 | --- 2 | export const prerender = true; 3 | 4 | import Main from '../layouts/main.astro'; 5 | import CollectionsList from '../components/collections-list.astro'; 6 | import Aside from '../components/aside.astro'; 7 | import ProfileCard from '../components/profile-card.astro'; 8 | 9 | 10 | import { profiles } from '../utils/all-collections'; 11 | 12 | 13 | --- 14 | 15 |
16 | Profiles 18 | {`x${profiles.length}`} 19 | 20 |

Users Profiles

21 |

22 | View some users profiles here, and feel free to explore further by reading their profile post. 23 |

24 | 25 | 28 |
29 | -------------------------------------------------------------------------------- /src/content/profiles/rohitshah09.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | base: posts 3 | title: Rohit Shah 4 | tags: [Javascript, Python, HTML] 5 | date: 2024-10-20 6 | author: rohitshah09 7 | featuredImage: https://avatars.githubusercontent.com/u/167185738?v=4 8 | --- 9 | 10 | Discord Bot Developer 11 | 12 | 13 | Hi, I am Rohit: 14 | 15 | I began my coding journey in year 7 with basic python code in pycharm. I expanded my coding skills by starting to learn HTMl - CSS - Javascript. I started to create different projects with different complexities using basic HTML. I continued practicing Python by making different projects such as face recognistion and voice recognition. 16 | 17 | Now I am learning more languages while continuing to work on my projects. I aim to learn more about open source and how to contribute to different projects through git and github. If you have any open source projects which I can contribute to, feel free to send them through my discord (vk_goat). 18 | 19 | Thanks for viewing my profile and reading about my journey! 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/style.yml: -------------------------------------------------------------------------------- 1 | 2 | name: 👯‍♂️ Style Changing Request 3 | description: Suggest a style designs 4 | title: '[style]: ' 5 | labels: ['enhancement'] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this template! 11 | - type: textarea 12 | id: style-idea 13 | attributes: 14 | label: What's the style idea? 15 | placeholder: Add descriptions 16 | value: 'We need to improve ' 17 | validations: 18 | required: true 19 | - type: textarea 20 | id: screenshots 21 | attributes: 22 | label: Add screenshots 23 | description: Add screenshots to see the demo 24 | placeholder: Add screenshots 25 | value: 'Add screenshots' 26 | - type: checkboxes 27 | id: terms 28 | attributes: 29 | label: Code of Conduct 30 | description: By submitting this issue, you agree to follow our Code of Conduct 31 | options: 32 | - label: I agree to follow this project's Code of Conduct 33 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## Fixes Issue 5 | 6 | 7 | 8 | 9 | 10 | ## Changes proposed 11 | 12 | 13 | 14 | 15 | 21 | 22 | ## Check List (Check all the applicable boxes) 23 | 24 | - [ ] My Changes follow the Code of Conduct of this Project. 25 | - [ ] My Post or Change does not contain any **Plagarized** Content. 26 | - [ ] The title of the PR is a short description of the Changes made. 27 | 28 | ## Note to reviewers 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/components/list-top-referrers.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { data } = Astro.props; 3 | 4 | const listData = data.sort((a, b) => b.total - a.total).slice(0, 10); 5 | --- 6 | 7 |
    8 | { 9 | listData.map((item, index) => { 10 | const { referrer, total } = item; 11 | 12 | return ( 13 |
  • 14 | 15 | {index + 1} 16 | 17 | 18 | 23 | 24 | {`x${total}`} 25 |
  • 26 | ); 27 | }) 28 | } 29 |
30 | -------------------------------------------------------------------------------- /src/components/tags-list.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { formatSlug } from '../utils/format-slug'; 3 | 4 | const { tags, className = 'mb-8', highlighted, link = false } = Astro.props; 5 | --- 6 | 7 |
    8 | { 9 | tags.map((tag) => { 10 | const isHighlighted = formatSlug(tag) === highlighted ? true : false; 11 | return ( 12 |
  • 15 | {link ? ( 16 | 20 | {tag} 21 | 22 | ) : ( 23 | {tag} 24 | )} 25 |
  • 26 | ); 27 | }) 28 | } 29 |
30 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Hemang Yadav 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/components/search-trigger.tsx: -------------------------------------------------------------------------------- 1 | import { component$ } from '@builder.io/qwik'; 2 | 3 | interface Props { 4 | handleModal: () => void; 5 | } 6 | 7 | const SearchTrigger = component$(({ handleModal }) => { 8 | return ( 9 | 28 | ); 29 | }); 30 | 31 | export default SearchTrigger; 32 | -------------------------------------------------------------------------------- /src/components/stackblitz-embed.tsx: -------------------------------------------------------------------------------- 1 | import { component$, useVisibleTask$ } from '@builder.io/qwik'; 2 | 3 | interface Props { 4 | id: string; 5 | file: string; 6 | view?: 'editor' | 'preview' | null; 7 | hideExplorer?: boolean; 8 | height?: number; 9 | theme?: 'dark' | 'light' | 'default' | null; 10 | clickToLoad?: boolean; 11 | } 12 | 13 | const StackBlitz = component$( 14 | ({ id, file, view = null, hideExplorer = false, height = 600, theme = 'dark', clickToLoad = false }) => { 15 | useVisibleTask$(async () => { 16 | const sdk = (await import('@stackblitz/sdk')).default; 17 | 18 | sdk.embedProjectId('stackblitz-embed', id, { 19 | forceEmbedLayout: true, 20 | openFile: file, 21 | view: view, 22 | hideExplorer: hideExplorer, 23 | hideNavigation: true, 24 | height: height, 25 | theme: theme, 26 | clickToLoad: clickToLoad, 27 | }); 28 | }); 29 | 30 | return ( 31 |
32 |
33 |
34 | ); 35 | } 36 | ); 37 | 38 | export default StackBlitz; 39 | -------------------------------------------------------------------------------- /src/components/featured-image-card.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import AstroImage from '../components/astro-image.astro'; 3 | 4 | const { alt, thumbnail, text } = Astro.props; 5 | --- 6 | 7 |
8 |
9 | 10 |
11 | 17 | 24 | Share on X 25 | 26 |
27 | -------------------------------------------------------------------------------- /src/components/search-input.tsx: -------------------------------------------------------------------------------- 1 | import { component$ } from '@builder.io/qwik'; 2 | 3 | interface Props { 4 | handleModal?: () => void; 5 | handleInput: (event: any) => void; 6 | showEsc?: boolean; 7 | } 8 | 9 | const SearchInput = component$(({ handleModal, handleInput, showEsc = false }) => { 10 | return ( 11 |
12 | 15 | 22 | {showEsc ? ( 23 | 31 | ) : null} 32 |
33 | ); 34 | }); 35 | 36 | export default SearchInput; 37 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Greetings 3 | 4 | on: 5 | pull_request: 6 | types: [opened] 7 | issues: 8 | types: [opened] 9 | 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | 14 | jobs: 15 | greet: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Greet on PRs and Issues 19 | uses: actions/github-script@v7 20 | with: 21 | script: | 22 | try { 23 | const isPR = context.payload.pull_request !== undefined; 24 | const number = isPR ? context.payload.pull_request.number : context.payload.issue.number; 25 | const commentBody = isPR 26 | ? `Welcome, @${{ github.actor }}! Thanks for raising the issue!` 27 | : `Great job, @${{ github.actor }}! Thanks for creating the pull request`; 28 | 29 | await github.rest.issues.createComment({ 30 | owner: context.repo.owner, 31 | repo: context.repo.repo, 32 | issue_number: number, 33 | body: commentBody 34 | }); 35 | 36 | console.log('Comment successfully created.'); 37 | } catch (error) { 38 | console.error('Error creating comment:', error); 39 | // Do not mark the step as failed; continue with the workflow. 40 | } 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.yml: -------------------------------------------------------------------------------- 1 | 2 | name: 🔖 Documentation update 3 | description: Improve Documentation 4 | title: '[Docs]: ' 5 | labels: ['documentation'] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this documentation update template! 11 | - type: textarea 12 | id: improve-docs 13 | attributes: 14 | label: What's wrong with the current Documentation? 15 | description: What Issue are you facing? 16 | placeholder: Add descriptions 17 | value: 'Briefly Describe the Issue you are facing' 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: screenshots 22 | attributes: 23 | label: Add screenshots 24 | description: Add Screenshots if Possible 25 | placeholder: Add screenshots 26 | value: 'Add Screenshots here' 27 | - type: checkboxes 28 | id: self-grab 29 | attributes: 30 | label: Self - Grab 31 | description: By checking this box, you acknowledge that you can fix this Documentation Error 32 | options: 33 | - label: I would like to work on this issue 34 | id: terms 35 | attributes: 36 | label: Code of Conduct 37 | description: By submitting this issue, you agree to follow our Code of Conduct 38 | options: 39 | - label: I agree to follow this project's Code of Conduct 40 | -------------------------------------------------------------------------------- /src/components/nav-link.tsx: -------------------------------------------------------------------------------- 1 | import { component$ } from '@builder.io/qwik'; 2 | 3 | interface Props { 4 | title: string; 5 | icon: string; 6 | stroke: boolean; 7 | slug: string; 8 | isActive: boolean; 9 | newCount: number; 10 | } 11 | 12 | const NavLink = component$(({ title, icon, stroke, slug, isActive, newCount }) => { 13 | return ( 14 | 20 | 28 | 29 | 30 | {newCount ? ( 31 | 32 | {newCount} 33 | 34 | ) : null} 35 | {title} 36 | 37 | ); 38 | }); 39 | 40 | export default NavLink; 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | 2 | name: 🐞 Bug Report 3 | description: File a bug report 4 | title: '[Bug]: ' 5 | labels: ['bug'] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this bug report! 11 | - type: textarea 12 | id: what-happened 13 | attributes: 14 | label: What happened? 15 | description: Also tell us, what did you expect to happen? 16 | placeholder: Add descriptions 17 | value: 'Briefly Describe the bug you found' 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: screenshots 22 | attributes: 23 | label: Add screenshots 24 | description: Add screenshots to see the problems 25 | placeholder: Add screenshots 26 | value: 'Add screenshots' 27 | - type: dropdown 28 | id: browsers 29 | attributes: 30 | label: What browsers are you seeing the problem on? 31 | multiple: true 32 | options: 33 | - Firefox 34 | - Chrome 35 | - Safari 36 | - Microsoft Edge 37 | - Brave 38 | - Other 39 | - type: checkboxes 40 | id: self-grab 41 | attributes: 42 | label: Self - Grab 43 | description: By checking this box, you can fix this bug 44 | options: 45 | - label: I would like to work on this issue 46 | id: terms 47 | attributes: 48 | label: Code of Conduct 49 | description: By submitting this issue, you agree to follow our Code of Conduct 50 | options: 51 | - label: I agree to follow this project's Code of Conduct -------------------------------------------------------------------------------- /src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | export const prerender = true; 3 | 4 | import Main from '../layouts/main.astro'; 5 | 6 | import Aside from '../components/aside.astro'; 7 | import ProfileCard from '../components/profile-card.astro'; 8 | import CollectionsList from '../components/collections-list.astro'; 9 | import CtaInternal from '../components/cta-internal.astro'; 10 | 11 | import { profiles } from '../utils/all-collections'; 12 | --- 13 | 14 |
15 | DISCOVER & CONNECT WITH DEVELOPERS 16 |

ZemProfiles

17 |

18 | ZemProfiles stands as an open-source platform, providing users with the opportunity to connect seamlessly with fellow developers. 19 | This connectivity is fostered through the simple act of adding one's Profile to the platform, 20 | thus creating a digital hub where like-minded individuals can engage, collaborate, and 21 | share insights within the expansive realm of software development. With its user-friendly interface and inclusive community ethos, 22 | ZemProfiles serves as a dynamic space where connections are forged, ideas are exchanged, and innovation thrives. 23 |

24 | 25 | 26 |

Latest Profiles

27 |

Latest profiles published on ZemProfiles 👇

28 | 29 | {`See All ${profiles.length} Profiles`} 30 | 31 | 34 |
35 | -------------------------------------------------------------------------------- /src/components/loading.tsx: -------------------------------------------------------------------------------- 1 | import { component$ } from '@builder.io/qwik'; 2 | 3 | interface Props { 4 | classNames?: string; 5 | } 6 | 7 | const Loading = component$(({ classNames }) => { 8 | return ( 9 |
10 | 26 | Loading... 27 |
28 | ); 29 | }); 30 | 31 | export default Loading; 32 | -------------------------------------------------------------------------------- /src/components/click-to-copy-email.jsx: -------------------------------------------------------------------------------- 1 | import { component$, useSignal, $ } from '@builder.io/qwik'; 2 | 3 | const ClickToCopyEmail = component$(() => { 4 | const defaultMessage = 'Click to Copy'; 5 | 6 | const message = useSignal(defaultMessage); 7 | 8 | const handleClick = $(async (event) => { 9 | const text = event.target.innerHTML; 10 | 11 | try { 12 | await navigator.clipboard.writeText(text); 13 | message.value = 'Copied!'; 14 | } catch (error) { 15 | console.error('Failed to copy: ', error); 16 | } 17 | }); 18 | 19 | const handleMouseOut = $(() => { 20 | setTimeout(() => { 21 | message.value = defaultMessage; 22 | }, 200); 23 | }); 24 | 25 | return ( 26 |
27 | 34 | 39 | 40 | 43 | 44 | {message.value} 45 | 46 |
47 | ); 48 | }); 49 | 50 | export default ClickToCopyEmail; 51 | -------------------------------------------------------------------------------- /src/components/audio-feed-embed.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { audioFeedId } = Astro.props; 3 | import Loading from './loading'; 4 | --- 5 | 6 |
10 | 11 |
12 | 13 | 58 | -------------------------------------------------------------------------------- /src/components/search-tags.tsx: -------------------------------------------------------------------------------- 1 | import { component$, useSignal, $, useVisibleTask$ } from '@builder.io/qwik'; 2 | import SearchInput from './search-input'; 3 | 4 | interface tagProps { 5 | name: string; 6 | slug: string; 7 | } 8 | 9 | interface Props { 10 | tags: tagProps[]; 11 | } 12 | 13 | const SearchTags = component$(({ tags }) => { 14 | const all = tags; 15 | const filtered = useSignal(tags); 16 | 17 | const handleInput = $(async (event) => { 18 | const FuseModule = await import('fuse.js'); 19 | const Fuse = FuseModule.default; 20 | const { 21 | target: { value }, 22 | } = event; 23 | const fuse = new Fuse(all, { 24 | threshold: 0.5, 25 | keys: ['name'], 26 | }); 27 | const results = fuse.search(value).map((data: any) => { 28 | const { 29 | item: { name, slug }, 30 | } = data; 31 | return { 32 | name, 33 | slug, 34 | }; 35 | }); 36 | if (value) { 37 | filtered.value = results; 38 | } else { 39 | filtered.value = all; 40 | } 41 | }); 42 | 43 | useVisibleTask$(() => { 44 | document.getElementById('input').focus(); 45 | }); 46 | 47 | return ( 48 |
49 | 50 |
    51 | {filtered.value.map((item) => { 52 | const { name, slug } = item; 53 | return ( 54 |
  • 55 | 59 | {name} 60 | 61 |
  • 62 | ); 63 | })} 64 |
65 |
66 | ); 67 | }); 68 | 69 | export default SearchTags; 70 | -------------------------------------------------------------------------------- /src/pages/tags/[...tag].astro: -------------------------------------------------------------------------------- 1 | --- 2 | export const prerender = true; 3 | 4 | import Main from '../../layouts/main.astro'; 5 | import Aside from '../../components/aside.astro'; 6 | import ProfileCard from '../../components/profile-card.astro'; 7 | import CollectionsList from '../../components/collections-list.astro'; 8 | 9 | import { collections } from '../../utils/all-collections'; 10 | import { createTagsCollection } from '../../utils/create-tags-collection'; 11 | 12 | interface Props { 13 | name: string; 14 | collection: { data: { tags: string[] } }[]; 15 | } 16 | 17 | export async function getStaticPaths() { 18 | const tags = createTagsCollection(collections); 19 | 20 | return tags.map((tag: { name: string; slug: string }) => { 21 | const { name, slug } = tag; 22 | 23 | return { 24 | params: { 25 | tag: slug, 26 | }, 27 | props: { 28 | name: name, 29 | collection: collections.filter((item) => item.data.tags.includes(name)), 30 | }, 31 | }; 32 | }); 33 | } 34 | 35 | const { tag } = Astro.params; 36 | const site = Astro.site.href; 37 | 38 | const { name, collection } = Astro.props; 39 | 40 | const ogImage = `${site}/tags/${tag}/og.png`; 41 | --- 42 | 43 |
44 | {name} 46 | {`x${collection.length}`} 47 | 48 |

{`${name} Developers`}

49 |

50 | Here you'll find {collection.length} 51 | {collection.length > 1 ? 'developers' : 'developer'} who {collection.length > 1 ? 'are' : 'is'} familiar with 52 | {name}. 53 |

54 | 55 | 58 |
59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zemprofiles", 3 | "version": "1.0.0", 4 | "description": "Discover & Connect with Developers", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "astro dev", 8 | "start": "astro dev", 9 | "build": "astro build", 10 | "preview": "astro preview", 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/Zemerik/ZemProfiles.git" 16 | }, 17 | "keywords": [], 18 | "author": "", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/Zemerik/ZemProfiles/issues" 22 | }, 23 | "homepage": "https://zemprofiles.vercel.app", 24 | "dependencies": { 25 | "@astrojs/mdx": "^4.3.10", 26 | "@astrojs/partytown": "^2.1.0", 27 | "@astrojs/rss": "^4.0.5", 28 | "@astrojs/sitemap": "^3.1.6", 29 | "@astrojs/tailwind": "^5.1.5", 30 | "@astrojs/vercel": "^9.0.0", 31 | "@builder.io/qwik": "^1.9.0", 32 | "@fontsource/inconsolata": "^5.0.8", 33 | "@google-analytics/data": "^4.7.0", 34 | "@neondatabase/serverless": "^0.6.0", 35 | "@qwikdev/astro": "^0.5.2", 36 | "@stackblitz/sdk": "^1.9.0", 37 | "@vercel/edge": "^1.1.0", 38 | "astro": "^5.15.9", 39 | "astro-auto-import": "^0.4.5", 40 | "astro-embed": "^0.7.4", 41 | "dotenv": "^16.4.5", 42 | "fuse.js": "^7.0.0", 43 | "globe.gl": "^2.32.4", 44 | "markdown-it": "^14.1.0", 45 | "mdx": "^0.3.1", 46 | "octokit": "^4.1.1", 47 | "og-img": "^0.2.1", 48 | "rehype-autolink-headings": "^7.1.0", 49 | "rehype-external-links": "^3.0.0", 50 | "rehype-slug": "^6.0.0", 51 | "sanitize-html": "^2.13.0", 52 | "slugify": "^1.6.6", 53 | "tailwindcss": "^3.4.1", 54 | "three": "0.161.0", 55 | "typescript": "^5.3.2", 56 | "zemprofilees": "file:", 57 | "zemprofiles": "file:" 58 | }, 59 | "devDependencies": { 60 | "@tailwindcss/typography": "^0.5.10", 61 | "@types/markdown-it": "^13.0.1" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/pages/posts/[...slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | export const prerender = true; 3 | 4 | import Main from '../../layouts/main.astro'; 5 | import Aside from '../../components/aside.astro'; 6 | import TagsList from '../../components/tags-list.astro'; 7 | import FeaturedImageCard from '../../components/featured-image-card.astro'; 8 | import TableOfContents from '../../components/table-of-contents.astro'; 9 | 10 | import { formatDate } from '../../utils/format-date'; 11 | import { createExcerpt } from '../../utils/create-excerpt'; 12 | 13 | import { profiles } from '../../utils/all-collections'; 14 | 15 | export async function getStaticPaths() { 16 | return profiles.map((post) => { 17 | return { 18 | params: { 19 | slug: post.slug, 20 | }, 21 | props: { 22 | post, 23 | }, 24 | }; 25 | }); 26 | } 27 | 28 | const { 29 | post, 30 | post: { 31 | slug, 32 | data: { title, author, date, tags, featuredImage, draft }, 33 | }, 34 | } = Astro.props; 35 | 36 | const excerpt = `${createExcerpt(post.body).substring(0, 70)}...`; 37 | 38 | const { Content, headings } = await post.render(); 39 | --- 40 | 41 |
42 | { 43 | draft ? ( 44 |

45 | Status: Unpublished 46 |

47 | ) : null 48 | } 49 |
50 | 51 | {`By ${author}`} 52 |
53 |

{title}

54 | 55 | 56 | 60 |
61 | -------------------------------------------------------------------------------- /src/content/config.js: -------------------------------------------------------------------------------- 1 | import { z, defineCollection } from 'astro:content'; 2 | 3 | export const collections = { 4 | posts: defineCollection({ 5 | type: 'content', 6 | schema: z.object({ 7 | draft: z.boolean().optional(), 8 | audioFeedId: z.string().optional(), 9 | base: z.string(), 10 | title: z.string(), 11 | tags: z.array(z.string()).optional(), 12 | date: z.date(), 13 | author: z.string(), 14 | featuredImage: z.string(), 15 | }), 16 | }), 17 | articles: defineCollection({ 18 | type: 'content', 19 | schema: z.object({ 20 | audioFeedId: z.string().optional(), 21 | base: z.string(), 22 | title: z.string(), 23 | tags: z.array(z.string()).optional(), 24 | date: z.date(), 25 | url: z.string(), 26 | publication: z.string(), 27 | author: z.string(), 28 | logo: z.string(), 29 | featuredImage: z.string().optional(), 30 | }), 31 | }), 32 | streams: defineCollection({ 33 | type: 'content', 34 | schema: z.object({ 35 | base: z.string(), 36 | title: z.string(), 37 | tags: z.array(z.string()).optional(), 38 | date: z.date(), 39 | url: z.string(), 40 | show: z.string(), 41 | role: z.string(), 42 | logo: z.string(), 43 | }), 44 | }), 45 | demos: defineCollection({ 46 | type: 'content', 47 | schema: z.object({ 48 | base: z.string(), 49 | title: z.string(), 50 | tags: z.array(z.string()).optional(), 51 | date: z.date(), 52 | author: z.string(), 53 | featuredImage: z.string(), 54 | }), 55 | }), 56 | opensource: defineCollection({ 57 | type: 'content', 58 | schema: z.object({ 59 | base: z.string(), 60 | title: z.string(), 61 | tags: z.array(z.string()).optional(), 62 | date: z.date(), 63 | author: z.string(), 64 | featuredImage: z.string(), 65 | }), 66 | }), 67 | ghosts: defineCollection({ 68 | type: 'content', 69 | schema: z.object({ 70 | base: z.string(), 71 | title: z.string(), 72 | tags: z.array(z.string()).optional(), 73 | date: z.date(), 74 | url: z.string(), 75 | publication: z.string(), 76 | author: z.string(), 77 | logo: z.string(), 78 | }), 79 | }), 80 | }; 81 | -------------------------------------------------------------------------------- /astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig, passthroughImageService } from 'astro/config'; 2 | import tailwind from '@astrojs/tailwind'; 3 | import mdx from '@astrojs/mdx'; 4 | import AutoImport from 'astro-auto-import'; 5 | import vercel from '@astrojs/vercel/serverless'; 6 | import qwikdev from '@qwikdev/astro'; 7 | import rehypeSlug from 'rehype-slug'; 8 | import rehypeAutolinkHeadings from 'rehype-autolink-headings'; 9 | import rehypeExternalLinks from 'rehype-external-links'; 10 | import partytown from '@astrojs/partytown'; 11 | import sitemap from '@astrojs/sitemap'; 12 | const isProd = import.meta.env.PROD; 13 | 14 | // https://astro.build/config 15 | export default defineConfig({ 16 | site: isProd ? 'https://zemprofiles.vercel.app' : 'http://localhost:4321', 17 | output: 'server', 18 | adapter: vercel({ 19 | edgeMiddleware: true, 20 | }), 21 | image: { 22 | domains: ['res.cloudinary.com'], 23 | service: passthroughImageService(), 24 | }, 25 | integrations: [ 26 | tailwind(), 27 | qwikdev(), 28 | AutoImport({ 29 | imports: [ 30 | { 31 | './src/components/cta-external.astro': [['default', 'CtaExternal']], 32 | }, 33 | { 34 | './src/components/code-sandbox.astro': [['default', 'CodeSandbox']], 35 | }, 36 | { 37 | './src/components/astro-image.astro': [['default', 'AstroImage']], 38 | }, 39 | { 40 | './src/components/video-player.astro': [['default', 'VideoPlayer']], 41 | }, 42 | { 43 | './src/components/stackblitz-embed.tsx': [['default', 'StackBlitz']], 44 | }, 45 | { 46 | 'astro-embed': ['Tweet', 'Vimeo', 'YouTube'], 47 | }, 48 | { 49 | 'astro:assets': ['Image'], 50 | }, 51 | ], 52 | }), 53 | mdx({ 54 | syntaxHighlight: 'prism', 55 | rehypePlugins: [ 56 | rehypeSlug, 57 | [ 58 | rehypeAutolinkHeadings, 59 | { 60 | behavior: 'wrap', 61 | }, 62 | ], 63 | [ 64 | rehypeExternalLinks, 65 | { 66 | rel: ['nofollow'], 67 | target: ['_blank'], 68 | }, 69 | ], 70 | ], 71 | }), 72 | partytown({ 73 | config: { 74 | forward: ['dataLayer.push'], 75 | }, 76 | }), 77 | sitemap(), 78 | ], 79 | vite: { 80 | build: { 81 | chunkSizeWarningLimit: 10000, 82 | }, 83 | }, 84 | }); 85 | -------------------------------------------------------------------------------- /src/components/line-chart-visits.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { data } = Astro.props; 3 | 4 | const chartData = data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); 5 | 6 | const chartWidth = 600; 7 | const chartHeight = 300; 8 | const offsetY = 40; 9 | const offsetX = 10; 10 | const paddingX = 40; 11 | const paddingY = 50; 12 | 13 | const maxY = data ? Math.max(...data.map((item) => item.total)) : null; 14 | const guides = [...Array(8).keys()]; 15 | 16 | const properties = chartData.map((property, index) => { 17 | const { day, month, total } = property; 18 | const ratio = (index / chartData.length) * (chartWidth - offsetX * 2); 19 | const x = ratio + paddingX / 2; 20 | const y = chartHeight - offsetY - (total / maxY) * (chartHeight - (paddingY + offsetY)) - paddingY + offsetY; 21 | return { 22 | total: total, 23 | date: `${month}•${day}`, 24 | x: x, 25 | y: y, 26 | }; 27 | }); 28 | 29 | const points = properties 30 | .map((point) => { 31 | const { x, y } = point; 32 | return `${x},${y}`; 33 | }) 34 | .toString(); 35 | --- 36 | 37 |
38 | 39 | { 40 | guides.map((_, index) => { 41 | const ratio = index / guides.length; 42 | const y = chartHeight - paddingY - chartHeight * ratio; 43 | 44 | return ( 45 | 51 | ); 52 | }) 53 | } 54 | 55 | 56 | 57 | { 58 | properties.map((property) => { 59 | const { total, date, x, y } = property; 60 | return ( 61 | 62 | 63 | 64 | {`x${total}`} 65 | 66 | 71 | {date} 72 | 73 | 74 | ); 75 | }) 76 | } 77 | 78 |
79 | -------------------------------------------------------------------------------- /src/content/profiles/zemerik.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | base: posts 3 | title: Hemang Yadav 4 | tags: [Typescript, Javascript, Astro, Python, HTML, CSS, NodeJS, ReactJS, NextJS, MongoDB, Open-Source, Content Creator] 5 | date: 2024-05-06 6 | author: Hemang Yadav 7 | featuredImage: https://avatars.githubusercontent.com/u/133865660?v=4 8 | --- 9 | 10 | 11 | 💻Passionate Developer + 💪Expertise in Web-Development + 🎓Open-Source Enthusiast + 🏆Content Creator 12 | 13 | 14 | ## About Me: 15 | 16 | As a 15-year-old high school student, I am driven by an unwavering passion for pursuing a career as a front-end software developer. 17 | With a knack for transforming concepts into tangible realities, I possess a strong command of Frontend / Backend development, along with different API's 18 | enabling me to bring ideas to life through coding expertise. 19 | 20 | - Learn more about me through my [Terminal](https://zemeriksterminal.vercel.app) 21 | 22 |

23 | 24 | Image 25 | 26 |

27 | 28 | ## How I Started? 29 | 30 | I began my coding journey with JavaScript, creating a simple "hello Zemerik" output. I initially focused on building Discord bots using Node.js, which sparked an interest in web development. This led me to explore and master various frameworks and technologies within the field. 31 | 32 | - Learn more about my Journey on [LinkedIn](https://linkedin.com/in/zemerik) 33 | 34 | ## Projects: 35 | 36 | - ZemPosts: Post & Connect with Developers 37 | - https://zemposts.vercel.app 38 | - https://github.com/Zemerik/ZemPosts 39 | 40 | - ZemShowcase: Showcase & Connect with Developers 41 | - https://zemshowcase.vercel.app 42 | - https://github.com/Zemerik/ZemShowcase 43 | 44 | ## Blogging: 45 | 46 | I often write blogs on my [Personal Blog Site](https://zemerik.hashnode.dev) and [DevTo](https://dev.to/Zemerik) sharing my coding journey, to connect with other developers around the globe. 47 | 48 | ## Youtube Jorney: 49 | 50 | Other than Hashnode, DevTo, and X (Twitter), I utilize my [Youtube Channel](https://www.youtube.com/@Zemerik) as a marketing tool for my projects. In my videos, I explore different projects and try to provide some feedback for the developers to enhnace their projects. 51 | 52 | > - You can submit your Open - Source Project to be reviewed by me through my socials! 53 | 54 | ## Want to Connect? 55 | 56 | Feel free to reach out to me through my socials below 57 | 58 | - [Instagram](https://instagram.com/Zemerik_Insta) 59 | - [X (Twitter)](https://x.com/Zemerik_X) 60 | - [Discord](https://discordapp.com/users/1018816958587748383) 61 | - [Email](mailto:ZemerikY@gmail.com) 62 | 63 | ## Thanks for Visiting 64 | -------------------------------------------------------------------------------- /public/prism-dracula.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Dracula Theme originally by Zeno Rocha [@zenorocha] 3 | * https://draculatheme.com/ 4 | * 5 | * Ported for PrismJS by Albert Vallverdu [@byverdu] 6 | */ 7 | 8 | code[class*='language-'], 9 | pre[class*='language-'] { 10 | color: #f8f8f2; 11 | background: none; 12 | text-shadow: 0 1px rgba(21, 34, 212, 0.3); 13 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 14 | text-align: left; 15 | white-space: pre; 16 | word-spacing: normal; 17 | word-break: normal; 18 | word-wrap: normal; 19 | line-height: 1.5; 20 | -moz-tab-size: 4; 21 | -o-tab-size: 4; 22 | tab-size: 4; 23 | -webkit-hyphens: none; 24 | -moz-hyphens: none; 25 | -ms-hyphens: none; 26 | hyphens: none; 27 | } 28 | 29 | /* Code blocks */ 30 | pre[class*='language-'] { 31 | padding: 1em; 32 | margin: 0.5em 0; 33 | overflow: auto; 34 | border-radius: 0.3em; 35 | } 36 | 37 | :not(pre) > code[class*='language-'], 38 | pre[class*='language-'] { 39 | background: #1c0cca; 40 | border: 1px solid #232140; 41 | } 42 | 43 | /* Inline code */ 44 | :not(pre) > code[class*='language-'] { 45 | padding: 0.1em; 46 | border-radius: 0.3em; 47 | white-space: normal; 48 | } 49 | 50 | .token.comment, 51 | .token.prolog, 52 | .token.doctype, 53 | .token.cdata { 54 | color: #1746d4; 55 | } 56 | 57 | .token.punctuation { 58 | color: #f8f8f2; 59 | } 60 | 61 | .namespace { 62 | opacity: 0.7; 63 | } 64 | 65 | .token.property, 66 | .token.tag, 67 | .token.constant, 68 | .token.symbol, 69 | .token.deleted { 70 | color: #1fcfc7; 71 | } 72 | 73 | .token.boolean, 74 | .token.number { 75 | color: #2614c4; 76 | } 77 | 78 | .token.selector, 79 | .token.attr-name, 80 | .token.string, 81 | .token.char, 82 | .token.builtin, 83 | .token.inserted { 84 | color: #50fa7b; 85 | } 86 | 87 | .token.operator, 88 | .token.entity, 89 | .token.url, 90 | .language-css .token.string, 91 | .style .token.string, 92 | .token.variable { 93 | color: #f8f8f2; 94 | } 95 | 96 | .token.atrule, 97 | .token.attr-value, 98 | .token.function, 99 | .token.class-name { 100 | color: #f1fa8c; 101 | } 102 | 103 | .token.keyword { 104 | color: #8be9fd; 105 | } 106 | 107 | .token.regex, 108 | .token.important { 109 | color: #ffb86c; 110 | } 111 | 112 | .token.important, 113 | .token.bold { 114 | font-weight: bold; 115 | } 116 | 117 | .token.italic { 118 | font-style: italic; 119 | } 120 | 121 | .token.entity { 122 | cursor: help; 123 | } 124 | 125 | /* Custom styles */ 126 | 127 | .token.inserted-sign.inserted > .token.line { 128 | color: #50fa7b; 129 | } 130 | 131 | .token.deleted-sign.deleted > .token.line { 132 | color: #fe3745; 133 | } 134 | .token.deleted-sign.deleted > .token.prefix.deleted { 135 | color: #fe3745; 136 | } 137 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Astro / Vercel build out 91 | .vercel 92 | 93 | # Nuxt.js build / generate output 94 | .nuxt 95 | dist 96 | 97 | # Gatsby files 98 | .cache/ 99 | # Comment in the public line in if your project uses Gatsby and not Next.js 100 | # https://nextjs.org/blog/next-9-1#public-directory-support 101 | # public 102 | 103 | # vuepress build output 104 | .vuepress/dist 105 | 106 | # vuepress v2.x temp and cache directory 107 | .temp 108 | .cache 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | 135 | #custom 136 | fauna 137 | src/pages/test.astro 138 | .tmp*/ 139 | tmp*/ 140 | db_backups -------------------------------------------------------------------------------- /src/layouts/nav-links.ts: -------------------------------------------------------------------------------- 1 | export const siteLinks = [ 2 | { 3 | title: 'Home', 4 | link: '/', 5 | icon: 'M12 5.432l8.159 8.159c.03.03.06.058.091.086v6.198c0 1.035-.84 1.875-1.875 1.875H15a.75.75 0 01-.75-.75v-4.5a.75.75 0 00-.75-.75h-3a.75.75 0 00-.75.75V21a.75.75 0 01-.75.75H5.625a1.875 1.875 0 01-1.875-1.875v-6.198a2.29 2.29 0 00.091-.086L12 5.43z', 6 | stroke: false, 7 | }, 8 | { 9 | title: 'Profiles', 10 | link: '/profiles/', 11 | icon: 'M5.566 4.657A4.505 4.505 0 016.75 4.5h10.5c.41 0 .806.055 1.183.157A3 3 0 0015.75 3h-7.5a3 3 0 00-2.684 1.657zM2.25 12a3 3 0 013-3h13.5a3 3 0 013 3v6a3 3 0 01-3 3H5.25a3 3 0 01-3-3v-6zM5.25 7.5c-.41 0-.806.055-1.184.157A3 3 0 016.75 6h10.5a3 3 0 012.683 1.657A4.505 4.505 0 0018.75 7.5H5.25z', 12 | stroke: false, 13 | }, 14 | { 15 | title: ' + Profile', 16 | link: 'https://github.com/Zemerik/ZemProfiles', 17 | icon: 'M21.731 2.269a2.625 2.625 0 00-3.712 0l-1.157 1.157 3.712 3.712 1.157-1.157a2.625 2.625 0 000-3.712zM19.513 8.199l-3.712-3.712-12.15 12.15a5.25 5.25 0 00-1.32 2.214l-.8 2.685a.75.75 0 00.933.933l2.685-.8a5.25 5.25 0 002.214-1.32L19.513 8.2z', 18 | stroke: false, 19 | }, 20 | ]; 21 | 22 | export const socialLinks = [ 23 | { 24 | url: 'https://x.com/Zemerik_X', 25 | title: 'Twitter/X', 26 | icon: 'M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z', 27 | stroke: false, 28 | rel: 'me', 29 | }, 30 | { 31 | url: 'https://github.com/Zemerik', 32 | title: 'GitHub', 33 | icon: 'M11.88,0.6C5.5,0.6,0.3,5.8,0.3,12.18c0,5.44,3.78,10.05,8.86,11.23c0-0.12-0.12-0.35-0.12-0.59V20.8c-0.47,0-1.3,0-1.42,0c-0.83,0-1.54-0.35-1.89-0.95c-0.35-0.71-0.47-1.77-1.42-2.48C4.08,17.14,4.2,16.9,4.55,16.9c0.59,0.12,1.06,0.59,1.54,1.18c0.47,0.59,0.71,0.71,1.54,0.71c0.47,0,1.06,0,1.65-0.12c0.35-0.83,0.83-1.54,1.54-1.89c-3.9-0.35-5.67-2.36-5.67-4.96c0-1.18,0.47-2.25,1.3-3.19c-0.35-0.59-0.71-2.48,0-3.19c1.77,0,2.84,1.18,3.07,1.42c0.83-0.35,1.77-0.47,2.84-0.47s2.01,0.12,2.84,0.47c0.24-0.35,1.3-1.42,3.07-1.42c0.71,0.71,0.35,2.6,0.12,3.55c0.83,0.95,1.3,2.01,1.3,3.07c0,2.6-1.89,4.49-5.67,4.96c1.06,0.59,1.89,2.13,1.89,3.31v2.6c0,0.12,0,0.12,0,0.24c4.49-1.54,7.8-5.91,7.8-10.99C23.46,5.8,18.26,0.6,11.88,0.6z', 34 | stroke: false, 35 | rel: 'me', 36 | }, 37 | { 38 | url: 'https://linkedin.com/in/Zemerik', 39 | title: 'LinkedIn', 40 | icon: 'M21.4,0.64H2.72c-1.14,0-2.02,0.88-2.02,2.02v18.55c0,1.26,0.88,2.15,2.02,2.15h18.55c1.14,0,2.02-0.88,2.02-2.02V2.66C23.42,1.52,22.53,0.64,21.4,0.64z M7.89,19.19H4.86V9.48h3.03C7.89,9.48,7.89,19.19,7.89,19.19z M6.38,8.09c-1.01,0-1.77-0.76-1.77-1.77s0.76-1.89,1.77-1.89s1.77,0.76,1.77,1.77S7.26,8.09,6.38,8.09z M19.25,19.19h-3.03v-4.67c0-1.14,0-2.65-1.64-2.65s-1.77,1.26-1.77,2.52v4.8H9.79V9.48h2.9v1.26l0,0c0.38-0.76,1.39-1.64,2.9-1.64c3.03,0,3.66,2.02,3.66,4.67C19.25,13.89,19.25,19.19,19.25,19.19z', 41 | stroke: false, 42 | rel: '', 43 | }, 44 | ]; 45 | -------------------------------------------------------------------------------- /src/components/donut-chart-tags.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { data, dataLength } = Astro.props; 3 | 4 | import colors from '../utils/colors'; 5 | import { formatSlug } from '../utils/format-slug'; 6 | 7 | const chartSize = 100; 8 | const chartData = data.sort((a, b) => b.total - a.total).slice(0, 5); 9 | const max = chartData.reduce((a, b) => a + b.total, 0); 10 | 11 | const convertToPercent = (num) => Math.round((num / max) * 100); 12 | const convertToDegrees = (num) => Math.round((num / 100) * 360); 13 | 14 | const gradient = chartData 15 | .reduce((items, item, index, array) => { 16 | items.push(item); 17 | 18 | item.count = item.count || 0; 19 | item.count += array[index - 1]?.count || item.count; 20 | item.start_value = array[index - 1]?.count ? array[index - 1].count : 0; 21 | item.end_value = item.count += item.total; 22 | item.start_percent = convertToPercent(item.start_value); 23 | item.end_percent = convertToPercent(item.end_value); 24 | item.start_degrees = convertToDegrees(item.start_percent); 25 | item.end_degrees = convertToDegrees(item.end_percent); 26 | 27 | return items; 28 | }, []) 29 | .map((chart, index) => { 30 | const { start_degrees, end_degrees } = chart; 31 | return ` var(--color-brand-${colors[index]}) ${start_degrees}deg ${end_degrees}deg`; 32 | }) 33 | .join(); 34 | --- 35 | 36 |
37 |
38 | 39 | 40 | 41 | 42 | Tags Analytics 43 | {`Displaying ${chartData.length} of ${dataLength}`} 46 | 47 |
53 |
54 |
55 |
56 |
57 |
    58 | { 59 | chartData.map((item, index) => { 60 | const { tag, total } = item; 61 | 62 | return ( 63 |
  • 64 | 65 |
    66 | {tag} 67 | 68 | {`x${total}`} 69 |
  • 70 | ); 71 | }) 72 | } 73 |
74 |
75 | -------------------------------------------------------------------------------- /src/pages/tags/[tag]/og.png.ts: -------------------------------------------------------------------------------- 1 | export const prerender = true; 2 | 3 | import { ImageResponse, html } from 'og-img'; 4 | import fs from 'fs'; 5 | import path from 'path'; 6 | 7 | import { collections } from '../../../utils/all-collections'; 8 | import { createTagsCollection } from '../../../utils/create-tags-collection'; 9 | 10 | export async function GET({ props }) { 11 | const { name, collection } = props; 12 | 13 | return new ImageResponse( 14 | html`
15 |
16 |
17 |
18 |
19 |
${name}
20 |
21 |
22 | Tagged with ${name} 23 |
24 |
25 | Here you'll find ${collection.length} all developers 26 | about ${name}. 27 |
28 |
29 |
ZemProfiles
30 |
|
31 |
32 | ${`zemprofiles.vercel.app/tags/${name}`} 33 |
34 |
35 |
36 |
`, 37 | { 38 | width: 1200, 39 | height: 600, 40 | fonts: [ 41 | { 42 | name: 'Roboto Regular', 43 | data: fs.readFileSync(path.resolve('./public/fonts/Roboto-Regular.ttf')), 44 | weight: 400, 45 | style: 'normal', 46 | }, 47 | { 48 | name: 'Inconsolata Bold', 49 | data: fs.readFileSync(path.resolve('./public/fonts/Inconsolata-Bold.ttf')), 50 | weight: 600, 51 | style: 'normal', 52 | }, 53 | { 54 | name: 'Inconsolata Black', 55 | data: fs.readFileSync(path.resolve('./public/fonts/Inconsolata-Black.ttf')), 56 | weight: 900, 57 | style: 'normal', 58 | }, 59 | ], 60 | } 61 | ); 62 | } 63 | 64 | export async function getStaticPaths() { 65 | const tags = createTagsCollection(collections); 66 | 67 | return tags.map((tag: { name: string; slug: string }) => { 68 | const { name, slug } = tag; 69 | 70 | return { 71 | params: { 72 | tag: slug, 73 | }, 74 | props: { 75 | name: name, 76 | collection: collections.filter((item) => item.data.tags.includes(name)), 77 | }, 78 | }; 79 | }); 80 | } 81 | -------------------------------------------------------------------------------- /src/components/profile-card.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Image } from 'astro:assets'; 3 | import ClickToCopyEmail from './click-to-copy-email'; 4 | 5 | const locations = [ 6 | // { 7 | // name: 'United Kingdom', 8 | // flag: '🇬🇧', 9 | // current: true, 10 | // }, 11 | // { 12 | // name: 'Panama City, Panama', 13 | // flag: '🇵🇦', 14 | // current: true, 15 | // }, 16 | // { 17 | // name: 'Medellín, Colombia', 18 | // flag: '🇨🇴', 19 | // current: false, 20 | // }, 21 | // { 22 | // name: 'Los Angeles, USA', 23 | // flag: '🇺🇲', 24 | // current: false, 25 | // }, 26 | // { 27 | // name: 'New Orleans, USA', 28 | // flag: '🇺🇲', 29 | // current: false, 30 | // }, 31 | // { 32 | // name: 'Montreal, Canada', 33 | // flag: '🇨🇦', 34 | // current: false, 35 | // }, 36 | // { 37 | // name: 'Toronto, Canada', 38 | // flag: '🇨🇦', 39 | // current: false, 40 | // }, 41 | ]; 42 | --- 43 | 44 |
45 | Hemang Yadav 52 |
53 |

54 | 55 | HEMANG YADAV 56 | 57 |

58 |
FOUNDER + MAINTAINER
59 |

60 |

💻Passionate Developer + 💪Expertise in Web-Development + 🎓Open-Source Enthusiast + 🏆Content Creator

61 |

62 | 80 | 81 |
82 |
83 | 89 | 96 | Zemerik_X 97 | 98 | 99 |
100 | -------------------------------------------------------------------------------- /src/components/collections-list.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Image } from 'astro:assets'; 3 | import AstroImage from './astro-image.astro'; 4 | 5 | import NewLabel from './new-label'; 6 | import TagsList from './tags-list.astro'; 7 | 8 | import { formatDate } from '../utils/format-date'; 9 | import { createExcerpt } from '../utils/create-excerpt'; 10 | 11 | const { collections, slice, highlighted } = Astro.props; 12 | --- 13 | 14 | 81 | -------------------------------------------------------------------------------- /src/components/happy-all-cities.tsx: -------------------------------------------------------------------------------- 1 | import { component$, useSignal, useVisibleTask$ } from '@builder.io/qwik'; 2 | import { formatNumber } from '../utils/format-number'; 3 | 4 | import Loading from './loading'; 5 | 6 | interface Props { 7 | period: number; 8 | } 9 | 10 | const HappyAllCities = component$(({ period }) => { 11 | const data = useSignal(null); 12 | 13 | useVisibleTask$(async () => { 14 | try { 15 | const response = await fetch('/api/happy-by-city', { 16 | method: 'POST', 17 | body: JSON.stringify({ period: period }), 18 | }); 19 | 20 | if (response.status !== 200) { 21 | throw new Error(); 22 | } 23 | 24 | const result = await response.json(); 25 | 26 | data.value = result.data; 27 | } catch (error) { 28 | console.error(error); 29 | } 30 | }); 31 | 32 | return ( 33 |
34 |
35 |
36 | {data.value ? ( 37 | <> 38 | {data.value.length ? ( 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | {data.value.map((row, index) => { 50 | const { city, country, flag, total } = row; 51 | return ( 52 | 53 | 65 | 66 | 70 | 71 | 72 | ); 73 | })} 74 | 75 |
CityCountryTotal
54 | 62 | 63 | {city} 64 | 67 | {flag} 68 | {country} 69 | {`x${formatNumber(total)}`}
76 |
77 | ) : ( 78 |
79 | No happy cities to display 80 |
81 | )} 82 | 83 | ) : ( 84 |
85 | 86 |
87 | )} 88 |
89 |
90 |
91 | ); 92 | }); 93 | 94 | export default HappyAllCities; 95 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |
6 | 7 |
8 | 9 | 10 | 11 |

12 | 13 |

14 | ZemProfiles 15 |

16 | 17 |

18 | Discover & Connect with Developers 19 |

20 | 21 |

22 | 23 |

24 | 25 | ## ➕ Adding your Profile: 26 | 27 | 1. Fork a copy of this Repository on your Github account by clicking below, 28 | 29 | - [Fork](https://github.com/Zemerik/ZemProfiles/fork) 30 | 31 | 2. Clone your Forked Repository by using the following `GIT` command: 32 | 33 | ```bash 34 | git clone https://github.com/[YOUR GITHUB USERNAME]/ZemProfiles.git 35 | ``` 36 | 37 | 3. Navigate into the Project's `Directory` by using the command below: 38 | 39 | ```bash 40 | cd ZemProfiles 41 | ``` 42 | 43 | 4. Initialize a Remote to the original Repository by the following `GIT` command: 44 | 45 | ```bash 46 | git remote add upstream https://github.com/Zemerik/ZemProfiles 47 | ``` 48 | 49 | 5. Create a new `branch` in which you can make your desired changes: 50 | 51 | ```bash 52 | git checkout -b newprofile 53 | ``` 54 | 55 | 6. Create a new file in the `src/content/profiles` directory and name it `[YOUR GITHUB USERNAME].mdx` 56 | 57 | ![Directory Screenshot](public/profile_directory.png) 58 | 59 | 7. After Creating the file, paste the code snippet below and enter **Your** Details: 60 | 61 | ```md 62 | --- 63 | base: posts 64 | title: Your Name 65 | tags: [Skill 1, Skill 2, Skill 3, ...] 66 | date: Today's Date 67 | author: Name / Github Username 68 | featuredImage: Image address of your Profile Picture 69 | --- 70 | 71 | Add a short description of yourself here 72 | 73 | 74 | Customize your Profile Post as you like using Markdown or HTML here. 75 | 76 | ``` 77 | 78 | > [!Tip] 79 | > You can refer to `zemerik.mdx` file for help or inspiration if required. 80 | 81 | ![Example Profile](public/zemerik_profile.png) 82 | 83 | 8. After you are happy with your Profile Post, add all your files to the Staging Area: 84 | 85 | ```bash 86 | git add --all 87 | ``` 88 | 89 | 9. Commit your Changes: 90 | 91 | ```bash 92 | git commit -m "Profile Addition: [Your Name]" 93 | ``` 94 | 95 | > [!Note] 96 | > Remember to have a good commit message! 97 | 98 | 10. Push all your Changes: 99 | 100 | ```bash 101 | git push origin newprofile 102 | ``` 103 | 104 | 11. Create a new Pull - Request on the Original Repository 105 | 106 | > Your Pull Request will be merged / reviewed as soon as possible 107 | 108 | - > Don't Forget to Check out [ZemShowcase](https://github.com/Zemerik/ZemShowcase) & [ZemPosts](https://github.com/Zemerik/ZemPosts) 109 | 110 | ## 🐞Bug/Issue/Feedback/Feature Request: 111 | 112 | - If you would like to report a bug, a issue, implement any feedack, or request any feature, you are free to do so by opening a issue on this repository. Remember to give a detailed explanation of what you are trying to say, and how it will help the website. 113 | 114 | ## 💁 Support: 115 | 116 | For any kind of support or inforrmation, you are free to join our **Discord Server**, 117 | 118 | 119 | 120 | 121 | 122 |

123 | Thanks for Visiting🙏 124 |

125 | 126 |

127 | Don't forget to leave a ⭐ 128 |
129 | Made with 💖 by Hemang Yadav (Zemerik) 130 |

131 | -------------------------------------------------------------------------------- /src/layouts/main.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from './layout'; 3 | import { search } from '../utils/all-collections'; 4 | 5 | import '@fontsource/inconsolata/300.css'; 6 | import '@fontsource/inconsolata/400.css'; 7 | import '@fontsource/inconsolata/500.css'; 8 | import '@fontsource/inconsolata/700.css'; 9 | import '@fontsource/inconsolata/900.css'; 10 | 11 | const name = 'ZemProfiles'; 12 | const siteUrl = 'https://zemprofiles.vercel.app'; 13 | const keywords = [ 14 | 'Developer Advocate', 15 | 'Technical Writing', 16 | 'Product Marketing' 17 | ]; 18 | 19 | const { type, title, description, slug, image, tags, fullWidth = false, canonical } = Astro.props; 20 | 21 | const htmlTitle = `${name} | ${title}`; 22 | const canonicalHref = canonical ? canonical : `${siteUrl}${slug}`; 23 | 24 | const ogImage = image ? image : `${siteUrl}`; 25 | const seoKeywords = tags ? tags : keywords; 26 | 27 | const isProduction = import.meta.env.PROD; 28 | --- 29 | 30 | 31 | 32 | 33 | 34 | 35 | {htmlTitle} 36 | 37 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | { 75 | isProduction ? ( 76 | 77 | 86 | ) : null 87 | } 88 | 89 | 90 | { 91 | isProduction ? ( 92 | 100 | ) : null 101 | } 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/components/search-modal.tsx: -------------------------------------------------------------------------------- 1 | import { component$, useSignal, $, useVisibleTask$ } from '@builder.io/qwik'; 2 | 3 | import SearchInput from './search-input'; 4 | 5 | import { formatDate } from '../utils/format-date'; 6 | 7 | interface searchProps { 8 | date: string; 9 | title: string; 10 | base: string; 11 | path: string; 12 | } 13 | 14 | interface Props { 15 | search: searchProps[]; 16 | isModalOpen: Boolean; 17 | handleModal: () => void; 18 | } 19 | 20 | const SearchModal = component$(({ search, isModalOpen, handleModal }) => { 21 | const all = useSignal(search); 22 | const filtered = useSignal(search); 23 | 24 | const handleBackdrop = $((event) => { 25 | if (event.target.localName === 'dialog') { 26 | handleModal(); 27 | } 28 | }); 29 | 30 | const handleInput = $(async (event) => { 31 | const FuseModule = await import('fuse.js'); 32 | const Fuse = FuseModule.default; 33 | 34 | const { 35 | target: { value }, 36 | } = event; 37 | 38 | const fuse = new Fuse(all.value, { 39 | threshold: 0.5, 40 | keys: ['title', 'date'], 41 | }); 42 | 43 | const results = fuse.search(value).map((data: any) => { 44 | const { 45 | item: { base, path, title, date }, 46 | } = data; 47 | 48 | return { 49 | title, 50 | date, 51 | path, 52 | base, 53 | }; 54 | }); 55 | 56 | if (value) { 57 | filtered.value = results; 58 | } else { 59 | filtered.value = all.value; 60 | } 61 | }); 62 | 63 | useVisibleTask$(({ track }) => { 64 | track(() => isModalOpen); 65 | if (isModalOpen) { 66 | document.getElementById('input').focus(); 67 | document.body.classList.add('overflow-hidden'); 68 | } else { 69 | document.body.classList.remove('overflow-hidden'); 70 | filtered.value = all.value; 71 | } 72 | }); 73 | 74 | return ( 75 | <> 76 | {isModalOpen ? ( 77 | 81 |
82 | 83 |
{`${ 84 | filtered.value.length > 0 ? filtered.value.length : 0 85 | } results`}
86 |
87 | 118 |
119 |
120 |
121 | ) : null} 122 | 123 | ); 124 | }); 125 | 126 | export default SearchModal; 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 | 6 |
7 | 8 |
9 | 10 | 11 | 12 |

13 | 14 |

15 | ZemProfiles 16 |

17 | 18 |

19 | Discover & Connect with Developers 20 |

21 | 22 |

23 | 24 |

25 | 26 | ## ❗About: 27 | 28 | ZemProfiles stands as an open-source platform, providing users with the opportunity to connect seamlessly with fellow developers. This connectivity is fostered through the simple act of adding one's Profile to the platform, thus creating a digital hub where like-minded individuals can engage, collaborate, and share insights within the expansive realm of software development. With its user-friendly interface and inclusive community ethos, ZemProfiles serves as a dynamic space where connections are forged, ideas are exchanged, and innovation thrives. 29 | 30 | - > Read out Official Docs on [ZemDocs](https://zemdocs.vercel.app/en/zemprofiles/introduction) 31 | 32 | ## 🎥 Youtube Video: 33 | 34 | - Feel free to watch our Youtube Video by clicking below 👇 35 | 36 |
37 | 38 | [![Introducing: ZemProfiles v2.0.1 || Github Review || Open Source](https://ytcards.demolab.com/?id=5XyGaH9f0wA&title=Introducing%3A+ZemProfiles+v2.0.1+%7C%7C+Github+Review+%7C%7C+Open+Source&lang=en×tamp=1724561946&background_color=%230d1117&title_color=%23ffffff&stats_color=%23dedede&max_title_lines=1&width=250&border_radius=5&duration=407 "Introducing: ZemProfiles v2.0.1 || Github Review || Open Source")](https://www.youtube.com/watch?v=5XyGaH9f0wA) 39 | 40 |
41 | 42 | 43 | ## ⭐ Features: 44 | 45 | - User Friendly UI/UX 46 | - Customizable Profile Post 47 | - Use markdown or html for styling 48 | - Search for Developers using Tags 49 | - List of all Developers 50 | - Profile Card for Maintainers 51 | 52 | Want to see any other features? Open an [issue](https://github.com/Zemerik/ZemProfiles/issues) and let us know! 53 | 54 | ## 💬 Fonts: 55 | 56 | - [x] Inconsolata-Black 57 | - [x] Inconsolata-Black 58 | - [x] Roboto-Regular 59 | 60 | ## 🏃‍♂️ Locally Running: 61 | 62 | - This project can be locally executed on your machine in 4 simple steps! 63 | 64 | > [!Tip] 65 | > [NodeJS](https://nodejs.org/) needs to be installed on your machine. 66 | 67 | 68 | 1. Make a `Copy` of this Repository on your machine by using the following `git command` in your terminal: 69 | 70 | ``` 71 | git clone https://github.com/Zemerik/ZemProfiles 72 | ``` 73 | 74 | 2. `Navigate` into the Project's `directory` by entering the following `command` in your terminal: 75 | 76 | ``` 77 | cd ZemProfiles 78 | ``` 79 | 80 | 3. `Install` the required `Dependencies` by using `NPM`: 81 | 82 | ```nodejs 83 | npm i 84 | ``` 85 | 86 | 4. Start the `Development Server` through the following `command`: 87 | 88 | ```nodejs 89 | npm run dev 90 | ``` 91 | 92 | ## 🚀 Project Structure 93 | 94 | ```text 95 | ├── public/ 96 | │   ├── fonts/ 97 | │   └── images/ 98 | ├── src/ 99 | │   ├── components/ 100 | │   ├── content/ 101 | │   ├── layouts/ 102 | │   └── pages/ 103 | │   └── services/ 104 | │   └── util/ 105 | ├── .gitignore 106 | ├── astro.config.mjs 107 | ├── CODE_OF_CONDUCT.md 108 | ├── CONTRIBUTING.md 109 | ├── LICENCE 110 | ├── package-lock.json 111 | ├── package.json 112 | ├── README.md 113 | ├── SECURITY.md 114 | ├── tailwind.config.cjs 115 | ├── yarn.lock 116 | └── tsconfig.json 117 | ``` 118 | 119 | ## 🤝 Contributing: 120 | 121 | Contributions are always welcome and appreciated! **Kindly visit the [CONTRIBUTING.md](https://github.com/Zemerik/ZemProfiles/blob/main/CONTRIBUTING.md) file for more information** 122 | 123 | 124 | ## 💁 Support: 125 | 126 | For any kind of support or inforrmation, you are free to join our **Discord Server**, 127 | 128 | 129 | 130 | 131 | 132 | ## 🥳 Contributers: 133 | 134 | Thanks to all Contributers! 135 | 136 | ![Contributers](https://contrib.rocks/image?repo=Zemerik/ZemProfiles) 137 | 138 |

139 | Thanks for Visiting🙏 140 |

141 | 142 |

143 | Don't forget to leave a ⭐ 144 |
145 | Made with 💖 by Hemang Yadav (Zemerik) 146 |

147 | -------------------------------------------------------------------------------- /src/pages/dashboard.astro: -------------------------------------------------------------------------------- 1 | --- 2 | export const prerender = false; 3 | 4 | import Main from '../layouts/main.astro'; 5 | 6 | import Aside from '../components/aside.astro'; 7 | import ProfileCard from '../components/profile-card.astro'; 8 | import ListPopular from '../components/list-popular.astro'; 9 | import DonutChartTags from '../components/donut-chart-tags.astro'; 10 | import PoweredByMdx from '../components/powered-by-mdx.astro'; 11 | import HappyAllCities from '../components/happy-all-cities'; 12 | 13 | let analyticsData = null; 14 | let reactionsData = null; 15 | const period = 30; 16 | 17 | --- 18 | 19 |
20 | Dashboard 21 |

Built-in Analytics

22 |

23 | The data visualizations on this page have been created using data from local MDX files and a custom web analytics 24 | solution powered by Vercel Edge Functions and a Neon Serverless Postgres database. The recent GitHub activity list 25 | has been created by using the GitHub REST API. 26 |

27 |
28 | { 29 | analyticsData && reactionsData ? ( 30 | <> 31 |
32 |

Totals by Year and Month

33 |

All content

34 |
35 | 36 |
37 |

Totals by Year and Day

38 |

All content

39 |
40 | 41 |
42 |
43 |

Totals by reaction

44 |

Recent reactions

45 |
46 |
47 |

Totals by Tag

48 |

Recent tags

49 | 51 |
52 | 53 |
54 | 55 |
56 |

Totals by publisher

57 |

All publishers

58 |
59 | 60 |
61 |

Totals by site visits

62 |

Recent site visits

63 |
64 | 65 |
66 |

Totals by referrer

67 |

Top Ten referrers

68 |
69 | 70 |
71 |
72 |
73 |

Totals by city

74 |

Recent city visits

75 |
76 |
77 |
78 |

Location visualization

79 |

Recent geolocation visits

80 |
81 |
82 |
83 |
84 |
85 |
86 | 87 |
88 |

Happiest Cities

89 |

Top ten happiest cities

90 | 91 |
92 | 93 |
94 |

Popular Posts

95 |

Top Ten Post views

96 | 98 |
99 | 100 |
101 |

Popular Articles

102 |

Top Ten Article views

103 | 105 |
106 | 107 | ) : null 108 | } 109 | 110 |
111 |

GtiHub Activity

112 |

Recent GitHub events

113 |
114 | 115 | 118 |
119 |
120 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, religion, or sexual identity 11 | and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the 27 | overall community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or 32 | advances of any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email 36 | address, without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | zemerikY@gmail.com. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series 87 | of actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or 94 | permanent ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within 114 | the community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.0, available at 120 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 121 | 122 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 123 | enforcement ladder](https://github.com/mozilla/diversity). 124 | 125 | [homepage]: https://www.contributor-covenant.org 126 | 127 | For answers to common questions about this code of conduct, see the FAQ at 128 | https://www.contributor-covenant.org/faq. Translations are available at 129 | https://www.contributor-covenant.org/translations. 130 | -------------------------------------------------------------------------------- /src/components/line-chart-years.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { data } = Astro.props; 3 | import colors from '../utils/colors'; 4 | import months from '../utils/months'; 5 | import years from '../utils/years'; 6 | 7 | const totalByYearAndMonth = Object.keys(data).reduce((acc, year) => { 8 | const groupedByYear = data[year]; 9 | Object.keys(groupedByYear).forEach((month) => { 10 | const monthCount = groupedByYear[month].length; 11 | 12 | if (!acc[year]) { 13 | acc[year] = []; 14 | } 15 | 16 | acc[year].push({ 17 | month: month, 18 | total: monthCount, 19 | }); 20 | }); 21 | 22 | // Add months with 0 count 23 | months.forEach((month) => { 24 | if (!acc[year].some((item) => item.month === month)) { 25 | acc[year].push({ 26 | month: month, 27 | total: 0, 28 | }); 29 | } 30 | }); 31 | return acc; 32 | }, {}); 33 | 34 | const chartWidth = 600; 35 | const chartHeight = 300; 36 | const offsetY = 40; 37 | const paddingX = 50; 38 | const paddingY = 50; 39 | 40 | const maxY = Math.max( 41 | ...Object.values(totalByYearAndMonth).flatMap((yearData: any) => yearData.map((month) => month.total)) 42 | ); 43 | const guides = [...Array(8).keys()]; 44 | 45 | const properties = Object.values(totalByYearAndMonth).map((property: any) => { 46 | return { 47 | total: property.reduce((items, item) => items + item.total, 0), 48 | data: property 49 | .sort((a, b) => months.indexOf(a.month) - months.indexOf(b.month)) 50 | .map((entry, index) => { 51 | const { total } = entry; 52 | 53 | const x = (index / months.length) * chartWidth + paddingX / 2; 54 | const y = chartHeight - offsetY - (total / maxY) * (chartHeight - (paddingY + offsetY)) - paddingY + offsetY; 55 | 56 | return { 57 | total: total, 58 | x: x, 59 | y: y, 60 | }; 61 | }), 62 | }; 63 | }); 64 | 65 | const points = properties.map((point): any => { 66 | return point.data.map((p) => { 67 | const { x, y } = p; 68 | return `${x},${y}`; 69 | }); 70 | }); 71 | 72 | const ticks = months.map((month, index) => { 73 | const x = (index / months.length) * chartWidth + paddingX / 2; 74 | return { 75 | month: month, 76 | x: x, 77 | }; 78 | }); 79 | --- 80 | 81 | 107 | 108 |
109 | 110 | { 111 | guides.map((_, index) => { 112 | const ratio = index / guides.length; 113 | const y = chartHeight - offsetY - chartHeight * ratio; 114 | 115 | return ( 116 | 122 | ); 123 | }) 124 | } 125 | { 126 | points.map((point, index) => { 127 | return ( 128 | 134 | ); 135 | }) 136 | } 137 | { 138 | properties.map((property, index) => { 139 | return property.data.map((p) => { 140 | const { total, x, y } = p; 141 | 142 | return ( 143 | 144 | 151 | {total > 0 ? ( 152 | 159 | {`x${total}`} 160 | 161 | ) : null} 162 | 163 | ); 164 | }); 165 | }) 166 | } 167 | { 168 | ticks.map((tick) => { 169 | const { month, x } = tick; 170 | 171 | return ( 172 | 179 | {month} 180 | 181 | ); 182 | }) 183 | } 184 | 185 |
186 |
    187 | { 188 | years.map((year: string, index: number) => { 189 | return ( 190 |
  • 191 | 197 |
  • 198 | ); 199 | }) 200 | } 201 |
202 | 203 | 208 | -------------------------------------------------------------------------------- /src/components/bar-chart-days.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { data } = Astro.props; 3 | import colors from '../utils/colors'; 4 | import days from '../utils/days'; 5 | import years from '../utils/years'; 6 | 7 | const totalByDayAndYear = Object.keys(data).reduce((acc, day) => { 8 | const groupedByDay = data[day]; 9 | 10 | Object.keys(groupedByDay).forEach((year) => { 11 | const yearCount = groupedByDay[year].length; 12 | 13 | if (!acc[day]) { 14 | acc[day] = []; 15 | } 16 | 17 | acc[day].push({ 18 | day: day, 19 | year: year, 20 | total: yearCount, 21 | }); 22 | }); 23 | 24 | // Add years with 0 count 25 | years.forEach((year) => { 26 | if (!acc[day].some((item) => item.year === year)) { 27 | acc[day].push({ 28 | day: day, 29 | year: year, 30 | total: 0, 31 | }); 32 | } 33 | }); 34 | 35 | acc[day].sort((a, b) => a.year - b.year); 36 | 37 | return acc; 38 | }, {}); 39 | 40 | const dayOrder = [...days.slice(1), 'Sun']; 41 | 42 | const totalByDayAndYearOrdered = dayOrder.reduce((result, day) => { 43 | result[day] = totalByDayAndYear[day]; 44 | return result; 45 | }, {}); 46 | 47 | const chartWidth = 600; 48 | const chartHeight = 300; 49 | const barWidth = 10; 50 | const barGap = 3; 51 | const offsetY = 40; 52 | const paddingX = 30; 53 | const paddingY = 50; 54 | const maxY = Math.max( 55 | ...Object.values(totalByDayAndYearOrdered).flatMap((yearData: any) => yearData.map((year) => year.total)) 56 | ); 57 | 58 | const guides = [...Array(8).keys()]; 59 | 60 | const properties = Object.values(totalByDayAndYearOrdered).map((property: any, index: number) => { 61 | const x = (index / days.length) * chartWidth + paddingX / 2; 62 | const day = property[0].day; 63 | 64 | const data = property 65 | .sort((a, b) => years.indexOf(a.year) - years.indexOf(b.year)) 66 | .map((entry, i) => { 67 | const { day, total } = entry; 68 | const height = 69 | chartHeight - offsetY - (total / maxY) * (chartHeight - (paddingY + offsetY)) - paddingY + offsetY * 2; 70 | const y = chartHeight - offsetY; 71 | return { 72 | day: day, 73 | year: years[i], 74 | total: total, 75 | height: total > 0 ? chartHeight - height : 1, 76 | x: x + (barWidth + barGap) * i, 77 | y: y, 78 | }; 79 | }); 80 | 81 | return { 82 | day: day, 83 | x: x, 84 | data: data, 85 | }; 86 | }); 87 | 88 | const ticks = dayOrder.map((day, index) => { 89 | const x = (index / days.length) * chartWidth + paddingX / 2; 90 | return { 91 | day: day, 92 | x: x, 93 | }; 94 | }); 95 | --- 96 | 97 | 124 | 125 |
126 | 127 | { 128 | guides.map((_, index) => { 129 | const ratio = index / guides.length; 130 | const y = chartHeight - offsetY - chartHeight * ratio; 131 | 132 | return ( 133 | 139 | ); 140 | }) 141 | } 142 | 143 | { 144 | properties.map((property) => { 145 | const { x, data } = property; 146 | 147 | return ( 148 | 149 | {data.map((d, index) => { 150 | const { x, y, height, total, day } = d; 151 | const _y = y - height; 152 | 153 | return ( 154 | 155 | 165 | {total > 0 ? ( 166 | 173 | {`x${total}`} 174 | 175 | ) : null} 176 | 177 | ); 178 | })} 179 | 180 | ); 181 | }) 182 | } 183 | 184 | { 185 | ticks.map((tick) => { 186 | const { day, x } = tick; 187 | 188 | return ( 189 | 196 | {day} 197 | 198 | ); 199 | }) 200 | } 201 | 202 |
203 |
    204 | { 205 | years.map((year: string, index: number) => { 206 | return ( 207 |
  • 208 | 214 |
  • 215 | ); 216 | }) 217 | } 218 |
219 | -------------------------------------------------------------------------------- /.astro/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'astro:content' { 2 | interface Render { 3 | '.mdx': Promise<{ 4 | Content: import('astro').MarkdownInstance<{}>['Content']; 5 | headings: import('astro').MarkdownHeading[]; 6 | remarkPluginFrontmatter: Record; 7 | }>; 8 | } 9 | } 10 | 11 | declare module 'astro:content' { 12 | interface Render { 13 | '.md': Promise<{ 14 | Content: import('astro').MarkdownInstance<{}>['Content']; 15 | headings: import('astro').MarkdownHeading[]; 16 | remarkPluginFrontmatter: Record; 17 | }>; 18 | } 19 | } 20 | 21 | declare module 'astro:content' { 22 | type Flatten = T extends { [K: string]: infer U } ? U : never; 23 | 24 | export type CollectionKey = keyof AnyEntryMap; 25 | export type CollectionEntry = Flatten; 26 | 27 | export type ContentCollectionKey = keyof ContentEntryMap; 28 | export type DataCollectionKey = keyof DataEntryMap; 29 | 30 | type AllValuesOf = T extends any ? T[keyof T] : never; 31 | type ValidContentEntrySlug = AllValuesOf< 32 | ContentEntryMap[C] 33 | >['slug']; 34 | 35 | /** @deprecated Use `getEntry` instead. */ 36 | export function getEntryBySlug< 37 | C extends keyof ContentEntryMap, 38 | E extends ValidContentEntrySlug | (string & {}), 39 | >( 40 | collection: C, 41 | // Note that this has to accept a regular string too, for SSR 42 | entrySlug: E, 43 | ): E extends ValidContentEntrySlug 44 | ? Promise> 45 | : Promise | undefined>; 46 | 47 | /** @deprecated Use `getEntry` instead. */ 48 | export function getDataEntryById( 49 | collection: C, 50 | entryId: E, 51 | ): Promise>; 52 | 53 | export function getCollection>( 54 | collection: C, 55 | filter?: (entry: CollectionEntry) => entry is E, 56 | ): Promise; 57 | export function getCollection( 58 | collection: C, 59 | filter?: (entry: CollectionEntry) => unknown, 60 | ): Promise[]>; 61 | 62 | export function getEntry< 63 | C extends keyof ContentEntryMap, 64 | E extends ValidContentEntrySlug | (string & {}), 65 | >(entry: { 66 | collection: C; 67 | slug: E; 68 | }): E extends ValidContentEntrySlug 69 | ? Promise> 70 | : Promise | undefined>; 71 | export function getEntry< 72 | C extends keyof DataEntryMap, 73 | E extends keyof DataEntryMap[C] | (string & {}), 74 | >(entry: { 75 | collection: C; 76 | id: E; 77 | }): E extends keyof DataEntryMap[C] 78 | ? Promise 79 | : Promise | undefined>; 80 | export function getEntry< 81 | C extends keyof ContentEntryMap, 82 | E extends ValidContentEntrySlug | (string & {}), 83 | >( 84 | collection: C, 85 | slug: E, 86 | ): E extends ValidContentEntrySlug 87 | ? Promise> 88 | : Promise | undefined>; 89 | export function getEntry< 90 | C extends keyof DataEntryMap, 91 | E extends keyof DataEntryMap[C] | (string & {}), 92 | >( 93 | collection: C, 94 | id: E, 95 | ): E extends keyof DataEntryMap[C] 96 | ? Promise 97 | : Promise | undefined>; 98 | 99 | /** Resolve an array of entry references from the same collection */ 100 | export function getEntries( 101 | entries: { 102 | collection: C; 103 | slug: ValidContentEntrySlug; 104 | }[], 105 | ): Promise[]>; 106 | export function getEntries( 107 | entries: { 108 | collection: C; 109 | id: keyof DataEntryMap[C]; 110 | }[], 111 | ): Promise[]>; 112 | 113 | export function reference( 114 | collection: C, 115 | ): import('astro/zod').ZodEffects< 116 | import('astro/zod').ZodString, 117 | C extends keyof ContentEntryMap 118 | ? { 119 | collection: C; 120 | slug: ValidContentEntrySlug; 121 | } 122 | : { 123 | collection: C; 124 | id: keyof DataEntryMap[C]; 125 | } 126 | >; 127 | // Allow generic `string` to avoid excessive type errors in the config 128 | // if `dev` is not running to update as you edit. 129 | // Invalid collection names will be caught at build time. 130 | export function reference( 131 | collection: C, 132 | ): import('astro/zod').ZodEffects; 133 | 134 | type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; 135 | type InferEntrySchema = import('astro/zod').infer< 136 | ReturnTypeOrOriginal['schema']> 137 | >; 138 | 139 | type ContentEntryMap = { 140 | "articles": Record; 146 | render(): Render[".md"]; 147 | }>; 148 | "demos": Record; 154 | render(): Render[".md"]; 155 | }>; 156 | "ghosts": Record; 162 | render(): Render[".md"]; 163 | }>; 164 | "opensource": Record; 170 | render(): Render[".md"]; 171 | }>; 172 | "posts": Record; 178 | render(): Render[".md"]; 179 | }>; 180 | "profiles": { 181 | "Developer-Utkarsh.mdx": { 182 | id: "Developer-Utkarsh.mdx"; 183 | slug: "developer-utkarsh"; 184 | body: string; 185 | collection: "profiles"; 186 | data: any 187 | } & { render(): Render[".mdx"] }; 188 | "axorax.mdx": { 189 | id: "axorax.mdx"; 190 | slug: "axorax"; 191 | body: string; 192 | collection: "profiles"; 193 | data: any 194 | } & { render(): Render[".mdx"] }; 195 | "calllme-shadow.mdx": { 196 | id: "calllme-shadow.mdx"; 197 | slug: "calllme-shadow"; 198 | body: string; 199 | collection: "profiles"; 200 | data: any 201 | } & { render(): Render[".mdx"] }; 202 | "harrysingh100.mdx": { 203 | id: "harrysingh100.mdx"; 204 | slug: "harrysingh100"; 205 | body: string; 206 | collection: "profiles"; 207 | data: any 208 | } & { render(): Render[".mdx"] }; 209 | "zemerik.mdx": { 210 | id: "zemerik.mdx"; 211 | slug: "zemerik"; 212 | body: string; 213 | collection: "profiles"; 214 | data: any 215 | } & { render(): Render[".mdx"] }; 216 | }; 217 | "streams": Record; 223 | render(): Render[".md"]; 224 | }>; 225 | 226 | }; 227 | 228 | type DataEntryMap = { 229 | 230 | }; 231 | 232 | type AnyEntryMap = ContentEntryMap & DataEntryMap; 233 | 234 | export type ContentConfig = typeof import("./../src/content/config.js"); 235 | } 236 | -------------------------------------------------------------------------------- /src/layouts/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Slot, component$, useSignal, $, useOnDocument } from '@builder.io/qwik'; 2 | 3 | import Logo from '../components/logo'; 4 | import NavLink from '../components/nav-link'; 5 | import SearchModal from '../components/search-modal'; 6 | import QuickSearch from '../components/search-trigger'; 7 | 8 | import isNewContent from '../utils/is-new-content'; 9 | 10 | import { siteLinks, socialLinks } from './nav-links.ts'; 11 | 12 | interface Props { 13 | fullWidth: boolean; 14 | slug: string; 15 | search: any; 16 | } 17 | 18 | const Layout = component$(({ fullWidth, slug, search }) => { 19 | const isModalOpen = useSignal(false); 20 | const isNavOpen = useSignal(false); 21 | 22 | const newItems = search 23 | .map((item) => { 24 | const { date, base } = item; 25 | 26 | return { 27 | base: base, 28 | date: new Date(date), 29 | }; 30 | }) 31 | .filter((item) => { 32 | const { date } = item; 33 | if (isNewContent(date)) { 34 | return item; 35 | } 36 | }) 37 | .reduce((items, item) => { 38 | const base = item.base; 39 | items[base] = (items[base] || 0) + 1; 40 | return items; 41 | }, {}); 42 | 43 | const handleNav = $(() => { 44 | isNavOpen.value = !isNavOpen.value; 45 | }); 46 | 47 | const handleModal = $(() => { 48 | isModalOpen.value = !isModalOpen.value; 49 | }); 50 | 51 | useOnDocument( 52 | 'keydown', 53 | $((event) => { 54 | if (event.key === 'k' && (event.metaKey || event.ctrlKey)) { 55 | handleModal(); 56 | } 57 | if (event.key === 'Escape' && isModalOpen.value) { 58 | handleModal(); 59 | } 60 | }) 61 | ); 62 | 63 | return ( 64 | <> 65 |
66 |
67 |
68 |
69 | 70 | ZemProfiles 71 | 72 |
73 | 95 |
96 |
97 |
98 |
99 |
100 | 101 |
102 | 112 | 113 |
114 | 170 |
171 |
174 |
175 | 176 |
177 | 181 |
182 |
183 |
184 |
185 | 186 | ); 187 | }); 188 | 189 | export default Layout; 190 | -------------------------------------------------------------------------------- /tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | const defaultTheme = require('tailwindcss/defaultTheme'); 3 | 4 | module.exports = { 5 | content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], 6 | safelist: [ 7 | // These are for the modal 8 | 'backdrop-blur', 9 | // These are for the TOC 10 | 'pl-4', 11 | 'pl-5', 12 | 'pl-6', 13 | 'pl-7', 14 | 'pl-8', 15 | // These are for the charts 16 | 'stroke-brand-teal', 17 | 'stroke-brand-mauve', 18 | 'stroke-brand-salmon', 19 | 'stroke-brand-yellow', 20 | 'stroke-brand-lime', 21 | 'stroke-brand-blood', 22 | 'stroke-brand-starfleet', 23 | 'stroke-brand-electric', 24 | 'stroke-brand-pink', 25 | 'stroke-brand-fuchsia', 26 | 'stroke-brand-secondary', 27 | 28 | 'fill-brand-teal', 29 | 'fill-brand-mauve', 30 | 'fill-brand-salmon', 31 | 'fill-brand-yellow', 32 | 'fill-brand-lime', 33 | 'fill-brand-blood', 34 | 'fill-brand-starfleet', 35 | 'fill-brand-electric', 36 | 'fill-brand-pink', 37 | 'fill-brand-fuchsia', 38 | 'fill-brand-secondary', 39 | 40 | 'bg-brand-teal', 41 | 'bg-brand-mauve', 42 | 'bg-brand-salmon', 43 | 'bg-brand-yellow', 44 | 'bg-brand-lime', 45 | 'bg-brand-blood', 46 | 'bg-brand-starfleet', 47 | 'bg-brand-electric', 48 | 'bg-brand-pink', 49 | 'bg-brand-fuchsia', 50 | 'bg-brand-secondary', 51 | 52 | 'text-brand-teal', 53 | 'text-brand-mauve', 54 | 'text-brand-salmon', 55 | 'text-brand-yellow', 56 | 'text-brand-lime', 57 | 'text-brand-blood', 58 | 'text-brand-starfleet', 59 | 'text-brand-electric', 60 | 'text-brand-pink', 61 | 'text-brand-fuchsia', 62 | 'text-brand-secondary', 63 | 64 | // This is for the GitHub Activity 65 | 'bg-brand-starfleet', 66 | 'bg-brand-electric', 67 | 'bg-red-500', 68 | 69 | // These are for the Ghosts collections cards 70 | 'cursor-not-allowed', 71 | ], 72 | theme: { 73 | extend: { 74 | colors: { 75 | brand: { 76 | text: '#d9dbdf', 77 | primary: '#f056c7', 78 | secondary: '#a4a0fb', 79 | tertiary: '#58e6d9', 80 | muted: '#605c9d', 81 | salmon: '#ff6090', 82 | mauve: '#4871e3', 83 | teal: '#00bcd4', 84 | lime: '#8bc34a', 85 | yellow: '#ffc107', 86 | fuchsia: '#7B1FA2', 87 | blood: '#fc5656', 88 | starfleet: '#0091f7', 89 | electric: '#b900f7', 90 | pink: '#0096FF', 91 | background: '#131127', 92 | outline: '#232140', 93 | surface: '#16142c', 94 | guide: '#2d2a58', 95 | radar: '#57538c', 96 | }, 97 | }, 98 | fontFamily: { 99 | sans: ['Inconsolata', ...defaultTheme.fontFamily.sans], 100 | }, 101 | maxWidth: { 102 | '8xl': '90rem', 103 | }, 104 | backgroundImage: { 105 | 'x-icon': "url('https://cdn.icon-icons.com/icons2/4029/PNG/512/twitter_x_new_logo_x_rounded_icon_256078.png')", 106 | }, 107 | typography: (theme) => ({ 108 | DEFAULT: { 109 | css: { 110 | '*:not(h1, h2, h3, h4, h5, h6, a, code)': { 111 | color: theme('colors.brand.text'), 112 | }, 113 | 114 | h1: { 115 | color: theme('colors.brand.text'), 116 | margin: '2rem 0', 117 | fontWeight: 900, 118 | }, 119 | 'h2, h3, h4, h5, h6': { 120 | color: theme('colors.brand.salmon'), 121 | fontWeight: 900, 122 | a: { 123 | fontWeight: 900, 124 | textDecoration: 'none', 125 | color: theme('colors.brand.salmon'), 126 | }, 127 | }, 128 | p: { 129 | fontFamily: 'system-ui', 130 | strong: { 131 | fontWeight: 700, 132 | }, 133 | }, 134 | button: { 135 | fontFamily: 'system-ui', 136 | fontWeight: 700, 137 | }, 138 | a: { 139 | color: theme('colors.brand.secondary'), 140 | cursor: 'pointer', 141 | wordBreak: 'break-word', 142 | '&:hover': { 143 | color: theme('colors.brand.text'), 144 | }, 145 | p: { 146 | margin: 0, 147 | color: 'inherit', 148 | }, 149 | }, 150 | ol: { 151 | li: { 152 | '&::marker': { 153 | color: theme('colors.brand.salmon'), 154 | }, 155 | }, 156 | }, 157 | ul: { 158 | li: { 159 | '&::marker': { 160 | color: theme('colors.brand.salmon'), 161 | }, 162 | }, 163 | }, 164 | 'a, small, time': { 165 | fontWeight: 300, 166 | }, 167 | 'pre[class*="language-"]': { 168 | margin: '2.5rem 0px!important', 169 | }, 170 | code: { 171 | color: theme('colors.brand.tertiary'), 172 | wordBreak: 'break-word', 173 | '&::before': { 174 | content: '"" !important', 175 | }, 176 | '&::after': { 177 | content: '"" !important', 178 | }, 179 | }, 180 | 181 | blockquote: { 182 | background: theme('colors.brand.surface'), 183 | padding: '1.2em', 184 | borderLeftColor: theme('colors.brand.yellow'), 185 | borderRadius: '.2em', 186 | p: { 187 | margin: 0, 188 | }, 189 | }, 190 | dl: { 191 | marginTop: '1.25em', 192 | marginBottom: '1.25em', 193 | paddingLeft: '1.625em', 194 | dt: { 195 | fontSize: '1.25rem', 196 | color: theme('colors.brand.text'), 197 | paddingLeft: '0.375em', 198 | }, 199 | dd: { 200 | display: 'list-item', 201 | listStyleType: 'disc', 202 | marginTop: '0.5em', 203 | marginBottom: '0.5em', 204 | paddingLeft: '0.375em', 205 | '&::marker': { 206 | color: theme('colors.brand.salmon'), 207 | }, 208 | }, 209 | }, 210 | '.twitter-tweet': { 211 | '&::before': { 212 | content: "''", 213 | display: 'block', 214 | background: theme('backgroundImage.x-icon'), 215 | width: 24, 216 | height: 24, 217 | marginBottom: 16, 218 | }, 219 | borderColor: '#232140!important', 220 | padding: '32px!important', 221 | background: theme('colors.brand.surface'), 222 | borderRadius: '4px', 223 | color: theme('colors.brand.text'), 224 | }, 225 | '.event-color-PushEvent': { 226 | backgroundColor: theme('colors.brand.starfleet'), 227 | }, 228 | '.event-color-CreateEvent': { 229 | backgroundColor: theme('colors.brand.lime'), 230 | }, 231 | '.event-color-ForkEvent': { 232 | backgroundColor: theme('colors.brand.mauve'), 233 | }, 234 | '.event-color-WatchEvent': { 235 | backgroundColor: theme('colors.brand.electric'), 236 | }, 237 | '.event-color-DeleteEvent': { 238 | backgroundColor: theme('colors.red.500'), 239 | }, 240 | 241 | '.event-color-IssueCommentEvent': { 242 | backgroundColor: theme('colors.brand.yellow'), 243 | }, 244 | '.event-color-PullRequestReviewCommentEvent': { 245 | backgroundColor: theme('colors.brand.yellow'), 246 | }, 247 | 248 | '.event-color-PullRequestEvent': { 249 | backgroundColor: theme('colors.brand.teal'), 250 | }, 251 | '.event-color-PullRequestReviewEvent': { 252 | backgroundColor: theme('colors.brand.teal'), 253 | }, 254 | }, 255 | }, 256 | }), 257 | }, 258 | }, 259 | plugins: [ 260 | require('@tailwindcss/typography'), 261 | function ({ addBase, theme }) { 262 | function extractColorVars(colorObj, colorGroup = '') { 263 | return Object.keys(colorObj).reduce((vars, colorKey) => { 264 | const value = colorObj[colorKey]; 265 | 266 | const newVars = 267 | typeof value === 'string' 268 | ? { [`--color${colorGroup}-${colorKey}`]: value } 269 | : extractColorVars(value, `-${colorKey}`); 270 | 271 | return { ...vars, ...newVars }; 272 | }, {}); 273 | } 274 | 275 | addBase({ 276 | ':root': extractColorVars(theme('colors')), 277 | }); 278 | }, 279 | ], 280 | }; 281 | --------------------------------------------------------------------------------