css needs maybe a lot or little work still because it's still wonky but the base of what we wanted is here

This commit is contained in:
taah 2022-06-19 11:33:14 -07:00
parent 43ec1192bd
commit 1e13a01ef6
20 changed files with 381 additions and 136 deletions

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -10,8 +10,12 @@
"@types/node": "^16.11.41",
"@types/react": "^18.0.14",
"@types/react-dom": "^18.0.5",
"axios": "^0.27.2",
"bootstrap": "^5.1.3",
"react": "^18.2.0",
"react-bootstrap": "^2.4.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4"

View File

@ -1,20 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<head>
<meta charset="utf-8"/>
<!-- <link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>-->
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#000000"/>
<meta
name="description"
content="Web site created using create-react-app"
name="description"
content="The official website for the minecraft server software, Scissors, which aims to patch creative mode exploits"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>-->
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
crossorigin="anonymous"
/>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
@ -24,20 +30,20 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
<title>Scissors</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@ -1,9 +0,0 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@ -1,26 +1,28 @@
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter, Route, Routes } from "react-router-dom";
import HomePage from "./pages/HomePage";
import { Button, Nav, Navbar, NavLink } from "react-bootstrap";
import "./css/App.css"
import DownloadPage from "./pages/DownloadPage";
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
return (
<BrowserRouter>
<Navbar bg={"dark"} variant={"dark"}>
<Navbar.Brand className={"ms-5"} href={"/"}>SCISSORS</Navbar.Brand>
<Nav className={"me-auto"}>
<NavLink href={"https://github.com/AtlasMediaGroup/Scissors"}>Source</NavLink>
<NavLink href={"https://status.scissors.gg"}>Status</NavLink>
</Nav>
<Button variant={"light"} className={"me-5 download-button"} href={"/downloads"} style={{borderRadius: "2vh"}}><img src={"https://cdn3.iconfinder.com/data/icons/download-buttons-outline-collection/70/Download-13-512.png"} width={"50px"} alt={"download"}/> DOWNLOAD</Button>
</Navbar>
<Routes>
<Route path={"/"} element={<HomePage/>}/>
<Route path={"/downloads"} element={<DownloadPage/>}/>
</Routes>
</BrowserRouter>
);
}
export default App;

26
src/css/App.css Normal file
View File

@ -0,0 +1,26 @@
@import url('https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap');
.navbar-brand {
font-family: 'Permanent Marker', cursive;
}
@media only screen and (max-width: 768px) {
.download-button {
height: 7vh;
font-size: 3vw;
}
.download-button > img {
width: 25px;
}
.navbar-brand {
position: relative;
right: 5vw;
}
.navbar-nav {
position: relative;
right: 5vw;
}
}

103
src/css/DownloadPage.css Normal file
View File

@ -0,0 +1,103 @@
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@200&display=swap');
body {
margin: 0;
}
ul > li {
color: white;
}
ul {
list-style-type: none;
flex-direction: row;
justify-content: space-around;
display: flex;
}
.builds {
padding: 0;
margin: 0;
background-color: #363534;
}
.builds {
flex-direction: column;
}
.builds > li {
padding-left: 1vw;
height: 10vh;
width: 100%;
border-bottom: 2px solid black;
display: table;
flex-wrap: nowrap;
}
.builds > li > .btn {
border-radius: 1vh !important;
position: relative;
top: 3vh;
}
.selected {
border-bottom: aqua 1px solid;
}
.selectable {
cursor: pointer;
}
ul[class^="changes-"] {
justify-content: left;
flex-direction: column;
margin: 0;
flex-wrap: nowrap;
align-content: flex-start;
}
ul[class^="changes-"] > li {
flex-wrap: nowrap;
margin: 0;
padding: 0;
font-size: 0.75vw;
position: relative;
bottom: 1vh;
left: 2vw;
width: 50%;
}
ul[class^="changes-"] > li > a {
text-decoration: none;
color: #91ffaf;
margin: 0;
}
.date {
display: table-cell;
float: right;
right: 10vw;
position: relative;
bottom: 2.5vh;
}
.nochanges {
position: relative;
bottom: 0;
}
@media only screen and (max-width: 768px) {
ul[class^="changes-"] > li {
position: relative;
left: 5vw;
font-size: 3vw;
}
.date {
bottom: 3.75vh;
}
.nochanges {
bottom: 1vh;
}
}

35
src/css/HomePage.css Normal file
View File

@ -0,0 +1,35 @@
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@200&display=swap');
body {
background-color: #262626;
}
h1, h4, h5 {
color: white;
text-align: center;
position: relative;
font-family: 'IBM Plex Sans', sans-serif;
}
h1 {
top: 10vh;
font-weight: bolder;
}
h4 {
top: 10vh;
}
.download-button:hover {
transition: all 0.25s ease;
background-color: #c7c7c7 !important;
}
@media only screen and (max-width: 768px) {
h1 {
font-size: 7vw;
}
h4 {
font-size: 5vw;
}
}

View File

@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@ -1,19 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
<App/>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,65 @@
import React, { Fragment, useEffect, useState } from "react";
import "../css/HomePage.css"
import { Build, getBuilds, getJobs, Job } from "../util/Jenkins";
import "../css/DownloadPage.css"
import { Button } from "react-bootstrap";
const DownloadPage = () => {
const [ jobs, setJobs ] = useState(new Map<Job, Build[]>())
const [ version, setVersion ] = useState("")
useEffect(() => {
doJobs().then(value => {
})
}, [])
function doJobs(): Promise<void> {
return new Promise(resolve => {
getJobs().then(value => {
for (let job of value) {
getBuilds(job.name).then(value1 => {
setJobs(prevState => {
let map = new Map<Job, Build[]>([ ...prevState, [ job, value1 ] ])
if (map.size >= value.length) {
let job = Array.from(map.keys()).sort((a, b) => parseFloat(a.name) - parseFloat(b.name)).reverse()[0]
setVersion(job.name)
}
return new Map<Job, Build[]>([ ...map.entries() ].sort((a, b) => parseFloat(a[0].name) - parseFloat(b[0].name)).reverse())
})
resolve()
})
}
})
})
}
function onClick(event: React.MouseEvent<HTMLLIElement>) {
setVersion(event.currentTarget.innerHTML)
}
return (
<Fragment>
<ul className={"versions"}>
{Array.from(jobs.keys()).map(value => {
return <li className={version == value.name ? "selected" : "selectable"}
onClick={onClick}>{value.name}</li>
})}
</ul>
<ul className={"builds"}>
{jobs.get(Array.from(jobs.keys()).filter(value => value.name === version)[0])?.map(value => {
return <li>
<Button href={value.url}>#{value.number}</Button>
<ul className={`changes-${value.number}`}>
{value.changes?.map(value1 => {
return <li>[<a href={`https://github.com/AtlasMediaGroup/Scissors/commit/${value1.id}`}>{value1.id}</a>]&nbsp;&nbsp;{value1.comment}</li>
})}
</ul>
<span className={value.changes && value.changes?.length > 0 ? "date" : "date nochanges"}>{new Date(value.timestamp!).toISOString().split("T")[0]}</span>
</li>
})}
</ul>
</Fragment>
);
}
export default DownloadPage;

15
src/pages/HomePage.tsx Normal file
View File

@ -0,0 +1,15 @@
import { Fragment } from "react";
import { Button, Nav, Navbar, NavLink } from "react-bootstrap";
import "../css/HomePage.css"
const HomePage = () => {
return (
<Fragment>
<h1>Scissors</h1>
<h4>Minecraft server software oriented towards patching Creative Mode exploits.</h4>
<h4>Versions: 1.17.1, 1.18.2, 1.19</h4>
</Fragment>
);
}
export default HomePage;

View File

@ -1,15 +0,0 @@
import { ReportHandler } from 'web-vitals';
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

View File

@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

62
src/util/Jenkins.ts Normal file
View File

@ -0,0 +1,62 @@
import axios from "axios";
const JENKINS_URL: string = "https://ci.scissors.gg/job/"
const ARTIFACT_NAME: string = "Scissors"
export type Job = {
name: string,
url: string
}
export type Build = {
number: number,
url: string,
changes?: BuildChange[],
timestamp?: number
}
export type BuildChange = {
comment: string,
id: string,
}
export function getJobs(): Promise<Job[]> {
let jobs: Job[] = []
let request = axios.get(`${JENKINS_URL}/${ARTIFACT_NAME}/api/json?pretty=true`)
return new Promise((resolve, reject) => {
request.then(value => {
jobs = value.data.jobs as Job[]
resolve(jobs)
}).catch(() => reject)
})
}
export function getBuilds(version: string): Promise<Build[]> {
let builds: Build[] = []
let request = axios.get(`${JENKINS_URL}/${ARTIFACT_NAME}/job/${version}/api/json?pretty=true`)
return new Promise((resolve, reject) => {
request.then(value => {
builds = value.data.builds as Build[]
let count = 0;
for (let build of builds) {
axios.get(`${JENKINS_URL}/${ARTIFACT_NAME}/job/${version}/${build.number}/api/json?pretty=true`).then(value1 => {
build.timestamp = value1.data.timestamp
let changeSet: any[] = value1.data.changeSets
if (changeSet.length > 0) {
let changes = changeSet[0].items as BuildChange[]
for (let change of changes) {
change.id = change.id.substring(0, 7)
}
build.changes = changes
count++;
if (count === builds.length - 1) {
resolve(builds)
}
}
})
}
}).catch(() => reject)
})
}

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2015",
"lib": [
"dom",
"dom.iterable",