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 fetch from "node-fetch"
import { AnilistInfo } from '../../src/components/Anilist'
const handler: Handler = async (event, context) => {
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 json = p_json.data.MediaList
let anime = {
let anime: AnilistInfo = {
title: json.media.title.romaji,
episodes: {
watched: json.progress,

View file

@ -1,5 +1,6 @@
import { Handler } from '@netlify/functions'
import { Octokit } from '@octokit/core'
import { GithubInfo } from '../../src/components/Github'
const handler: Handler = async (event, context) => {
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: {
repo: public_push.repo.name,
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 fetch from "node-fetch"
import { GitlabInfo } from '../../src/components/Gitlab'
const handler: Handler = async (event, context) => {
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 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 {
statusCode: 200,
body: JSON.stringify({date})
body: JSON.stringify(activity)
}
}

View file

@ -1,8 +1,9 @@
import { Handler } from '@netlify/functions'
import { api } from "./shared/api"
import { HacktheboxInfo } from '../../src/components/Hackthebox'
const handler: Handler = async (event, context) => {
let hackthebox = await api<{
let hackthebox: {profile: {activity: HacktheboxInfo[]}} = await api<{
profile: {
activity: {
id: string
@ -16,7 +17,7 @@ const handler: Handler = async (event, context) => {
}>
(`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) {
return {
statusCode: 404,

View file

@ -1,5 +1,6 @@
import { Handler } from '@netlify/functions'
import { API, APIError, User } from 'osu-api-v2-js'
import { OsuInfo } from '../../src/components/Osu'
const handler: Handler = async (event, context) => {
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],
taiko: [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;
}
.info > * {
padding: 3px 10px;
margin: auto;
.info canvas {
height: 110px !important;
width: 220px !important;
margin: 0;
}

View file

@ -3,11 +3,11 @@ import "./App.css";
import Lastfm from "./components/Lastfm";
import Speedruncom from "./components/Speedruncom";
import Hackthebox from "./components/hackthebox";
import Github from "./components/github";
import Gitlab from "./components/gitlab";
import Osu from "./components/osu";
import Anilist from "./components/anilist";
import Hackthebox from "./components/Hackthebox";
import Github from "./components/Github";
import Gitlab from "./components/Gitlab";
import Osu from "./components/Osu";
import Anilist from "./components/Anilist";
function App() {
return (
@ -16,10 +16,10 @@ function App() {
<div className="info_container">
<Lastfm/>
<Speedruncom/>
<Osu/>
{/* <Hackthebox/>
<Github/>
<Gitlab/>
<Osu/>
<Anilist/> */}
</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() {
const [anilist, setAnilist] = useState({})
const [anilist, setAnilist]: [AnilistInfo, React.Dispatch<React.SetStateAction<AnilistInfo>>] = useState()
const getAnilist = async () => {
const response = await fetch("/.netlify/functions/anilist").then(r => r.json())
setAnilist(response)
@ -11,7 +24,7 @@ export default function Anilist() {
getAnilist()
}, [])
if (anilist.title === undefined) {
if (anilist === undefined) {
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() {
const [github, setGithub] = useState({})
const [github, setGithub]: [GithubInfo, React.Dispatch<React.SetStateAction<GithubInfo>>] = useState()
const getGithub = async () => {
const response = await fetch("/.netlify/functions/github").then(r => r.json())
setGithub(response)
@ -11,7 +21,7 @@ export default function Github() {
getGithub()
}, [])
if (github.public === undefined || github.public.date === undefined) {
if (github === undefined) {
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() {
const [gitlab, setGitlab] = useState({})
const [gitlab, setGitlab]: [GitlabInfo, React.Dispatch<React.SetStateAction<GitlabInfo>>] = useState()
const getGitlab = async () => {
const response = await fetch("/.netlify/functions/gitlab").then(r => r.json())
setGitlab(response)
@ -11,7 +15,7 @@ export default function Gitlab() {
getGitlab()
}, [])
if (gitlab.date === undefined) {
if (gitlab === undefined) {
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() {
const [hackthebox, setHackthebox] = useState({})
const [hackthebox, setHackthebox]: [HacktheboxInfo, React.Dispatch<React.SetStateAction<HacktheboxInfo>>] = useState()
const getHackthebox = async () => {
const response = await fetch("/.netlify/functions/hackthebox").then(r => r.json())
setHackthebox(response)
@ -11,7 +20,7 @@ export default function Hackthebox() {
getHackthebox()
}, [])
if (hackthebox.name === undefined) {
if (hackthebox === undefined) {
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;
}