diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000..a55e7a17
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 00000000..03d9549e
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
index eebd0751..bbe33ea3 100644
--- a/package.json
+++ b/package.json
@@ -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"
diff --git a/public/index.html b/public/index.html
index aa069f27..5f0f39c5 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,20 +1,26 @@
-
-
-
-
-
+
+
+
+
+
-
+
-
+
+
- React App
-
-
-
-
-
-
+ To begin the development, run `npm start` or `yarn start`.
+ To create a production bundle, use `npm run build` or `yarn build`.
+-->
+
diff --git a/src/App.css b/src/App.css
deleted file mode 100644
index 74b5e053..00000000
--- a/src/App.css
+++ /dev/null
@@ -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);
- }
-}
diff --git a/src/App.test.tsx b/src/App.test.tsx
deleted file mode 100644
index 2a68616d..00000000
--- a/src/App.test.tsx
+++ /dev/null
@@ -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();
- const linkElement = screen.getByText(/learn react/i);
- expect(linkElement).toBeInTheDocument();
-});
diff --git a/src/App.tsx b/src/App.tsx
index a53698aa..de49fc5e 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -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 (
-
- );
+ return (
+
+
+ SCISSORS
+
+
+
+
+ }/>
+ }/>
+
+
+ );
}
export default App;
diff --git a/src/css/App.css b/src/css/App.css
new file mode 100644
index 00000000..8f57d48f
--- /dev/null
+++ b/src/css/App.css
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/css/DownloadPage.css b/src/css/DownloadPage.css
new file mode 100644
index 00000000..fb9ba51c
--- /dev/null
+++ b/src/css/DownloadPage.css
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/css/HomePage.css b/src/css/HomePage.css
new file mode 100644
index 00000000..f0bfaa78
--- /dev/null
+++ b/src/css/HomePage.css
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/index.css b/src/index.css
deleted file mode 100644
index ec2585e8..00000000
--- a/src/index.css
+++ /dev/null
@@ -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;
-}
diff --git a/src/index.tsx b/src/index.tsx
index 032464fb..f9133920 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -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(
-
-
-
+
);
-
-// 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();
diff --git a/src/logo.svg b/src/logo.svg
deleted file mode 100644
index 9dfc1c05..00000000
--- a/src/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/pages/DownloadPage.tsx b/src/pages/DownloadPage.tsx
new file mode 100644
index 00000000..53a86b2d
--- /dev/null
+++ b/src/pages/DownloadPage.tsx
@@ -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())
+ const [ version, setVersion ] = useState("")
+ useEffect(() => {
+ doJobs().then(value => {
+ })
+ }, [])
+
+ function doJobs(): Promise {
+ return new Promise(resolve => {
+ getJobs().then(value => {
+ for (let job of value) {
+ getBuilds(job.name).then(value1 => {
+ setJobs(prevState => {
+ let map = new Map([ ...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([ ...map.entries() ].sort((a, b) => parseFloat(a[0].name) - parseFloat(b[0].name)).reverse())
+ })
+ resolve()
+ })
+ }
+ })
+ })
+ }
+
+ function onClick(event: React.MouseEvent) {
+ setVersion(event.currentTarget.innerHTML)
+ }
+
+ return (
+
+
+ {Array.from(jobs.keys()).map(value => {
+ return - {value.name}
+ })}
+
+
+ {jobs.get(Array.from(jobs.keys()).filter(value => value.name === version)[0])?.map(value => {
+ return -
+
+
+ {value.changes?.map(value1 => {
+ return - [{value1.id}] {value1.comment}
+ })}
+
+ 0 ? "date" : "date nochanges"}>{new Date(value.timestamp!).toISOString().split("T")[0]}
+
+ })}
+
+
+ );
+}
+
+export default DownloadPage;
\ No newline at end of file
diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx
new file mode 100644
index 00000000..a019fd14
--- /dev/null
+++ b/src/pages/HomePage.tsx
@@ -0,0 +1,15 @@
+import { Fragment } from "react";
+import { Button, Nav, Navbar, NavLink } from "react-bootstrap";
+import "../css/HomePage.css"
+
+const HomePage = () => {
+ return (
+
+ Scissors
+ Minecraft server software oriented towards patching Creative Mode exploits.
+ Versions: 1.17.1, 1.18.2, 1.19
+
+ );
+}
+
+export default HomePage;
\ No newline at end of file
diff --git a/src/reportWebVitals.ts b/src/reportWebVitals.ts
deleted file mode 100644
index 49a2a16e..00000000
--- a/src/reportWebVitals.ts
+++ /dev/null
@@ -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;
diff --git a/src/setupTests.ts b/src/setupTests.ts
deleted file mode 100644
index 8f2609b7..00000000
--- a/src/setupTests.ts
+++ /dev/null
@@ -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';
diff --git a/src/util/Jenkins.ts b/src/util/Jenkins.ts
new file mode 100644
index 00000000..b4eb2d49
--- /dev/null
+++ b/src/util/Jenkins.ts
@@ -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 {
+ 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 {
+ 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)
+ })
+}
+
diff --git a/tsconfig.json b/tsconfig.json
index a273b0cf..d48d3f4d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
- "target": "es5",
+ "target": "es2015",
"lib": [
"dom",
"dom.iterable",