From 0ee7b355300e9adfec42215ce1457406c22755fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20LUDWIG?= Date: Fri, 26 Jul 2024 14:05:05 +0200 Subject: [PATCH] feat: get all internal links from a Wikipedia article --- TODO.md | 3 +- packages/config-tailwind/tailwind.config.js | 1 + packages/constants/version.ts | 2 +- packages/i18n/src/translations/fr-FR.json | 2 +- packages/ui/src/Footer/Footer.tsx | 4 +- packages/ui/src/Header/Locales.tsx | 5 +- .../src/WikipediaClient.tsx | 56 +++++--- .../src/wikipedia-api.ts | 127 +++++++++++++++--- 8 files changed, 154 insertions(+), 46 deletions(-) diff --git a/TODO.md b/TODO.md index a329339..08345ec 100644 --- a/TODO.md +++ b/TODO.md @@ -2,9 +2,10 @@ - [x] chore: initial commit (+ mirror on GitHub) - [x] Deploy first staging version (v1.0.0-staging.1) -- [ ] Add docs to add locale/edit translations, create component, install a dependency in a package, create a new package, technology used, architecture, links where it's deployed, how to use/install for end users, how to update dependencies with `npx taze -l` etc. - [ ] Implement Wikipedia Game Solver (`website`) with inputs, button to submit, and list all articles to go from one to another, or none if it is not possible +- [ ] Implement toast notifications for errors, warnings, and success messages - [ ] v1.0.0-staging.2 +- [ ] Add docs to add locale/edit translations, create component, install a dependency in a package, create a new package, technology used, architecture, links where it's deployed, how to use/install for end users, how to update dependencies with `npx taze -l` etc. - [ ] Implement CLI (`cli`) - [ ] v1.0.0-staging.3 - [ ] Implement REST API (`api`) with JSON responses ([AdonisJS](https://adonisjs.com/)) diff --git a/packages/config-tailwind/tailwind.config.js b/packages/config-tailwind/tailwind.config.js index ac64023..24b3e4d 100644 --- a/packages/config-tailwind/tailwind.config.js +++ b/packages/config-tailwind/tailwind.config.js @@ -23,6 +23,7 @@ const config = { yellow: "#fef08a", transparent: "transparent", inherit: "inherit", + current: "currentColor", }, fontFamily: { sans: ["'Montserrat'", ...fontFamily.sans], diff --git a/packages/constants/version.ts b/packages/constants/version.ts index 70923bc..000564d 100644 --- a/packages/constants/version.ts +++ b/packages/constants/version.ts @@ -5,5 +5,5 @@ export const VERSION = ? "0.0.0-development" : packageJSON.version -export const GIT_REPO_URL = +export const GIT_REPO_LINK = "https://git.theoludwig.fr/theoludwig/wikipedia-game-solver" diff --git a/packages/i18n/src/translations/fr-FR.json b/packages/i18n/src/translations/fr-FR.json index dc97706..b1712f7 100644 --- a/packages/i18n/src/translations/fr-FR.json +++ b/packages/i18n/src/translations/fr-FR.json @@ -18,6 +18,6 @@ }, "home": { "title": "Wikipedia Game Solver", - "description": "Le jeu Wikipédia implique des joueurs en compétition pour naviguer d'une page Wikipédia à une autre en utilisant uniquement des liens internes." + "description": "Le jeu Wikipédia implique des joueurs en compétition pour naviguer d'une page Wikipedia à une autre en utilisant uniquement des liens internes." } } diff --git a/packages/ui/src/Footer/Footer.tsx b/packages/ui/src/Footer/Footer.tsx index a4f78f5..f112efe 100644 --- a/packages/ui/src/Footer/Footer.tsx +++ b/packages/ui/src/Footer/Footer.tsx @@ -1,6 +1,6 @@ import { useTranslations } from "next-intl" -import { GIT_REPO_URL } from "@repo/constants" +import { GIT_REPO_LINK } from "@repo/constants" import { Link } from "../design/Link/Link" export interface FooterProps { @@ -24,7 +24,7 @@ export const Footer: React.FC = (props) => {

Version{" "} diff --git a/packages/ui/src/Header/Locales.tsx b/packages/ui/src/Header/Locales.tsx index b5acc84..af4fede 100644 --- a/packages/ui/src/Header/Locales.tsx +++ b/packages/ui/src/Header/Locales.tsx @@ -1,6 +1,7 @@ "use client" import { classNames } from "@repo/config-tailwind/classNames" +import type { Locale } from "@repo/i18n/config" import { LOCALES } from "@repo/i18n/config" import { usePathname, useRouter } from "@repo/i18n/navigation" import { useLocale, useTranslations } from "next-intl" @@ -8,7 +9,7 @@ import { useLocale, useTranslations } from "next-intl" export const Locales: React.FC = () => { const router = useRouter() const pathname = usePathname() - const currentLocale = useLocale() + const localeCurrent = useLocale() as Locale const t = useTranslations() @@ -21,7 +22,7 @@ export const Locales: React.FC = () => { key={locale} className={classNames("rounded-md p-2", { "border-primary dark:border-primary-dark border": - locale === currentLocale, + locale === localeCurrent, })} > - - + + Using: + + {getWikipediaLink(localeWikipedia).replace("https://", "")} + + ) } diff --git a/packages/wikipedia-game-solver/src/wikipedia-api.ts b/packages/wikipedia-game-solver/src/wikipedia-api.ts index d27ea77..308eb1b 100644 --- a/packages/wikipedia-game-solver/src/wikipedia-api.ts +++ b/packages/wikipedia-game-solver/src/wikipedia-api.ts @@ -1,28 +1,111 @@ +import type { Locale } from "@repo/i18n/config" + export const sum = (a: number, b: number): number => { return a + b } -export const wikipediaAPIBaseURL = new URL("https://en.wikipedia.org/w/api.php") +export const WIKIPEDIA_LOCALES = ["en", "fr"] as const +export type WikipediaLocale = (typeof WIKIPEDIA_LOCALES)[number] -// const getWikipediaPageLinks = async (title: string): Promise => { -// const url = new URL(wikipediaAPIBaseURL) -// url.searchParams.append("action", "query") -// url.searchParams.append("titles", title) -// url.searchParams.append("prop", "links") -// url.searchParams.append("pllimit", "max") -// url.searchParams.append("format", "json") -// url.searchParams.append("origin", "*") -// const response = await fetch(url, { -// method: "GET", -// }) -// if (!response.ok) { -// throw new Error(response.statusText) -// } -// const json = await response.json() -// return json -// } +export const fromLocaleToWikipediaLocale = ( + locale: Locale, +): WikipediaLocale => { + return locale === "en-US" ? "en" : "fr" +} -// const links = await getWikipediaPageLinks("France") -// const links2 = await getWikipediaPageLinks("Frddgdgdgance") -// console.log("links.length", links) -// console.log("links.length", links2) +export const getWikipediaLink = (locale: WikipediaLocale): string => { + return `https://${locale}.wikipedia.org` +} + +interface WikipediaQueryLinksResponse { + continue?: { + plcontinue: string + continue: string + } + query: { + pages: { + [key: string]: { + pageid: number + ns: number + title: string + links: [ + { + ns: number + title: string + }, + ] + } + } + } + limits: { + links: number + } +} + +interface GetWikipediaPageInternalLinksInput { + title: string + locale: WikipediaLocale +} + +interface GetWikipediaPageInternalLinksOutput { + title: string + links: string[] +} + +export const getWikipediaPageInternalLinks = async ( + input: GetWikipediaPageInternalLinksInput, +): Promise => { + const links: string[] = [] + let title = input.title + let plcontinue: string | null = null + + const fetchLinks = async (): Promise => { + const url = new URL("/w/api.php", getWikipediaLink(input.locale)) + url.searchParams.append("action", "query") + url.searchParams.append("titles", title) + url.searchParams.append("prop", "links") + url.searchParams.append("pllimit", "max") + url.searchParams.append("format", "json") + url.searchParams.append("origin", "*") + if (plcontinue != null) { + url.searchParams.set("plcontinue", plcontinue) + } + const response = await fetch(url, { + method: "GET", + }) + if (!response.ok) { + throw new Error(response.statusText) + } + const json = (await response.json()) as WikipediaQueryLinksResponse + return json + } + + do { + try { + const response = await fetchLinks() + plcontinue = response?.continue?.plcontinue ?? null + const pages = Object.keys(response.query.pages) + const page = pages[0] ?? "" + if (page === "-1" || page === "") { + break + } + const pageData = response.query.pages[page] + if (pageData == null) { + break + } + title = pageData.title + links.push( + ...pageData.links.map((link) => { + return link.title + }), + ) + } catch { + break + } + } while (plcontinue != null) + + return { + title, + links, + } +}