mirror of
https://github.com/pmret/website.git
synced 2024-11-08 12:12:27 +01:00
Merge branch 'party' into main
This commit is contained in:
commit
7052cb5b08
@ -1,10 +1,6 @@
|
|||||||
import React, { useState, useEffect } from "react"
|
import React, { useState, useEffect, useMemo } from "react"
|
||||||
import { createPortal } from "react-dom"
|
import { createPortal } from "react-dom"
|
||||||
import { Area, XAxis, YAxis, AreaChart, CartesianGrid, Tooltip, ResponsiveContainer } from "recharts"
|
import { Area, XAxis, YAxis, AreaChart, CartesianGrid, Tooltip, ResponsiveContainer, Text } from "recharts"
|
||||||
import { scalePow } from "d3-scale"
|
|
||||||
|
|
||||||
const scale = scalePow()
|
|
||||||
.exponent(30)
|
|
||||||
|
|
||||||
const csvVersions = {
|
const csvVersions = {
|
||||||
"1": {
|
"1": {
|
||||||
@ -45,7 +41,7 @@ async function fetchData(version) {
|
|||||||
|
|
||||||
const latest = rows[rows.length - 1]
|
const latest = rows[rows.length - 1]
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
row.percentBytes = (row.matchingBytes / latest.totalBytes) * 100
|
row.percentBytes = (row.matchingBytes / latest.totalBytes) * 100
|
||||||
}
|
}
|
||||||
|
|
||||||
return rows
|
return rows
|
||||||
@ -67,17 +63,6 @@ export default function ProgressPane({ captionPortal, nonce, color, version }) {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const monthDates = []
|
|
||||||
{
|
|
||||||
let date = new Date(2020, 3, 1)
|
|
||||||
while (date < Date.now()) {
|
|
||||||
monthDates.push(date / 1000)
|
|
||||||
|
|
||||||
date = new Date(date) // clone
|
|
||||||
date.setMonth(date.getMonth() + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function DataView({ data, captionPortal, nonce, color }) {
|
function DataView({ data, captionPortal, nonce, color }) {
|
||||||
const latest = data[data.length - 1]
|
const latest = data[data.length - 1]
|
||||||
const oldest = data[0]
|
const oldest = data[0]
|
||||||
@ -85,6 +70,10 @@ function DataView({ data, captionPortal, nonce, color }) {
|
|||||||
|
|
||||||
const [selectedEntry, setSelectedEntry] = useState(latest)
|
const [selectedEntry, setSelectedEntry] = useState(latest)
|
||||||
|
|
||||||
|
if (!selectedEntry && latest) {
|
||||||
|
setSelectedEntry(latest)
|
||||||
|
}
|
||||||
|
|
||||||
function renderTooltip(tip) {
|
function renderTooltip(tip) {
|
||||||
const entry = data.find(row => row.timestamp === tip.label)
|
const entry = data.find(row => row.timestamp === tip.label)
|
||||||
|
|
||||||
@ -97,13 +86,31 @@ function DataView({ data, captionPortal, nonce, color }) {
|
|||||||
|
|
||||||
const maxPercent = latest ? Math.ceil(latest.percentBytes / 25) * 25 : 25
|
const maxPercent = latest ? Math.ceil(latest.percentBytes / 25) * 25 : 25
|
||||||
|
|
||||||
|
const monthDates = useMemo(() => {
|
||||||
|
const monthDates = []
|
||||||
|
|
||||||
|
if (oldest) {
|
||||||
|
let date = new Date(oldest.timestamp * 1000)
|
||||||
|
date.setDate(0)
|
||||||
|
|
||||||
|
while (date < Date.now()) {
|
||||||
|
monthDates.push(date / 1000)
|
||||||
|
|
||||||
|
date = new Date(date) // clone
|
||||||
|
date.setMonth(date.getMonth() + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return monthDates
|
||||||
|
}
|
||||||
|
}, [oldest && oldest.timestamp])
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className="shadow-box flex-grow">
|
<div className="shadow-box flex-grow">
|
||||||
<div className="shadow-box-inner" style={{ paddingRight: ".7em", paddingTop: ".7em", "--text-outline": "transparent", background: "#e2e1d8" }}>
|
<div className="shadow-box-inner" style={{ paddingRight: ".7em", paddingTop: ".7em", "--text-outline": "transparent", background: "#e2e1d8" }}>
|
||||||
<div className="progress-chart">
|
<div className="progress-chart">
|
||||||
<ResponsiveContainer>
|
<ResponsiveContainer>
|
||||||
<AreaChart data={data}>
|
<AreaChart data={data}>
|
||||||
<XAxis dataKey="timestamp" type="number" scale={scale} domain={["dataMin", Date.now()/1000]} ticks={monthDates} tickFormatter={formatTimestampMonth} interval={0}/>
|
<XAxis dataKey="timestamp" type="number" scale="linear" domain={["dataMin", Date.now()/1000]} ticks={monthDates} tickFormatter={formatTimestampMonth}/>
|
||||||
<YAxis type="number" unit="%" domain={[0, maxPercent]} tickCount={maxPercent / 5 + 1}/>
|
<YAxis type="number" unit="%" domain={[0, maxPercent]} tickCount={maxPercent / 5 + 1}/>
|
||||||
|
|
||||||
<CartesianGrid stroke="#d9d0c9"/>
|
<CartesianGrid stroke="#d9d0c9"/>
|
||||||
@ -122,6 +129,9 @@ function DataView({ data, captionPortal, nonce, color }) {
|
|||||||
</AreaChart>
|
</AreaChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
|
{latest && <div className="progress-percent" title="Latest matched percentage">
|
||||||
|
{formatPercent(latest.percentBytes)}
|
||||||
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button className={"shadow-box-title " + color}>
|
<button className={"shadow-box-title " + color}>
|
||||||
@ -144,15 +154,16 @@ function formatTimestamp(timestamp, options={}) {
|
|||||||
|
|
||||||
function formatTimestampMonth(timestamp) {
|
function formatTimestampMonth(timestamp) {
|
||||||
const date = new Date(timestamp * 1000)
|
const date = new Date(timestamp * 1000)
|
||||||
const [day, month, year] = new Intl.DateTimeFormat("en-GB", {
|
|
||||||
dateStyle: "medium",
|
|
||||||
}).format(date).split(" ")
|
|
||||||
|
|
||||||
if (month === "Jan") {
|
if (date.getMonth() == 0) {
|
||||||
return year
|
return date.getFullYear().toString()
|
||||||
|
} else {
|
||||||
|
return new Intl.DateTimeFormat([], { month: "short" }).format(date)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return month
|
function formatPercent(alpha) {
|
||||||
|
return Math.round(alpha * 100) / 100 + "%"
|
||||||
}
|
}
|
||||||
|
|
||||||
function EntryInfo({ entry, isLatest }) {
|
function EntryInfo({ entry, isLatest }) {
|
||||||
@ -170,17 +181,12 @@ function EntryInfo({ entry, isLatest }) {
|
|||||||
<a href={`https://github.com/pmret/papermario/commit/${entry.commit}`}>
|
<a href={`https://github.com/pmret/papermario/commit/${entry.commit}`}>
|
||||||
{entry.commit.substr(0, 8)}
|
{entry.commit.substr(0, 8)}
|
||||||
</a>
|
</a>
|
||||||
{isLatest && " (latest)"}
|
{isLatest && " (latest commit)"}
|
||||||
<table>
|
|
||||||
<tbody>
|
<br/>
|
||||||
<tr>
|
|
||||||
<td width="200">Matched</td>
|
<span className="thin">
|
||||||
<td className="thin align-right">
|
Matched {formatPercent(entry.percentBytes)} bytes ({entry.matchingFuncs}/{entry.totalFuncs} functions)
|
||||||
{Math.round(entry.percentBytes * 100) / 100}% bytes
|
</span>
|
||||||
({entry.matchingFuncs}/{entry.totalFuncs} functions)
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ html {
|
|||||||
--dark: #313131;
|
--dark: #313131;
|
||||||
--light: #d6d6ce;
|
--light: #d6d6ce;
|
||||||
|
|
||||||
font-size: 32px;
|
font-size: 21px;
|
||||||
|
font-size: clamp(21px, 1.5vw, 32px);
|
||||||
font-family: "Paper Mario Dialog Redesigned", sans-serif;
|
font-family: "Paper Mario Dialog Redesigned", sans-serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
@ -32,6 +33,13 @@ body {
|
|||||||
background-repeat: repeat-x;
|
background-repeat: repeat-x;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
animation: clouds linear 30s infinite normal;
|
animation: clouds linear 30s infinite normal;
|
||||||
|
|
||||||
|
/* centre children */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
padding: 1vw 1vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes clouds {
|
@keyframes clouds {
|
||||||
@ -55,13 +63,13 @@ p {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:any-link {
|
a:any-link:not(.tab) {
|
||||||
color: #3796ff;
|
color: #3796ff;
|
||||||
--text-outline: #d3e5f9;
|
--text-outline: #d3e5f9;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button, .tab {
|
||||||
all: unset;
|
all: unset;
|
||||||
|
|
||||||
border-radius: 100em;
|
border-radius: 100em;
|
||||||
@ -80,9 +88,11 @@ button {
|
|||||||
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
color: var(--light);
|
||||||
}
|
}
|
||||||
|
|
||||||
button.red {
|
button.red, .tab.red {
|
||||||
border-top-color: #f04e54;
|
border-top-color: #f04e54;
|
||||||
border-left-color: #f04e54;
|
border-left-color: #f04e54;
|
||||||
background: #b4313e;
|
background: #b4313e;
|
||||||
@ -90,7 +100,7 @@ button.red {
|
|||||||
border-right-color: #7f1729;
|
border-right-color: #7f1729;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.yellow {
|
button.yellow, .tab.yellow {
|
||||||
border-top-color: #f0c74e;
|
border-top-color: #f0c74e;
|
||||||
border-left-color: #f0c74e;
|
border-left-color: #f0c74e;
|
||||||
background: #b48b31;
|
background: #b48b31;
|
||||||
@ -98,7 +108,7 @@ button.yellow {
|
|||||||
border-right-color: #7f5617;
|
border-right-color: #7f5617;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.blurple {
|
button.blurple, .tab.blurple {
|
||||||
border-top-color: #98a9e2;
|
border-top-color: #98a9e2;
|
||||||
border-left-color: #98a9e2;
|
border-left-color: #98a9e2;
|
||||||
background: #7289da;
|
background: #7289da;
|
||||||
@ -106,7 +116,7 @@ button.blurple {
|
|||||||
border-right-color: #4E5D94;
|
border-right-color: #4E5D94;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.github {
|
button.github, .tab.github {
|
||||||
border-top-color: #554e4e;
|
border-top-color: #554e4e;
|
||||||
border-left-color: #554e4e;
|
border-left-color: #554e4e;
|
||||||
background: #322f2f;
|
background: #322f2f;
|
||||||
@ -114,7 +124,7 @@ button.github {
|
|||||||
border-right-color: #171515;
|
border-right-color: #171515;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.teal {
|
button.teal, .tab.teal {
|
||||||
border-top-color: #22eec9;
|
border-top-color: #22eec9;
|
||||||
border-left-color: #22eec9;
|
border-left-color: #22eec9;
|
||||||
background: #14a98e;
|
background: #14a98e;
|
||||||
@ -122,7 +132,7 @@ button.teal {
|
|||||||
border-right-color: #076d5a;
|
border-right-color: #076d5a;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.green {
|
button.green, .tab.green {
|
||||||
border-top-color: #68ff51;
|
border-top-color: #68ff51;
|
||||||
border-left-color: #68ff51;
|
border-left-color: #68ff51;
|
||||||
background: #47b836;
|
background: #47b836;
|
||||||
@ -130,11 +140,11 @@ button.green {
|
|||||||
border-right-color: #2a791e;
|
border-right-color: #2a791e;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.inactive {
|
button.inactive, .tab.inactive {
|
||||||
filter: brightness(0.6);
|
filter: brightness(0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover {
|
button:hover, .tab:hover {
|
||||||
filter: brightness(1.0);
|
filter: brightness(1.0);
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
@ -142,29 +152,40 @@ button:hover {
|
|||||||
.tab {
|
.tab {
|
||||||
margin-right: .25em;
|
margin-right: .25em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
/* TODO: use flex on body */
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
width: 80%;
|
width: 100%;
|
||||||
max-width: 95%;
|
max-width: 1600px;
|
||||||
height: 80%;
|
height: 100%;
|
||||||
max-height: 950%;
|
max-height: 1100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 2100px) {
|
||||||
|
#container {
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 90%;
|
||||||
|
|
||||||
|
width: max(80vw, calc(80vh * 16/11));
|
||||||
|
height: max(calc(80vw * 11/16), 80vh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
margin-bottom: -.6em;
|
margin-bottom: -.6em;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
width: 95%;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
nav {
|
||||||
|
margin-left: 48px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -195,6 +216,14 @@ main {
|
|||||||
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
main {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
main > :last-child {
|
main > :last-child {
|
||||||
padding-bottom: 1.5em;
|
padding-bottom: 1.5em;
|
||||||
}
|
}
|
||||||
@ -251,6 +280,14 @@ main > * {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
.shadow-box {
|
||||||
|
padding: .5em;
|
||||||
|
margin: .3em;
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.shadow-box-inner {
|
.shadow-box-inner {
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: inset .4em .4em rgba(0, 0, 0, 0.15);
|
box-shadow: inset .4em .4em rgba(0, 0, 0, 0.15);
|
||||||
@ -264,6 +301,7 @@ main > * {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
background: white;
|
background: white;
|
||||||
@ -275,7 +313,8 @@ button.shadow-box-title {
|
|||||||
bottom: -1em;
|
bottom: -1em;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
|
|
||||||
width: 60%;
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
@ -300,7 +339,7 @@ button.shadow-box-title {
|
|||||||
|
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
width: 85%;
|
width: 85%;
|
||||||
height: 4rem;
|
min-height: 4rem;
|
||||||
|
|
||||||
padding: .5em 1em;
|
padding: .5em 1em;
|
||||||
margin-top: -2em;
|
margin-top: -2em;
|
||||||
@ -312,13 +351,23 @@ button.shadow-box-title {
|
|||||||
.progress-chart {
|
.progress-chart {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
font-size: 18px;
|
font-size: 14px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.progress-percent {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
font-size: max(48px, 10vw);
|
||||||
|
color: rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
.outline-invert {
|
.outline-invert {
|
||||||
color: var(--dark);
|
color: var(--dark);
|
||||||
--text-outline: var(--light);
|
--text-outline: var(--light);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width"/>
|
||||||
<title>Paper Mario Decompilation</title>
|
<title>Paper Mario Decompilation</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="index.css"/>
|
<link rel="stylesheet" href="index.css"/>
|
||||||
|
21
src/main.jsx
21
src/main.jsx
@ -77,22 +77,27 @@ function App() {
|
|||||||
return <>
|
return <>
|
||||||
<nav>
|
<nav>
|
||||||
{tabs.map((tab, index) => {
|
{tabs.map((tab, index) => {
|
||||||
return <button
|
return <a
|
||||||
key={tab.name}
|
key={tab.name}
|
||||||
className={clsx("tab", tab.color, { "inactive": index !== tabIndex })}
|
className={clsx("tab", tab.color, { "inactive": index !== tabIndex })}
|
||||||
onClick={() => {
|
href={tab.slug}
|
||||||
switchToTab(index, true)
|
onClick={evt => {
|
||||||
|
const q = window.matchMedia("(prefers-reduced-motion: reduce)")
|
||||||
|
if (!q.matches) {
|
||||||
|
switchToTab(index, true)
|
||||||
|
evt.preventDefault()
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{tab.name}
|
{tab.name}
|
||||||
</button>
|
</a>
|
||||||
})}
|
})}
|
||||||
<button className="tab blurple inactive" onClick={() => window.open("https://discord.gg/urUm3VG")}>
|
<a className="tab blurple inactive" href="https://discord.gg/urUm3VG">
|
||||||
Discord
|
Discord
|
||||||
</button>
|
</a>
|
||||||
<button className="tab github inactive" onClick={() => window.open("https://github.com/pmret/papermario")}>
|
<a className="tab github inactive" href="https://github.com/pmret/papermario">
|
||||||
GitHub
|
GitHub
|
||||||
</button>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
<main id="main" ref={pane} className={clsx(tabs[paneIndex].color)} style={{
|
<main id="main" ref={pane} className={clsx(tabs[paneIndex].color)} style={{
|
||||||
transform: `perspective(4000px) rotateX(${rotation}deg)`,
|
transform: `perspective(4000px) rotateX(${rotation}deg)`,
|
||||||
|
Loading…
Reference in New Issue
Block a user