first commit
This commit is contained in:
commit
b5a4c0a601
42 changed files with 2802 additions and 0 deletions
56
.forgejo/workflows/build.yaml
Normal file
56
.forgejo/workflows/build.yaml
Normal file
|
@ -0,0 +1,56 @@
|
|||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
|
||||
- name: Cache npm dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: '~/.npm'
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Build project
|
||||
run: npm install && npm run build
|
||||
|
||||
- name: Upload production-ready build files
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: production-files
|
||||
path: ./dist
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: production-files
|
||||
path: ./dist
|
||||
|
||||
- name: Upload ftp
|
||||
uses: https://git.lgbt/mirror/ftp-action@releases/v2
|
||||
with:
|
||||
host: ${{ secrets.FTP_SERVER }}
|
||||
user: ${{ secrets.FTP_USER }}
|
||||
password: ${{ secrets.FTP_PASSWORD }}
|
||||
localDir: "dist"
|
||||
remoteDir: "v2.exhq.dev"
|
||||
options: "--delete"
|
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
28
README.md
Normal file
28
README.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
## Usage
|
||||
|
||||
```bash
|
||||
$ npm install # or pnpm install or yarn install
|
||||
```
|
||||
|
||||
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm run dev`
|
||||
|
||||
Runs the app in the development mode.<br>
|
||||
Open [http://localhost:5173](http://localhost:5173) to view it in the browser.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `dist` folder.<br>
|
||||
It correctly bundles Solid in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.<br>
|
||||
Your app is ready to be deployed!
|
||||
|
||||
## Deployment
|
||||
|
||||
Learn more about deploying your application with the [documentations](https://vitejs.dev/guide/static-deploy.html)
|
21
hacked/App.tsx
Normal file
21
hacked/App.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import '../src/App.css'
|
||||
import './hacked.css'
|
||||
export default function App() {
|
||||
return <div class='hackedmain'>
|
||||
<div class='hackedheader'>
|
||||
<h1>websites that ive stolen</h1>
|
||||
<div class='hackedlist'>
|
||||
<a href="https://exhq.mugman.tech/">exhq.mugman.tech</a>
|
||||
<a href="https://exhq.nekos.in/">exhq.nekos.in</a>
|
||||
<a href="https://exhq.i386.dev">exhq.i386.dev</a>
|
||||
<a href="https://exhq.sadan.zip">exhq.sadan.zip</a>
|
||||
<a href="https://exhq.maggiepi.site">exhq.maggiepi.site</a>
|
||||
<a href="https://exhq.nea.moe">exhq.nea.moe</a>
|
||||
<a href="https://exhq.ushie.dev">exhq.ushie.dev</a>
|
||||
<a href="https://exhq.aspy.dev">exhq.aspy.dev</a>
|
||||
<a href="https://exhq.steamcumunity.com/">exhq.steamcumunity.com</a>
|
||||
<a href="https://exhq.rico040.su/">exhq.rico040.su</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
18
hacked/hacked.css
Normal file
18
hacked/hacked.css
Normal file
|
@ -0,0 +1,18 @@
|
|||
.hackedmain {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.hackedheader {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.hackedlist a {
|
||||
color: pink;
|
||||
}
|
||||
|
||||
.hackedlist {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
17
hacked/index.html
Normal file
17
hacked/index.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="https://proxy.spiro.exhq.dev/_/plain/https://dp.nea.moe/avatar/712639419785412668.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>amy hacked</title>
|
||||
<meta content="i am hakcer" property="og:title" />
|
||||
<meta content="wevbsiutres that ive st0oplen" property="og:description" />
|
||||
<meta content="https://proxy.spiro.exhq.dev/_/plain/https://dp.nea.moe/avatar/712639419785412668.png" property="og:image" />
|
||||
<meta content="#43B581" data-react-helmet="true" name="theme-color" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="hackedroot"></div>
|
||||
<script type="module" src="./index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
11
hacked/index.tsx
Normal file
11
hacked/index.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { render } from 'solid-js/web'
|
||||
|
||||
import App from './App'
|
||||
|
||||
const root = document.getElementById('hackedroot')
|
||||
|
||||
render(() => (
|
||||
<>
|
||||
<App />
|
||||
</>
|
||||
), root!)
|
24
index.html
Normal file
24
index.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/svg+xml"
|
||||
href="https://files.amy.rip/pfp.jpg"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Amy</title>
|
||||
<meta content="Amy" property="og:title" />
|
||||
<meta
|
||||
content="warning: this user is known to be extremely amy, proceed with caution."
|
||||
property="og:description"
|
||||
/>
|
||||
<meta content="https://files.amy.rip/pfp.jpg" property="og:image" />
|
||||
<meta content="#43B581" data-react-helmet="true" name="theme-color" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
21
package.json
Normal file
21
package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "v2.exhq.dev",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^20.14.10",
|
||||
"solid-js": "^1.8.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-solid": "^2.10.2"
|
||||
},
|
||||
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee"
|
||||
}
|
1142
pnpm-lock.yaml
Normal file
1142
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
BIN
public/birthday.png
Normal file
BIN
public/birthday.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
BIN
public/explod.gif
Normal file
BIN
public/explod.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
public/explod.mp3
Normal file
BIN
public/explod.mp3
Normal file
Binary file not shown.
BIN
public/fireemoji.png
Normal file
BIN
public/fireemoji.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 928 B |
BIN
public/fjonkie.png
Executable file
BIN
public/fjonkie.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
public/gaybackground.png
Normal file
BIN
public/gaybackground.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
public/nyaboom.webp
Normal file
BIN
public/nyaboom.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
51
review/App.tsx
Normal file
51
review/App.tsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import '../src/App.css'
|
||||
import "./reviewed.css"
|
||||
import { sendReview } from '../src/components/api'
|
||||
|
||||
export default function App() {
|
||||
const token = window.location.hash.substring(window.location.hash.indexOf("access_token") + "access_token".length + 1).substring(0, 30)
|
||||
console.log(token)
|
||||
if (token === "") {
|
||||
window.location.href = "https://discord.com/oauth2/authorize?client_id=1208380910525743134&response_type=token&redirect_uri=https%3A%2F%2Fexhq.dev%2Freview%2F&scope=identify"
|
||||
}
|
||||
let ref!: HTMLTextAreaElement;
|
||||
return <div class='reviewOuterparent'>
|
||||
<div class='reviewParent'>
|
||||
<img src="../fjonkie.png" alt="" />
|
||||
<span>(it doesnt)</span>
|
||||
<textarea
|
||||
ref={ref}
|
||||
onKeyPress={async (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault()
|
||||
if (await sendReview(ref.value, token)) {
|
||||
alert("review sent!")
|
||||
} else {
|
||||
alert("something went wrong, check your network tab or something idfk")
|
||||
}
|
||||
}
|
||||
}}
|
||||
placeholder='your shitty review'
|
||||
class='reviewText'
|
||||
name="" id="" cols="25" rows="3">
|
||||
</textarea>
|
||||
|
||||
<div class='flexButton'>
|
||||
<button onclick={async () => {
|
||||
try {
|
||||
const success = await sendReview(ref.value, token);
|
||||
if (success) {
|
||||
alert("Review sent successfully!");
|
||||
} else {
|
||||
alert("Failed to send review. open your browser's network tab for more info lmao");
|
||||
}
|
||||
} catch (error) {
|
||||
alert("how");
|
||||
}
|
||||
|
||||
}} class='sendButton'>send yo shi</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
20
review/index.html
Normal file
20
review/index.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="https://proxy.spiro.exhq.dev/_/plain/https://dp.nea.moe/avatar/712639419785412668.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>amy reviews</title>
|
||||
<meta content="review" property="og:title" />
|
||||
<meta content="rewviewdb, but not turkish" property="og:description" />
|
||||
<meta content="https://proxy.spiro.exhq.dev/_/plain/https://dp.nea.moe/avatar/712639419785412668.png" property="og:image" />
|
||||
<meta content="#43B581" data-react-helmet="true" name="theme-color" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="reviewroot"></div>
|
||||
<script type="module" src="./index.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
11
review/index.tsx
Normal file
11
review/index.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { render } from 'solid-js/web'
|
||||
|
||||
import App from './App'
|
||||
|
||||
const root = document.getElementById('reviewroot')
|
||||
|
||||
render(() => (
|
||||
<>
|
||||
<App />
|
||||
</>
|
||||
), root!)
|
54
review/reviewed.css
Normal file
54
review/reviewed.css
Normal file
|
@ -0,0 +1,54 @@
|
|||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.parent {
|
||||
height: 100%;
|
||||
/* just */
|
||||
}
|
||||
|
||||
.reviewOuterparent {
|
||||
height: 90vh;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.reviewText {
|
||||
margin-top: 15%;
|
||||
color: pink;
|
||||
margin-bottom: 10%;
|
||||
font-size: xx-large;
|
||||
background-color: #1e1e1e;
|
||||
font-family: monospace;
|
||||
outline: none;
|
||||
border: none;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.reviewParent {
|
||||
display: flex;
|
||||
/* background-color: ; */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sendButton {
|
||||
color: pink;
|
||||
background-color: #0a0a0a;
|
||||
font-size: 19px;
|
||||
border: 2px solid #0a0a0a;
|
||||
padding: 15px 50px;
|
||||
cursor: pointer
|
||||
}
|
||||
.sendButton:hover {
|
||||
background-color: #2c2c2c;
|
||||
border: 2px solid #2c2c2c;
|
||||
}
|
||||
|
||||
.flexButton {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
417
src/App.css
Normal file
417
src/App.css
Normal file
|
@ -0,0 +1,417 @@
|
|||
:root {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
/* browsers agreeing on stuff challenge (impossible) */
|
||||
background-color: #121212;
|
||||
font-family: monospace;
|
||||
overflow-x: hidden;
|
||||
color: #ffc8dd;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #cdb4db;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: 10px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.musicartist {
|
||||
font-weight: bolder;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.musicbutton {
|
||||
background-color: #272525;
|
||||
color: pink;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
padding: 10px 30px;
|
||||
box-shadow: none;
|
||||
border-radius: 5px;
|
||||
transition: 639ms;
|
||||
transform: translateY(0);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.musicdiv {
|
||||
background-color: rgba(0, 0, 0, 0.731);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1500;
|
||||
}
|
||||
|
||||
.music-close-button-div {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
padding: 2;
|
||||
border: none;
|
||||
background: none;
|
||||
border-radius: 2px;
|
||||
background-color: #5e5a5a;
|
||||
text-decoration: none;
|
||||
color: pink;
|
||||
cursor: pointer;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.musiclist {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
font-size: larger;
|
||||
flex-wrap: wrap;
|
||||
height: 80%;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.innermusic {
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
border-radius: 2%;
|
||||
background: #121212;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.musicbutton:hover {
|
||||
border-radius: 5px;
|
||||
transition: 639ms;
|
||||
padding: 10px 30px;
|
||||
transform: translateY(-1px);
|
||||
border: none;
|
||||
box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
-webkit-box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
-moz-box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
background-color: #5e5a5a;
|
||||
animation: big 500ms infinite;
|
||||
transform: translateY(-0.3em);
|
||||
transition:
|
||||
background-color 1s,
|
||||
transform 0.5s,
|
||||
box-shadow 0.5s,
|
||||
-webkit-box-shadow 0.5s,
|
||||
-moz-box-shadow 0.5s;
|
||||
}
|
||||
|
||||
.actualreviewdiv {
|
||||
overflow-y: scroll;
|
||||
height: 18em;
|
||||
}
|
||||
|
||||
.cardchild:hover + .actualreviewdiv {
|
||||
transition: 1s;
|
||||
transform: rotateY(100);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-top: 6em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cardchild h1:not(:has(.listeningto)) {
|
||||
font-size: 3em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.reviewheadertext {
|
||||
margin-bottom: -0.2em;
|
||||
}
|
||||
|
||||
.cardchild p {
|
||||
margin-bottom: -1.5em;
|
||||
}
|
||||
|
||||
.cardchild a {
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
color: pink;
|
||||
text-decoration: underline;
|
||||
margin-bottom: 0%;
|
||||
.fadein {
|
||||
animation: spawntop 1s;
|
||||
}
|
||||
}
|
||||
|
||||
.cardchild span {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.cardchild img {
|
||||
max-width: 5em;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.cardchild:hover::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* CAN BROWSERS JUST AGREE ON ONE FUCKING THING */
|
||||
|
||||
.cardchild {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
cursor: default;
|
||||
background-color: #272525;
|
||||
border-radius: 5%;
|
||||
width: 25em;
|
||||
height: 25em;
|
||||
margin-top: 1em;
|
||||
padding: 0.5em 5em 2em 5em;
|
||||
transform: translateY(-0em);
|
||||
transition:
|
||||
background-color 1s,
|
||||
transform 0.5s,
|
||||
box-shadow 0.5s,
|
||||
-webkit-box-shadow 0.5s,
|
||||
-moz-box-shadow 0.5s;
|
||||
}
|
||||
|
||||
.theeaster {
|
||||
color: pink;
|
||||
padding: 8px;
|
||||
font-size: 21px;
|
||||
text-align: center;
|
||||
border-width: 0;
|
||||
background-color: #5555557a;
|
||||
border-style: solid;
|
||||
border-radius: 11px;
|
||||
}
|
||||
|
||||
.theeaster:focus {
|
||||
border-color: pink;
|
||||
box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
-webkit-box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
-moz-box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
.easteregg {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.easteregginner {
|
||||
width: 70%;
|
||||
background-color: #272525;
|
||||
height: 10em;
|
||||
}
|
||||
|
||||
.cardchild:hover {
|
||||
box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
-webkit-box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
-moz-box-shadow: 0 0 534px -3px rgba(250, 236, 236, 0.4);
|
||||
background-color: #5e5a5a;
|
||||
animation: big 500ms infinite;
|
||||
transform: translateY(-0.3em);
|
||||
transition:
|
||||
background-color 1s,
|
||||
transform 0.5s,
|
||||
box-shadow 0.5s,
|
||||
-webkit-box-shadow 0.5s,
|
||||
-moz-box-shadow 0.5s;
|
||||
}
|
||||
|
||||
.linktree {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.linktree img {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.singlereview img {
|
||||
border-radius: 12%;
|
||||
}
|
||||
|
||||
.singlereview {
|
||||
margin: 1em;
|
||||
border-radius: 3%;
|
||||
background-color: #00000040;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.cssishard {
|
||||
background-color: #121212;
|
||||
}
|
||||
|
||||
.singlemusic {
|
||||
cursor: pointer;
|
||||
min-width: 15em;
|
||||
max-width: 15em;
|
||||
word-wrap: anywhere;
|
||||
margin: 1em;
|
||||
padding: 1em;
|
||||
border-radius: 3%;
|
||||
background-color: #272525;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.singlemusic img {
|
||||
max-width: 5em;
|
||||
}
|
||||
|
||||
.innermusic {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.reviewname {
|
||||
margin-bottom: 0.1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.reviewinfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.reviewname {
|
||||
margin-bottom: 0.1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.parent {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 3.6em;
|
||||
color: blanchedalmond;
|
||||
display: inline-table;
|
||||
}
|
||||
|
||||
.cardchild h2 {
|
||||
display: inline-table;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.header h1:not(:active) {
|
||||
animation: slide-right 1.5s;
|
||||
}
|
||||
|
||||
.header h1:hover {
|
||||
animation: shake 10ms infinite;
|
||||
}
|
||||
|
||||
.header img {
|
||||
border-radius: 25%;
|
||||
margin-right: 1em;
|
||||
vertical-align: middle;
|
||||
max-width: 10em;
|
||||
}
|
||||
|
||||
.initialanim {
|
||||
animation: slide-left 1.5s;
|
||||
}
|
||||
|
||||
.gaybackground {
|
||||
background-image: url("/gaybackground.png");
|
||||
}
|
||||
|
||||
.animate {
|
||||
z-index: 10000000;
|
||||
transform: scale(10000);
|
||||
transition: 20s;
|
||||
}
|
||||
|
||||
@keyframes slide-left {
|
||||
from {
|
||||
transform: translateX(-10000em);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-right {
|
||||
from {
|
||||
transform: translateX(10000em);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bigsmall {
|
||||
0% {
|
||||
max-width: 10em;
|
||||
}
|
||||
|
||||
50% {
|
||||
width: 10.5em;
|
||||
max-width: 10.5em;
|
||||
}
|
||||
|
||||
100% {
|
||||
max-width: 10em;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spawntop {
|
||||
0% {
|
||||
opacity: 0%;
|
||||
transform: translateY(1em);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 100%;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0% {
|
||||
transform: translate(0, 0) rotate(0deg);
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: translate(5px, 5px) rotate(5deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translate(0, 0) rotate(0eg);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translate(-5px, 5px) rotate(-5deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(0, 0) rotate(0deg);
|
||||
}
|
||||
}
|
255
src/App.tsx
Normal file
255
src/App.tsx
Normal file
|
@ -0,0 +1,255 @@
|
|||
import './App.css'
|
||||
import {AdvancedBr, Singular88, SingularOomfie} from './components/comps.tsx'
|
||||
import {createSignal, onMount} from 'solid-js';
|
||||
import Reviews from './components/api.tsx';
|
||||
import Music, {MusicEntry} from './components/music.tsx';
|
||||
import {Bdpfp, Normalpfp} from './components/pfp.tsx';
|
||||
import {InfoCard} from './components/middlecard.tsx';
|
||||
|
||||
export const [shouldpopup, setpopup] = createSignal(false)
|
||||
export const [shouldpopup88, setpopup88] = createSignal(false)
|
||||
export const [shouldpopupEasterEgg, setpopupEasterEgg] = createSignal(false)
|
||||
export const [ishover, setishover] = createSignal(false)
|
||||
|
||||
let explodcount = 0
|
||||
const isitmybd = () => new Date().toISOString().slice(5, 10) === '08-22';
|
||||
|
||||
function getRandomVivsieWord() {
|
||||
const words = [
|
||||
"fuck",
|
||||
"shit",
|
||||
"pussy",
|
||||
"penis",
|
||||
"dick"
|
||||
]
|
||||
return words[Math.floor(Math.random() * words.length)]
|
||||
}
|
||||
|
||||
function vivsiepop() {
|
||||
const blep = document.body.childNodes;
|
||||
|
||||
function fuckshit(node: ChildNode) {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
node.textContent = getRandomVivsieWord();
|
||||
} else {
|
||||
node.childNodes.forEach(fuckshit);
|
||||
}
|
||||
}
|
||||
|
||||
blep.forEach(fuckshit)
|
||||
}
|
||||
|
||||
function nyaboom() {
|
||||
explodcount++
|
||||
const blep = document.body.childNodes;
|
||||
|
||||
function fuckshit(node: ChildNode) {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
(node as Element).textContent = ''
|
||||
node.parentElement?.appendChild(<img style={{
|
||||
width: "1.5em"
|
||||
}} src="./explod.gif"/> as Element)
|
||||
} else if (node instanceof HTMLImageElement) {
|
||||
node.src = "./explod.gif"
|
||||
} else {
|
||||
node.childNodes.forEach(fuckshit);
|
||||
}
|
||||
}
|
||||
|
||||
blep.forEach(fuckshit)
|
||||
}
|
||||
|
||||
function App() {
|
||||
|
||||
const [musicList, setMusicList] = createSignal<string[]>([]);
|
||||
const [isLoading, setIsLoading] = createSignal(true);
|
||||
const [oomfies, setoomfies] = createSignal(<>oomfies</>)
|
||||
const [isAnimating, setIsAnimating] = createSignal(false);
|
||||
onMount(async () => {
|
||||
try {
|
||||
const response = await fetch("https://imtoolazytomakeaproperapi.exhq.dev/");
|
||||
const data = await response.json();
|
||||
setMusicList(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching music data:", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
});
|
||||
let gitgay = <img onClick={() => {
|
||||
setIsAnimating(true)
|
||||
setTimeout(() => {
|
||||
window.location.href = "https://git.lgbt/exhq"
|
||||
}, 200);
|
||||
gitgay.src = "/gaybackground.png"
|
||||
}} classList={{'gitgayimg': true, 'animate': isAnimating(), 'gaybackground': isAnimating()}}
|
||||
src="https://proxy.spiro.exhq.dev/_/plain/https://git.lgbt/assets/img/logo.png"
|
||||
alt="logo of git.lgbt"/> as HTMLImageElement
|
||||
// @ts-ignore
|
||||
return (
|
||||
<>
|
||||
{isitmybd() ? <Bdpfp setpopupEasterEgg={setpopupEasterEgg}/> :
|
||||
<Normalpfp setpopupEasterEgg={setpopupEasterEgg}/>}
|
||||
|
||||
<p style={{display: "none"}}>AdvancedBr my beloved</p>
|
||||
<AdvancedBr count={6}/>
|
||||
|
||||
|
||||
<div class='parent'>
|
||||
<div class='cardchild'>
|
||||
<h1>link tree</h1>
|
||||
<div class='linktree'>
|
||||
{gitgay}
|
||||
|
||||
</div>
|
||||
<br/>
|
||||
<div class='linktree'>
|
||||
<span class='gitgaytext'>Git</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
opacity: isAnimating() ? "0%" : "100%"
|
||||
}} class='cardchild'>
|
||||
<InfoCard bd={isitmybd()}/>
|
||||
|
||||
</div>
|
||||
<div
|
||||
onMouseEnter={() => {
|
||||
setishover(true)
|
||||
}}
|
||||
onmouseleave={() => {
|
||||
setishover(false)
|
||||
}}
|
||||
style={{
|
||||
opacity: isAnimating() ? "0%" : "100%"
|
||||
}} class='cardchild'>
|
||||
<Reviews/>
|
||||
</div>
|
||||
</div>
|
||||
<AdvancedBr count={2}/>
|
||||
<div class='easteregg' style={{opacity: isAnimating() ? "0%" : "100%"}}>
|
||||
<div class="musicbutton" onClick={() => {
|
||||
setpopup(!shouldpopup())
|
||||
}}>
|
||||
<p>typa shit ive been on</p><img style={{
|
||||
"margin-left": "0.3em",
|
||||
"max-width": "1.5em"
|
||||
}} src="./fireemoji.png"/>
|
||||
</div>
|
||||
<div class="musicbutton">
|
||||
<div class="oomfies" onClick={() => {
|
||||
setoomfies(
|
||||
<>
|
||||
<SingularOomfie name='ashley' discordid='836177139798638592'
|
||||
url='https://ashleygraves.eu/'></SingularOomfie>
|
||||
<SingularOomfie name='nea' discordid='310702108997320705'
|
||||
url='https://nea.moe'></SingularOomfie>
|
||||
<SingularOomfie name='vozy' discordid='359175647257690113'
|
||||
url='https://vozy.exhq.dev'></SingularOomfie>
|
||||
<SingularOomfie name='hazel' discordid='435026627907420161'
|
||||
url='https://yellows.ink/'></SingularOomfie>
|
||||
<SingularOomfie name='nax' discordid='148801388938264576'
|
||||
url='https://nax.dev/'></SingularOomfie>
|
||||
<SingularOomfie name='squirrelly' discordid='218032723296649217'
|
||||
url='https://squirrelly13.neocities.org/'></SingularOomfie>
|
||||
<SingularOomfie name='ushie' discordid='399862294143696897'
|
||||
url='https://ushie.dev/'></SingularOomfie>
|
||||
<SingularOomfie name='mugman' discordid='601836455006044163'
|
||||
url='https://mugman.tech'></SingularOomfie>
|
||||
<SingularOomfie name='krystal' discordid='929208515883569182'
|
||||
url='https://krystal.exhq.dev/'></SingularOomfie>
|
||||
|
||||
</>
|
||||
)
|
||||
}}> {oomfies()}</div>
|
||||
</div>
|
||||
<div class="musicbutton" onClick={vivsiepop}>
|
||||
<p>echo if it was written by vivsiepop</p>
|
||||
</div>
|
||||
<div class="musicbutton" onClick={() => {
|
||||
setpopup88(true)
|
||||
}}>
|
||||
<p>88x31's</p>
|
||||
</div>
|
||||
<div class="musicbutton" onClick={() => {
|
||||
if (explodcount > 5) {
|
||||
document.body.innerHTML = ""
|
||||
setTimeout(() => {
|
||||
alert("sorry bud, you exploded so much that my document.body is gon")
|
||||
}, 500)
|
||||
} else {
|
||||
new Audio("./explod.mp3").play()
|
||||
nyaboom()
|
||||
}
|
||||
}}>
|
||||
<img style={{
|
||||
"margin-left": "0.3em",
|
||||
"max-width": "1.5em"
|
||||
}} src="./nyaboom.webp"/>
|
||||
</div>
|
||||
</div>
|
||||
<AdvancedBr count={3}/>
|
||||
<Music shouldpopup={shouldpopup}>
|
||||
<div class='musicdiv'>
|
||||
<div class='innermusic'>
|
||||
<div class="music-close-button-div">
|
||||
<button class="close-button" onClick={() => {
|
||||
setpopup(false)
|
||||
}}>X
|
||||
</button>
|
||||
</div>
|
||||
<div class='musiclist'>
|
||||
{isLoading() ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
musicList().map((link) => <MusicEntry spotifylink={link}/>)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Music>
|
||||
<Music shouldpopup={shouldpopupEasterEgg}>
|
||||
<div class='musicdiv'>
|
||||
<div class='innermusic'>
|
||||
<div class="music-close-button-div">
|
||||
<button class="close-button" onClick={() => {
|
||||
setpopupEasterEgg(false)
|
||||
}}>X
|
||||
</button>
|
||||
</div>
|
||||
<img src={"https://pico.exhq.dev/-Aax47Gmdsy"}/>
|
||||
</div>
|
||||
</div>
|
||||
</Music>
|
||||
<Music shouldpopup={shouldpopup88}>
|
||||
<div class='musicdiv'>
|
||||
<div class='innermusic'>
|
||||
<div class="music-close-button-div">
|
||||
<button class="close-button" onClick={() => {
|
||||
setpopup88(false)
|
||||
}}>X
|
||||
</button>
|
||||
</div>
|
||||
<div style={{}}>
|
||||
<img src="https://exhq.dev/88x31.png" alt=""/>
|
||||
<br/>
|
||||
<span>feel free to link mine, <code>https://exhq.dev/88x31.png</code></span>
|
||||
<div style={{"background-color": "gray", height: "1px"}}/>
|
||||
<div>
|
||||
<Singular88 name="nax" url="https://nax.dev" src="https://nax.dev/88x31.gif"/>
|
||||
<Singular88 name="sophari" url="https://sophari.org" src="https://sophari.org/img/sophari.gif"/>
|
||||
<Singular88 name="rini" url="https://rinici.de/" src="https://rinici.de/button.png"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Music>
|
||||
<div class='footer'> <a href="https://ko-fi.com/amyarson">support me ♥</a><br/>made with ♥ by amy. <a
|
||||
href="https://git.lgbt/exhq/v2.exhq.dev">this website is
|
||||
opensource</a></div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
115
src/components/api.tsx
Normal file
115
src/components/api.tsx
Normal file
|
@ -0,0 +1,115 @@
|
|||
import {createSignal, onMount} from "solid-js"
|
||||
import {ishover} from "../App";
|
||||
|
||||
interface Review {
|
||||
reviewID: number;
|
||||
discordID: string;
|
||||
reviewText: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
interface NeoReview extends Review {
|
||||
global_name: string;
|
||||
username: string
|
||||
}
|
||||
|
||||
|
||||
export default function Reviews() {
|
||||
const [reviews, setReviews] = createSignal<NeoReview[]>([]);
|
||||
onMount(() => {
|
||||
fetch("https://review.exhq.dev/getreviews")
|
||||
.then(response => response.json())
|
||||
.then((data: Review[]) => {
|
||||
const promises = data.map(review => (
|
||||
fetch(`https://dc-lookup.spiro.exhq.dev/v1/user/${review.discordID}`)
|
||||
.then(response => response.json())
|
||||
.then(user => ({
|
||||
...review,
|
||||
global_name: user.global_name,
|
||||
username: user.username
|
||||
}))
|
||||
));
|
||||
|
||||
Promise.all(promises)
|
||||
.then(yeah => {
|
||||
setReviews(yeah);
|
||||
})
|
||||
.catch(error => console.error("Error fetching Discord user data:", error));
|
||||
})
|
||||
.catch(error => console.error("Error fetching reviews:", error));
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<a style={{
|
||||
display: ishover() ? "inline" : "none"
|
||||
}}
|
||||
href="https://discord.com/oauth2/authorize?client_id=1208380910525743134&response_type=token&redirect_uri=https%3A%2F%2Fexhq.dev%2Freview%2F&scope=identify">
|
||||
<p class="fadein">add your reviews here</p>
|
||||
</a>
|
||||
<h1 class="reviewheadertext">Reviews</h1>
|
||||
<div
|
||||
class="actualreviewdiv">
|
||||
{reviews().length > 0 ? (
|
||||
reviews().reverse().map((review) => (
|
||||
<div>
|
||||
<SingleReview {...review} />
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div>Loading reviews...</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export const theImager = async (id: string): Promise<string> => (await fetch(`https://dc-lookup.spiro.exhq.dev/v1/user/${id}`)
|
||||
.then(res => res.json()).then(data => "https://proxy.spiro.exhq.dev/_/plain/"+data.avatar.link).catch(() => "https://http.cat/status/100"));
|
||||
|
||||
function SingleReview(props: NeoReview) {
|
||||
const [imageSrc, setImageSrc] = createSignal("");
|
||||
|
||||
onMount(async () => {
|
||||
const url = await theImager(props.discordID);
|
||||
setImageSrc(url);
|
||||
});
|
||||
|
||||
return (
|
||||
<div class="singlereview">
|
||||
<img
|
||||
src={imageSrc()}
|
||||
alt="User Avatar"
|
||||
style={{"max-width": "3em", "border-radius": "30%"}}
|
||||
/>
|
||||
<div class="reviewinfo">
|
||||
<div class="reviewname">
|
||||
{props.global_name === null ? props.username : props.global_name}
|
||||
</div>
|
||||
<div class="reviewtext">{props.reviewText}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export async function sendReview(review: string, token: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(`https://review.exhq.dev/sendreview?review=${review}`, {
|
||||
headers: {
|
||||
"Auth": token,
|
||||
},
|
||||
method: "POST"
|
||||
});
|
||||
|
||||
if (response.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
9
src/components/comps.css
Normal file
9
src/components/comps.css
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
.tooltip:hover {
|
||||
max-width: 4em !important;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
animation: ease-in-out 2s infinite;
|
||||
padding: 1em;
|
||||
}
|
67
src/components/comps.tsx
Normal file
67
src/components/comps.tsx
Normal file
|
@ -0,0 +1,67 @@
|
|||
import { createSignal, onMount } from "solid-js";
|
||||
import { theImager } from "./api"
|
||||
import "./comps.css"
|
||||
// warning: this IS horrible code. its a joke. DO NOT try this at home because
|
||||
// your local senior programmer CAN and WILL hunt you down
|
||||
// you have been warned.
|
||||
export function AdvancedBr({ count }: { count: number }) {
|
||||
return new Array(count).fill(null).map(_ => (<br />))
|
||||
}
|
||||
|
||||
export function SingularOomfie(props: { name: string; url: string; discordid: string }) {
|
||||
const [imageSrc, setImageSrc] = createSignal("");
|
||||
const [showTooltip, setShowTooltip] = createSignal(false);
|
||||
|
||||
onMount(async () => {
|
||||
const url = await theImager(props.discordid);
|
||||
setImageSrc(url);
|
||||
});
|
||||
|
||||
const handleMouseMove = () => {
|
||||
setShowTooltip(true);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
setShowTooltip(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
style={{ position: "relative", display: "inline-block" }}
|
||||
>
|
||||
<a href={props.url}>
|
||||
<img
|
||||
class="tooltip"
|
||||
style={{
|
||||
"max-width": "3em",
|
||||
"border-radius": "30%",
|
||||
}}
|
||||
src={imageSrc()}
|
||||
alt={"profile picture for " + props.name}
|
||||
/>
|
||||
</a>
|
||||
{showTooltip() && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
background: "rgba(0, 0, 0, 0.7)",
|
||||
color: "white",
|
||||
padding: "0.5em",
|
||||
"border-radius": "5px",
|
||||
"pointer-events": "none",
|
||||
transform: "translate(20%, -100%)",
|
||||
}}
|
||||
>
|
||||
{props.name}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export function Singular88(props: { name: string; url: string; src:string }) {
|
||||
return <a href={props.url}><img alt={props.name} src={props.src}/></a>
|
||||
}
|
6
src/components/cumbrainz.css
Normal file
6
src/components/cumbrainz.css
Normal file
|
@ -0,0 +1,6 @@
|
|||
.listeningto {
|
||||
font-size: smaller;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
65
src/components/cumbrainz.tsx
Normal file
65
src/components/cumbrainz.tsx
Normal file
|
@ -0,0 +1,65 @@
|
|||
import {createSignal, onMount, Show} from "solid-js";
|
||||
import "./cumbrainz.css"
|
||||
|
||||
|
||||
interface ListenPayload {
|
||||
payload: {
|
||||
count: number;
|
||||
listens: Listen[];
|
||||
playing_now: boolean;
|
||||
user_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Listen {
|
||||
playing_now: boolean;
|
||||
track_metadata: TrackMetadata;
|
||||
}
|
||||
|
||||
interface TrackMetadata {
|
||||
additional_info: AdditionalInfo;
|
||||
artist_name: string;
|
||||
release_name: string;
|
||||
track_name: string;
|
||||
}
|
||||
|
||||
interface AdditionalInfo {
|
||||
duration: number;
|
||||
music_service_name: string;
|
||||
origin_url: string;
|
||||
submission_client: string;
|
||||
submission_client_version: string;
|
||||
}
|
||||
|
||||
export function Cumbrainz() {
|
||||
const [musicInfo, setMusicInfo] = createSignal({} as ListenPayload);
|
||||
const [isLoading, setIsLoading] = createSignal(true);
|
||||
onMount(async () => {
|
||||
try {
|
||||
const the = await fetch("https://music.exhq.dev/")
|
||||
const thejson = await the.json()
|
||||
setMusicInfo(thejson)
|
||||
} catch (error) {
|
||||
console.error("Error fetching music data from song.link:", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
})
|
||||
return <div class="listeningto">
|
||||
<h2 >Listening to</h2>
|
||||
<Show when={isLoading()} fallback={
|
||||
<Show when={musicInfo().payload.listens.length > 0} fallback={<span>nothing</span>}>
|
||||
<Thesong song={musicInfo()} />
|
||||
</Show>
|
||||
}>
|
||||
<span>loading</span>
|
||||
</Show>
|
||||
</div>
|
||||
}
|
||||
|
||||
function Thesong({song}: { song: ListenPayload }) {
|
||||
return <a
|
||||
href={song.payload.listens[0].track_metadata.additional_info.origin_url.replace(/\?.*/, m => `?v=${new URLSearchParams(m).get('v') ?? ''}`).replace(/(\?v=)$/, '')}>
|
||||
<div> {song.payload.listens[0].track_metadata.artist_name} - {song.payload.listens[0].track_metadata.track_name} </div>
|
||||
</a>
|
||||
}
|
21
src/components/events.tsx
Normal file
21
src/components/events.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { onMount } from 'solid-js';
|
||||
|
||||
const ReloadOnBack = () => {
|
||||
const handlePageShow = (event: Event) => {
|
||||
const pageshowEvent = event as PageTransitionEvent;
|
||||
if (pageshowEvent.persisted) {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
window.addEventListener('pageshow', handlePageShow);
|
||||
return () => {
|
||||
window.removeEventListener('pageshow', handlePageShow);
|
||||
};
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default ReloadOnBack;
|
11
src/components/middlecard.css
Normal file
11
src/components/middlecard.css
Normal file
|
@ -0,0 +1,11 @@
|
|||
.middleparent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.middlechild {
|
||||
text-align: center;
|
||||
}
|
33
src/components/middlecard.tsx
Normal file
33
src/components/middlecard.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { Cumbrainz } from "./cumbrainz"
|
||||
import "./middlecard.css"
|
||||
export interface InfoCardProps {
|
||||
bd: boolean
|
||||
}
|
||||
|
||||
export function InfoCard(props: InfoCardProps) {
|
||||
|
||||
return <div class="middleparent">
|
||||
<div class="middlechild">{
|
||||
props.bd ?
|
||||
<>
|
||||
<span>
|
||||
its my birthday
|
||||
<br />
|
||||
please buy me stuff
|
||||
</span>
|
||||
</> : <>
|
||||
<span>silly goober who does silly stuff
|
||||
<br />
|
||||
self proclaimed programmer and progamer
|
||||
<br />
|
||||
shitposts for fun
|
||||
</span>
|
||||
</>}</div>
|
||||
<div style={{"background-color": "gray", height: "1px"}}>
|
||||
<br/>
|
||||
</div>
|
||||
<div class="middlechild">
|
||||
<Cumbrainz></Cumbrainz>
|
||||
</div>
|
||||
</div>
|
||||
}
|
47
src/components/music.tsx
Normal file
47
src/components/music.tsx
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { createSignal, onMount } from "solid-js";
|
||||
|
||||
export default function Music(props: { shouldpopup: () => boolean, children: any }) {
|
||||
return <div style={{
|
||||
position: "absolute",
|
||||
display: props.shouldpopup() ? "block" : "none"
|
||||
}}>
|
||||
{props.children}
|
||||
</div>
|
||||
}
|
||||
|
||||
export function MusicEntry({ spotifylink }: { spotifylink: string }) {
|
||||
const [musicInfo, setMusicInfo] = createSignal({}) as any;
|
||||
const [isLoading, setIsLoading] = createSignal(true);
|
||||
onMount(async () => {
|
||||
try {
|
||||
const apiresponse = await fetch(`https://corsisdum.exhq.dev/v1-alpha.1/links?url=spotify%253Atrack%253A${spotifylink}`)
|
||||
const data = await apiresponse.json()
|
||||
setMusicInfo(data)
|
||||
} catch (error) {
|
||||
console.error("Error fetching music data from song.link:", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
})
|
||||
return (
|
||||
<>{isLoading() ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<div onClick={() => {
|
||||
document.location.href = musicInfo().pageUrl
|
||||
}} class="singlemusic">
|
||||
<img style={{
|
||||
"margin-right": "0.5em"
|
||||
}} src={"https://proxy.spiro.exhq.dev/_/plain/" + musicInfo().entitiesByUniqueId[`SPOTIFY_SONG::${spotifylink}`]?.thumbnailUrl} alt={"album cover of" + musicInfo().entitiesByUniqueId[`SPOTIFY_SONG::${spotifylink}`]?.title} />
|
||||
<div class="innersinglemusic">
|
||||
<div class="musicartist" > {
|
||||
musicInfo().entitiesByUniqueId[`SPOTIFY_SONG::${spotifylink}`]?.artistName?.length > 43 ? musicInfo().entitiesByUniqueId[`SPOTIFY_SONG::${spotifylink}`]?.artistName.substring(0, 30) + "..." : musicInfo().entitiesByUniqueId[`SPOTIFY_SONG::${spotifylink}`]?.artistName
|
||||
}</div>
|
||||
<div class="musictitle"> {
|
||||
musicInfo().entitiesByUniqueId[`SPOTIFY_SONG::${spotifylink}`]?.title?.length > 43 ? musicInfo().entitiesByUniqueId[`SPOTIFY_SONG::${spotifylink}`]?.title.substring(0, 30) + "..." : musicInfo().entitiesByUniqueId[`SPOTIFY_SONG::${spotifylink}`]?.title
|
||||
} </div>
|
||||
</div>
|
||||
</div>
|
||||
)}</>
|
||||
)
|
||||
}
|
31
src/components/name.tsx
Normal file
31
src/components/name.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
// import { createSignal, onCleanup } from "solid-js";
|
||||
import { onCleanup } from "solid-js";
|
||||
import { removethething } from "./utils.tsx";
|
||||
|
||||
function HoverComponent() {
|
||||
let timerId: number | null;
|
||||
|
||||
const clearTimer = () => {
|
||||
if (timerId) {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
}
|
||||
};
|
||||
|
||||
onCleanup(() => {
|
||||
clearTimer();
|
||||
});
|
||||
|
||||
return (
|
||||
<h1
|
||||
class="removethisinstantly"
|
||||
onMouseEnter={() => {
|
||||
removethething();
|
||||
}}
|
||||
>
|
||||
Amy
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
export default HoverComponent;
|
40
src/components/pfp.css
Normal file
40
src/components/pfp.css
Normal file
|
@ -0,0 +1,40 @@
|
|||
.birthdayparent {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@keyframes rotateAnimation {
|
||||
from {
|
||||
transform: rotateY(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.rotate {
|
||||
animation: rotateAnimation 0.5s ease-in-out forwards;
|
||||
}
|
||||
|
||||
.header .bd {
|
||||
flex-direction: column;
|
||||
margin-left: 10em;
|
||||
}
|
||||
|
||||
.birthday {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin-left: -12em;
|
||||
}
|
||||
|
||||
.birthdaypfp {
|
||||
z-index: 1;
|
||||
max-width: 10em;
|
||||
}
|
||||
|
||||
.birthdayhat {
|
||||
z-index: 2;
|
||||
width: 14em;
|
||||
top: -3em;
|
||||
left: -1em;
|
||||
}
|
69
src/components/pfp.tsx
Normal file
69
src/components/pfp.tsx
Normal file
|
@ -0,0 +1,69 @@
|
|||
import HoverComponent from "./name";
|
||||
import "./pfp.css";
|
||||
|
||||
export function Bdpfp({
|
||||
setpopupEasterEgg,
|
||||
}: {
|
||||
setpopupEasterEgg: (value: boolean) => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
setpopupEasterEgg(true);
|
||||
}}
|
||||
class="header bd"
|
||||
>
|
||||
<div class="birthdayparent">
|
||||
<img
|
||||
class="birthdaypfp birthday"
|
||||
src="https://files.amy.rip/pfp.jpg"
|
||||
alt="amy's current discord pfp, with a birthday hat on it"
|
||||
/>
|
||||
<img class="birthdayhat birthday" src="./birthday.png" alt="" />
|
||||
<HoverComponent />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function Normalpfp({
|
||||
setpopupEasterEgg,
|
||||
}: {
|
||||
setpopupEasterEgg: (value: boolean) => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
setpopupEasterEgg(true);
|
||||
}}
|
||||
class="birthdayparent header normal"
|
||||
>
|
||||
<img
|
||||
class="initialanim"
|
||||
src="https://files.amy.rip/pfp.jpg"
|
||||
alt="amy's current discord pfp"
|
||||
onMouseEnter={(e) => {
|
||||
(e.target as HTMLImageElement).animate(
|
||||
[{ transform: "rotateZ(0deg)" }, { transform: "rotateZ(360deg)" }],
|
||||
{
|
||||
duration: 400,
|
||||
iterations: 1,
|
||||
},
|
||||
);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
(e.target as HTMLImageElement).animate(
|
||||
[{ transform: "rotateY(0deg)" }, { transform: "rotateY(360deg)" }],
|
||||
{
|
||||
duration: 150,
|
||||
iterations: 1,
|
||||
},
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<HoverComponent />
|
||||
</div>
|
||||
);
|
||||
}
|
35
src/components/utils.tsx
Normal file
35
src/components/utils.tsx
Normal file
|
@ -0,0 +1,35 @@
|
|||
export function removethething() {
|
||||
for (let i = 0; i < document.styleSheets.length; i++) {
|
||||
let styleSheet = document.styleSheets[i];
|
||||
let rules = styleSheet.cssRules || styleSheet.rules;
|
||||
for (let j = 0; j < rules.length; j++) {
|
||||
let rule = rules[j];
|
||||
if (rule.type === CSSRule.KEYFRAMES_RULE && ((rule as CSSKeyframesRule).name === "slide-right" )) {
|
||||
styleSheet.deleteRule(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// export interface song {
|
||||
// entitiesByUniqueId: {
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
export async function getLatestItems(apiUrl: string) {
|
||||
try {
|
||||
const response = await fetch(apiUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error(`API call failed with status ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error('API response is not an array');
|
||||
}
|
||||
const lastFive = data.slice(-5);
|
||||
return lastFive;
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
}
|
14
src/index.tsx
Normal file
14
src/index.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* @refresh reload */
|
||||
import { render } from 'solid-js/web'
|
||||
|
||||
import App from './App'
|
||||
import ReloadOnBack from './components/events'
|
||||
|
||||
const root = document.getElementById('root')
|
||||
|
||||
render(() => (
|
||||
<>
|
||||
<ReloadOnBack />
|
||||
<App />
|
||||
</>
|
||||
), root!)
|
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
28
tsconfig.app.json
Normal file
28
tsconfig.app.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src", "hacked", "review"]
|
||||
}
|
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
13
tsconfig.node.json
Normal file
13
tsconfig.node.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
16
vite.config.ts
Normal file
16
vite.config.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import { resolve } from 'path'
|
||||
import solid from 'vite-plugin-solid'
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
main: resolve(__dirname, 'index.html'),
|
||||
hacked: resolve(__dirname, 'hacked/index.html'),
|
||||
review: resolve(__dirname, 'review/index.html')
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [solid()],
|
||||
})
|
Loading…
Reference in a new issue