Strongly type everything

This commit is contained in:
Taevas 2023-05-10 19:55:11 +02:00
parent 842a627cac
commit fee3766c2b
18 changed files with 221 additions and 109 deletions

View file

@ -1,5 +1,6 @@
import { Handler } from '@netlify/functions' import { Handler } from '@netlify/functions'
import fetch from "node-fetch" import fetch from "node-fetch"
import { AnilistInfo } from '../../src/components/Anilist'
const handler: Handler = async (event, context) => { const handler: Handler = async (event, context) => {
let anilist = await fetch("https://graphql.anilist.co", { let anilist = await fetch("https://graphql.anilist.co", {
@ -52,7 +53,7 @@ const handler: Handler = async (event, context) => {
let p_json = await anilist.json() as {[key: string]: any} let p_json = await anilist.json() as {[key: string]: any}
let json = p_json.data.MediaList let json = p_json.data.MediaList
let anime = { let anime: AnilistInfo = {
title: json.media.title.romaji, title: json.media.title.romaji,
episodes: { episodes: {
watched: json.progress, watched: json.progress,

View file

@ -1,5 +1,6 @@
import { Handler } from '@netlify/functions' import { Handler } from '@netlify/functions'
import { Octokit } from '@octokit/core' import { Octokit } from '@octokit/core'
import { GithubInfo } from '../../src/components/Github'
const handler: Handler = async (event, context) => { const handler: Handler = async (event, context) => {
let octokit = new Octokit({auth: process.env.API_GITHUB}) let octokit = new Octokit({auth: process.env.API_GITHUB})
@ -20,7 +21,7 @@ const handler: Handler = async (event, context) => {
} }
} }
let info = { let info: GithubInfo = {
public: { public: {
repo: public_push.repo.name, repo: public_push.repo.name,
date: public_push.created_at.substring(0, public_push.created_at.indexOf("T")) date: public_push.created_at.substring(0, public_push.created_at.indexOf("T"))

View file

@ -1,5 +1,6 @@
import { Handler } from '@netlify/functions' import { Handler } from '@netlify/functions'
import fetch from "node-fetch" import fetch from "node-fetch"
import { GitlabInfo } from '../../src/components/Gitlab'
const handler: Handler = async (event, context) => { const handler: Handler = async (event, context) => {
let gitlab = await fetch("https://gitlab.com/api/v4/events?action=pushed", { let gitlab = await fetch("https://gitlab.com/api/v4/events?action=pushed", {
@ -19,11 +20,13 @@ const handler: Handler = async (event, context) => {
} }
let json = await gitlab.json() as {[key: string]: any} let json = await gitlab.json() as {[key: string]: any}
let date = json[0].created_at.substring(0, json[0].created_at.indexOf("T")) let activity: GitlabInfo = {
date: json[0].created_at.substring(0, json[0].created_at.indexOf("T"))
}
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify({date}) body: JSON.stringify(activity)
} }
} }

View file

@ -1,8 +1,9 @@
import { Handler } from '@netlify/functions' import { Handler } from '@netlify/functions'
import { api } from "./shared/api" import { api } from "./shared/api"
import { HacktheboxInfo } from '../../src/components/Hackthebox'
const handler: Handler = async (event, context) => { const handler: Handler = async (event, context) => {
let hackthebox = await api<{ let hackthebox: {profile: {activity: HacktheboxInfo[]}} = await api<{
profile: { profile: {
activity: { activity: {
id: string id: string
@ -16,7 +17,7 @@ const handler: Handler = async (event, context) => {
}> }>
(`https://www.hackthebox.com/api/v4/profile/activity/1063999`) (`https://www.hackthebox.com/api/v4/profile/activity/1063999`)
let pwn = hackthebox.profile.activity.find((a) => a.object_type === "machine") let pwn = hackthebox.profile.activity.find((a: HacktheboxInfo) => a!.object_type === "machine")
if (!pwn) { if (!pwn) {
return { return {
statusCode: 404, statusCode: 404,

View file

@ -1,5 +1,6 @@
import { Handler } from '@netlify/functions' import { Handler } from '@netlify/functions'
import { API, APIError, User } from 'osu-api-v2-js' import { API, APIError, User } from 'osu-api-v2-js'
import { OsuInfo } from '../../src/components/Osu'
const handler: Handler = async (event, context) => { const handler: Handler = async (event, context) => {
let api = await API.createAsync({id: 11451, secret: process.env.API_OSU!}) let api = await API.createAsync({id: 11451, secret: process.env.API_OSU!})
@ -24,7 +25,7 @@ const handler: Handler = async (event, context) => {
} }
} }
let ranks = { let ranks: OsuInfo = {
osu: [0,0], osu: [0,0],
taiko: [0,0], taiko: [0,0],
fruits: [0,0], fruits: [0,0],

BIN
public/mode-fruits.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/mode-mania.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
public/mode-osu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/mode-taiko.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -50,7 +50,8 @@ body {
writing-mode: vertical-rl; writing-mode: vertical-rl;
} }
.info > * { .info canvas {
padding: 3px 10px; height: 110px !important;
margin: auto; width: 220px !important;
margin: 0;
} }

View file

@ -3,11 +3,11 @@ import "./App.css";
import Lastfm from "./components/Lastfm"; import Lastfm from "./components/Lastfm";
import Speedruncom from "./components/Speedruncom"; import Speedruncom from "./components/Speedruncom";
import Hackthebox from "./components/hackthebox"; import Hackthebox from "./components/Hackthebox";
import Github from "./components/github"; import Github from "./components/Github";
import Gitlab from "./components/gitlab"; import Gitlab from "./components/Gitlab";
import Osu from "./components/osu"; import Osu from "./components/Osu";
import Anilist from "./components/anilist"; import Anilist from "./components/Anilist";
function App() { function App() {
return ( return (
@ -16,10 +16,10 @@ function App() {
<div className="info_container"> <div className="info_container">
<Lastfm/> <Lastfm/>
<Speedruncom/> <Speedruncom/>
<Osu/>
{/* <Hackthebox/> {/* <Hackthebox/>
<Github/> <Github/>
<Gitlab/> <Gitlab/>
<Osu/>
<Anilist/> */} <Anilist/> */}
</div> </div>
</div> </div>

View file

@ -1,7 +1,20 @@
import { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
export type AnilistInfo = {
title: string
episodes: {
watched: number
total: number
},
score: number
startDate: string
updateDate: string
endDate: string
cover: string
} | undefined
export default function Anilist() { export default function Anilist() {
const [anilist, setAnilist] = useState({}) const [anilist, setAnilist]: [AnilistInfo, React.Dispatch<React.SetStateAction<AnilistInfo>>] = useState()
const getAnilist = async () => { const getAnilist = async () => {
const response = await fetch("/.netlify/functions/anilist").then(r => r.json()) const response = await fetch("/.netlify/functions/anilist").then(r => r.json())
setAnilist(response) setAnilist(response)
@ -11,7 +24,7 @@ export default function Anilist() {
getAnilist() getAnilist()
}, []) }, [])
if (anilist.title === undefined) { if (anilist === undefined) {
return <></> return <></>
} }
return ( return (

View file

@ -1,7 +1,17 @@
import { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
export type GithubInfo = {
public: {
repo: string
date: string
}
private: {
date: string
}
} | undefined
export default function Github() { export default function Github() {
const [github, setGithub] = useState({}) const [github, setGithub]: [GithubInfo, React.Dispatch<React.SetStateAction<GithubInfo>>] = useState()
const getGithub = async () => { const getGithub = async () => {
const response = await fetch("/.netlify/functions/github").then(r => r.json()) const response = await fetch("/.netlify/functions/github").then(r => r.json())
setGithub(response) setGithub(response)
@ -11,7 +21,7 @@ export default function Github() {
getGithub() getGithub()
}, []) }, [])
if (github.public === undefined || github.public.date === undefined) { if (github === undefined) {
return <></> return <></>
} }
return ( return (

View file

@ -1,7 +1,11 @@
import { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
export type GitlabInfo = {
date: string
} | undefined
export default function Gitlab() { export default function Gitlab() {
const [gitlab, setGitlab] = useState({}) const [gitlab, setGitlab]: [GitlabInfo, React.Dispatch<React.SetStateAction<GitlabInfo>>] = useState()
const getGitlab = async () => { const getGitlab = async () => {
const response = await fetch("/.netlify/functions/gitlab").then(r => r.json()) const response = await fetch("/.netlify/functions/gitlab").then(r => r.json())
setGitlab(response) setGitlab(response)
@ -11,7 +15,7 @@ export default function Gitlab() {
getGitlab() getGitlab()
}, []) }, [])
if (gitlab.date === undefined) { if (gitlab === undefined) {
return <></> return <></>
} }
return ( return (

View file

@ -1,7 +1,16 @@
import { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
export type HacktheboxInfo = {
id: string
date_diff: string
object_type: string
type: string
name: string
machine_avatar: string
} | undefined
export default function Hackthebox() { export default function Hackthebox() {
const [hackthebox, setHackthebox] = useState({}) const [hackthebox, setHackthebox]: [HacktheboxInfo, React.Dispatch<React.SetStateAction<HacktheboxInfo>>] = useState()
const getHackthebox = async () => { const getHackthebox = async () => {
const response = await fetch("/.netlify/functions/hackthebox").then(r => r.json()) const response = await fetch("/.netlify/functions/hackthebox").then(r => r.json())
setHackthebox(response) setHackthebox(response)
@ -11,7 +20,7 @@ export default function Hackthebox() {
getHackthebox() getHackthebox()
}, []) }, [])
if (hackthebox.name === undefined) { if (hackthebox === undefined) {
return <></> return <></>
} }

126
src/components/Osu.tsx Normal file
View file

@ -0,0 +1,126 @@
import React, { useState, useEffect } from "react";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
import { Line } from 'react-chartjs-2';
import Info from "./structures/info";
import "../style/osu.css"
export type OsuInfo = {
osu: number[]
taiko: number[]
fruits: number[]
mania: number[]
} | undefined
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
export default function Osu() {
const [osu, setOsu]: [OsuInfo, React.Dispatch<React.SetStateAction<OsuInfo>>] = useState()
const getOsu = async () => {
const response = await fetch("/.netlify/functions/osu").then(r => r.json())
setOsu(response)
}
useEffect(() => {
getOsu()
}, [])
if (osu === undefined) {
return <></>
}
function shapeData(ranks: number[]) {
let labels = ranks.map((r, i) => `${i + 1} days ago`).reverse()
return {
labels,
datasets: [{
id: 1,
label: "",
data: ranks,
borderColor: `rgb(
${String(ranks[0]).slice(-2)},
${String(ranks[ranks.length/2]).slice(-2)},
${String(ranks[ranks.length-1]).slice(-2)}
)`,
tension: 0.5,
fill: false,
pointStyle: false as false
}]
}
}
let options = {
scales: {
y: {
reverse: true,
}
},
plugins: {
legend: {
display: false
}
}
}
return (
<Info
title="osu!"
link="https://osu.ppy.sh/users/7276846"
description="Rhythm games"
elements={[
<div>
<a href="https://osu.ppy.sh/users/7276846/osu" target="_blank" className="gamemode-title">
<img src="mode-osu.png"></img>
<h2><strong>osu!</strong></h2>
</a>
<div className="bg-white">
<Line datasetIdKey="1" data={shapeData(osu.osu)} options={options}/>
</div>
</div>,
<div className="mt-6">
<a href="https://osu.ppy.sh/users/7276846/taiko" target="_blank" className="gamemode-title">
<img src="mode-taiko.png"></img>
<h2>osu!<strong>taiko</strong></h2>
</a>
<div className="bg-white">
<Line datasetIdKey="1" data={shapeData(osu.taiko)} options={options}/>
</div>
</div>,
<div className="mt-6">
<a href="https://osu.ppy.sh/users/7276846/fruits" target="_blank" className="gamemode-title">
<img src="mode-fruits.png"></img>
<h2>osu!<strong>catch</strong></h2>
</a>
<div className="bg-white">
<Line datasetIdKey="1" data={shapeData(osu.fruits)} options={options}/>
</div>
</div>,
<div className="mt-6">
<a href="https://osu.ppy.sh/users/7276846/mania" target="_blank" className="gamemode-title">
<img src="mode-mania.png"></img>
<h2>osu!<strong>mania</strong></h2>
</a>
<div className="bg-white">
<Line datasetIdKey="1" data={shapeData(osu.mania)} options={options}/>
</div>
</div>
]}
/>
)
}

View file

@ -1,81 +0,0 @@
import { useState, useEffect } from "react";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
scales,
} from 'chart.js';
import { Line } from 'react-chartjs-2';
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
export default function Osu() {
const [osu, setOsu] = useState({})
const getOsu = async () => {
const response = await fetch("/.netlify/functions/osu").then(r => r.json())
setOsu(response)
}
useEffect(() => {
getOsu()
}, [])
if (osu.osu === undefined) {
return <></>
}
function shapeData(ranks) {
let labels = ranks.map((r, i) => `${i + 1} days ago`).reverse()
return {
labels,
datasets: [{
id: 1,
label: "",
data: ranks,
borderColor: `rgb(
${String(ranks[0]).slice(-2)},
${String(ranks[ranks.length/2]).slice(-2)},
${String(ranks[ranks.length-1]).slice(-2)}
)`,
tension: 0.5,
fill: false,
pointStyle: false
}]
}
}
let options = {
scales: {
y: {
reverse: true,
}
},
plugins: {
legend: {
display: false
}
}
}
return (
<div id="osu">
<Line datasetIdKey="1" data={shapeData(osu.osu)} options={options}/>
<Line datasetIdKey="1" data={shapeData(osu.taiko)} options={options}/>
<Line datasetIdKey="1" data={shapeData(osu.fruits)} options={options}/>
<Line datasetIdKey="1" data={shapeData(osu.mania)} options={options}/>
</div>
)
}

View file

@ -0,0 +1,23 @@
.gamemode-title {
display: flex;
margin: auto;
margin-bottom: 6px;
width: fit-content;
}
.gamemode-title img {
height: 64px;
width: 64px;
}
.gamemode-title h2 {
margin-top: auto;
margin-bottom: auto;
font-size: 24px;
padding-bottom: 0.4rem;
}
.gamemode-title > * {
margin-left: 6px;
margin-right: 6px;
}