From a9b9cf738091f07774d7764af19dd0895044d9bf Mon Sep 17 00:00:00 2001 From: khris-xp Date: Wed, 15 Nov 2023 11:14:13 +0700 Subject: [PATCH 1/7] refac: sperate event and project fetch function --- scripts/actions/event.ts | 20 +++++++++++++++ scripts/actions/project.ts | 27 ++++++++++++++++++++ src/components/CardLink.astro | 1 - src/content/ring.json | 2 ++ src/pages/index.astro | 46 ++++++++++++----------------------- src/pages/ring.astro | 10 ++------ 6 files changed, 66 insertions(+), 40 deletions(-) create mode 100644 scripts/actions/event.ts create mode 100644 scripts/actions/project.ts diff --git a/scripts/actions/event.ts b/scripts/actions/event.ts new file mode 100644 index 0000000..67cc463 --- /dev/null +++ b/scripts/actions/event.ts @@ -0,0 +1,20 @@ +export interface IEvent { + name: string; + date: string; + location: string; + img: string; + link: string; +} + +export function fetchEvent(existingEvent: IEvent[]): IEvent[] { + const events = [...existingEvent]; + + for (const event of events) { + const index = events.findIndex((x) => x.name === event.name); + if (index === -1) { + events.push(event); + } + } + + return events; +} \ No newline at end of file diff --git a/scripts/actions/project.ts b/scripts/actions/project.ts new file mode 100644 index 0000000..d0c1b0c --- /dev/null +++ b/scripts/actions/project.ts @@ -0,0 +1,27 @@ +export interface IProject { + name: string; + repo: string; + description: string; + languages?: string[]; +} + +export function fetchProjects(existingProjects: IProject[], newProjects: IProject[]): IProject[] { + const projects = [...existingProjects]; + + for (const project of newProjects) { + const index = projects.findIndex((x) => x.name === project.name); + if (index === -1) { + projects.push(project); + } + } + + return projects; +} + +export function shuffleProject(array: T[]): T[] { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)) + ;[array[i], array[j]] = [array[j], array[i]] + } + return array +} \ No newline at end of file diff --git a/src/components/CardLink.astro b/src/components/CardLink.astro index d422b47..364bb36 100644 --- a/src/components/CardLink.astro +++ b/src/components/CardLink.astro @@ -19,7 +19,6 @@ const { title, url, description, languages = [] } = Astro.props

{description}

- {languages.length > 0 &&

{languages.join(', ')}

} diff --git a/src/content/ring.json b/src/content/ring.json index 6351d3b..c6559f7 100644 --- a/src/content/ring.json +++ b/src/content/ring.json @@ -384,6 +384,7 @@ "languages": [ "JavaScript", "Discord.js" + ] }, { "name": "Arcade Game", @@ -397,6 +398,7 @@ "Socket-io", "Mqtt.js", "Mongoose" + ] }, { "name": "Bad Boyz", diff --git a/src/pages/index.astro b/src/pages/index.astro index 44f076b..2bf0846 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -6,33 +6,11 @@ import events from '../content/events.json' import sponsors from '../content/sponsors.json' import CardLink from '../components/CardLink.astro' import EventCard from '../components/EventCard.astro' +import { fetchProjects, shuffleProject } from '../../scripts/actions/project' +import { fetchEvent } from '../../scripts/actions/event' -// TODO: refactor dedupe logic to separate file? -// TODO: limit projects in index page -const projects = [...ring.projects] -for (const project of generatedRing.projects as typeof ring.projects) { - const index = projects.findIndex((x) => x.name === project.name) - if (index === -1) { - projects.push(project) - } -} - -function shuffle(array: T[]): T[] { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)) - ;[array[i], array[j]] = [array[j], array[i]] - } - return array -} - -const event = [...events.events] - .filter((x, i, a) => a.findIndex((y) => y.name === x.name) === i) - .sort((a, b) => { - const aDate = new Date(a.date) - const bDate = new Date(b.date) - return aDate.getTime() - bDate.getTime() - }) - .slice(0, 6) // Add this line to limit to 6 events +const projects = fetchProjects([...ring.projects], [...generatedRing.projects]) +const event = fetchEvent([...events.events]) --- @@ -48,10 +26,16 @@ const event = [...events.events]

1. Write code 💻

{ - shuffle(projects) + shuffleProject(projects) .slice(0, 6) - .map((x) => { - return + .map((project) => { + return ( + + ) }) }
@@ -63,8 +47,8 @@ const event = [...events.events]

2. Join events 🙌

{ - event.map((x) => { - return + event.map((event) => { + return }) }
diff --git a/src/pages/ring.astro b/src/pages/ring.astro index f5350d0..c75016e 100644 --- a/src/pages/ring.astro +++ b/src/pages/ring.astro @@ -3,15 +3,9 @@ import BaseLayout from '../layouts/BaseLayout.astro' import ring from '../content/ring.json' import generatedRing from '../content/ring.generated.json' import CardLink from '../components/CardLink.astro' +import { fetchProjects } from '../../scripts/actions/project' -// TODO: refactor dedupe logic to separate file? -const projects = [...ring.projects] -for (const project of generatedRing.projects as typeof ring.projects) { - const index = projects.findIndex((x) => x.name === project.name) - if (index === -1) { - projects.push(project) - } -} +const projects = fetchProjects([...ring.projects], [...generatedRing.projects]) --- From 9fc762ed63533841a7b294aeed55de8bdfd851ad Mon Sep 17 00:00:00 2001 From: khris-xp Date: Wed, 15 Nov 2023 11:14:13 +0700 Subject: [PATCH 2/7] refac: separate event and project fetch function --- scripts/actions/event.ts | 20 +++++++++++++++ scripts/actions/project.ts | 27 ++++++++++++++++++++ src/components/CardLink.astro | 1 - src/content/ring.json | 2 ++ src/pages/index.astro | 46 ++++++++++++----------------------- src/pages/ring.astro | 10 ++------ 6 files changed, 66 insertions(+), 40 deletions(-) create mode 100644 scripts/actions/event.ts create mode 100644 scripts/actions/project.ts diff --git a/scripts/actions/event.ts b/scripts/actions/event.ts new file mode 100644 index 0000000..67cc463 --- /dev/null +++ b/scripts/actions/event.ts @@ -0,0 +1,20 @@ +export interface IEvent { + name: string; + date: string; + location: string; + img: string; + link: string; +} + +export function fetchEvent(existingEvent: IEvent[]): IEvent[] { + const events = [...existingEvent]; + + for (const event of events) { + const index = events.findIndex((x) => x.name === event.name); + if (index === -1) { + events.push(event); + } + } + + return events; +} \ No newline at end of file diff --git a/scripts/actions/project.ts b/scripts/actions/project.ts new file mode 100644 index 0000000..d0c1b0c --- /dev/null +++ b/scripts/actions/project.ts @@ -0,0 +1,27 @@ +export interface IProject { + name: string; + repo: string; + description: string; + languages?: string[]; +} + +export function fetchProjects(existingProjects: IProject[], newProjects: IProject[]): IProject[] { + const projects = [...existingProjects]; + + for (const project of newProjects) { + const index = projects.findIndex((x) => x.name === project.name); + if (index === -1) { + projects.push(project); + } + } + + return projects; +} + +export function shuffleProject(array: T[]): T[] { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)) + ;[array[i], array[j]] = [array[j], array[i]] + } + return array +} \ No newline at end of file diff --git a/src/components/CardLink.astro b/src/components/CardLink.astro index d422b47..364bb36 100644 --- a/src/components/CardLink.astro +++ b/src/components/CardLink.astro @@ -19,7 +19,6 @@ const { title, url, description, languages = [] } = Astro.props

{description}

- {languages.length > 0 &&

{languages.join(', ')}

} diff --git a/src/content/ring.json b/src/content/ring.json index 6351d3b..c6559f7 100644 --- a/src/content/ring.json +++ b/src/content/ring.json @@ -384,6 +384,7 @@ "languages": [ "JavaScript", "Discord.js" + ] }, { "name": "Arcade Game", @@ -397,6 +398,7 @@ "Socket-io", "Mqtt.js", "Mongoose" + ] }, { "name": "Bad Boyz", diff --git a/src/pages/index.astro b/src/pages/index.astro index 44f076b..2bf0846 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -6,33 +6,11 @@ import events from '../content/events.json' import sponsors from '../content/sponsors.json' import CardLink from '../components/CardLink.astro' import EventCard from '../components/EventCard.astro' +import { fetchProjects, shuffleProject } from '../../scripts/actions/project' +import { fetchEvent } from '../../scripts/actions/event' -// TODO: refactor dedupe logic to separate file? -// TODO: limit projects in index page -const projects = [...ring.projects] -for (const project of generatedRing.projects as typeof ring.projects) { - const index = projects.findIndex((x) => x.name === project.name) - if (index === -1) { - projects.push(project) - } -} - -function shuffle(array: T[]): T[] { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)) - ;[array[i], array[j]] = [array[j], array[i]] - } - return array -} - -const event = [...events.events] - .filter((x, i, a) => a.findIndex((y) => y.name === x.name) === i) - .sort((a, b) => { - const aDate = new Date(a.date) - const bDate = new Date(b.date) - return aDate.getTime() - bDate.getTime() - }) - .slice(0, 6) // Add this line to limit to 6 events +const projects = fetchProjects([...ring.projects], [...generatedRing.projects]) +const event = fetchEvent([...events.events]) --- @@ -48,10 +26,16 @@ const event = [...events.events]

1. Write code 💻

{ - shuffle(projects) + shuffleProject(projects) .slice(0, 6) - .map((x) => { - return + .map((project) => { + return ( + + ) }) }
@@ -63,8 +47,8 @@ const event = [...events.events]

2. Join events 🙌

{ - event.map((x) => { - return + event.map((event) => { + return }) }
diff --git a/src/pages/ring.astro b/src/pages/ring.astro index f5350d0..c75016e 100644 --- a/src/pages/ring.astro +++ b/src/pages/ring.astro @@ -3,15 +3,9 @@ import BaseLayout from '../layouts/BaseLayout.astro' import ring from '../content/ring.json' import generatedRing from '../content/ring.generated.json' import CardLink from '../components/CardLink.astro' +import { fetchProjects } from '../../scripts/actions/project' -// TODO: refactor dedupe logic to separate file? -const projects = [...ring.projects] -for (const project of generatedRing.projects as typeof ring.projects) { - const index = projects.findIndex((x) => x.name === project.name) - if (index === -1) { - projects.push(project) - } -} +const projects = fetchProjects([...ring.projects], [...generatedRing.projects]) --- From 6023d1c16c439ddbda5cb2ab78de9450d19e5ca9 Mon Sep 17 00:00:00 2001 From: khris-xp Date: Wed, 15 Nov 2023 11:23:58 +0700 Subject: [PATCH 3/7] feat: languages url --- scripts/actions/fetch-projects-by-topic.ts | 49 ++++++++++++++++------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/scripts/actions/fetch-projects-by-topic.ts b/scripts/actions/fetch-projects-by-topic.ts index 8e7084f..2f7866d 100644 --- a/scripts/actions/fetch-projects-by-topic.ts +++ b/scripts/actions/fetch-projects-by-topic.ts @@ -1,10 +1,15 @@ +import { string } from 'astro/zod' import fs from 'fs' -import path from 'path' import process from 'node:process' +import path from 'path' import { fileURLToPath } from 'url' const defaultTopicName = 'bangkok-open-source' +interface Language { + [key: string]: number; +} + const __dirname = path.dirname(fileURLToPath(import.meta.url)) const filePath = path.resolve(__dirname, '../../src/content/ring.generated.json') @@ -37,16 +42,30 @@ async function fetchPagedProjects( page = 1, perPage = 100 ): Promise { - const url = new URL('https://api.github.com/search/repositories') - url.searchParams.set('q', query) - url.searchParams.set('page', `${page}`) - url.searchParams.set('per_page', `${perPage}`) + const url = new URL('https://api.github.com/search/repositories'); + url.searchParams.set('q', query); + url.searchParams.set('page', `${page}`); + url.searchParams.set('per_page', `${perPage}`); - const resp = await fetch(url) + const resp = await fetch(url); if (!resp.ok) { - throw new Error(`Failed to fetch paged projects: ${resp.status} ${await resp.text()}`) + throw new Error(`Failed to fetch paged projects: ${resp.status} ${await resp.text()}`); } - return (await resp.json()) as SearchRepositoriesResponse + const result = (await resp.json()) as SearchRepositoriesResponse; + + // Fetch languages for each repository + const repositoriesWithLanguages = await Promise.all( + result.items.map(async (repo) => { + const languagesResp = await fetch(repo.languages_url); + if (!languagesResp.ok) { + throw new Error(`Failed to fetch languages for ${repo.full_name}`); + } + const languages: Language = await languagesResp.json(); + return { ...repo, languages: Object.keys(languages) }; + }) + ); + + return { ...result, items: repositoriesWithLanguages }; } function saveProjectsToJSON(projects: Project[]) { @@ -64,14 +83,17 @@ function saveProjectsToJSON(projects: Project[]) { async function main() { const topicName = process.argv[2] || defaultTopicName const topicLimit = Number(process.argv[3] ?? 1000) - const repositories = await fetchProjects(topicName, topicLimit) - // TODO: should be nice to have repo's languages from Repository.languages_url not just Repository.language + const repositories = await fetchProjects(topicName, topicLimit); + const projects = repositories.map((repo) => ({ name: repo.name, repo: repo.html_url, description: repo.description, - languages: [repo.language] - })) + languages: [repo.language], + languages_url: repo.languages_url + })); + + console.log(`Fetched ${projects.length} projects from ${topicName} topic`); saveProjectsToJSON(projects) } @@ -175,5 +197,6 @@ interface Project { name: string repo: string description: string - languages: string[] + languages?: string[] + languages_url?: string } From 1b96c52037ca9e3f6741329b1b76d1aaa98c7870 Mon Sep 17 00:00:00 2001 From: khris-xp Date: Wed, 15 Nov 2023 11:27:23 +0700 Subject: [PATCH 4/7] style: remove console.log --- scripts/actions/fetch-projects-by-topic.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/actions/fetch-projects-by-topic.ts b/scripts/actions/fetch-projects-by-topic.ts index 2f7866d..34d1529 100644 --- a/scripts/actions/fetch-projects-by-topic.ts +++ b/scripts/actions/fetch-projects-by-topic.ts @@ -92,8 +92,6 @@ async function main() { languages: [repo.language], languages_url: repo.languages_url })); - - console.log(`Fetched ${projects.length} projects from ${topicName} topic`); saveProjectsToJSON(projects) } From 9264c5a4792f9763a52eecab81f29f255e56f7bd Mon Sep 17 00:00:00 2001 From: khris-xp Date: Thu, 16 Nov 2023 09:55:14 +0700 Subject: [PATCH 5/7] style: add languages text color --- src/components/CardLink.astro | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/CardLink.astro b/src/components/CardLink.astro index 364bb36..1f2dd25 100644 --- a/src/components/CardLink.astro +++ b/src/components/CardLink.astro @@ -11,7 +11,10 @@ const { title, url, description, languages = [] } = Astro.props From 15b28cd1622a5ef7aa8349ce9c21ae79e999a5f0 Mon Sep 17 00:00:00 2001 From: khris-xp Date: Sat, 18 Nov 2023 08:32:44 +0700 Subject: [PATCH 6/7] fix: astro zod build --- scripts/actions/fetch-projects-by-topic.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/actions/fetch-projects-by-topic.ts b/scripts/actions/fetch-projects-by-topic.ts index 34d1529..fc3e5f7 100644 --- a/scripts/actions/fetch-projects-by-topic.ts +++ b/scripts/actions/fetch-projects-by-topic.ts @@ -1,4 +1,3 @@ -import { string } from 'astro/zod' import fs from 'fs' import process from 'node:process' import path from 'path' From 0d0e3c50b4082eed7733a16152349cc1cb996274 Mon Sep 17 00:00:00 2001 From: khris-xp Date: Sat, 18 Nov 2023 02:08:48 +0000 Subject: [PATCH 7/7] Update ring.generated.json --- src/content/ring.generated.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content/ring.generated.json b/src/content/ring.generated.json index 1690a97..8298be5 100644 --- a/src/content/ring.generated.json +++ b/src/content/ring.generated.json @@ -6,7 +6,8 @@ "description": "A client-side secure P2P file sharing using WebRTC.", "languages": [ "Svelte" - ] + ], + "languages_url": "https://api.github.com/repos/ntsd/zero-share/languages" } ] } \ No newline at end of file