1
0
Fork 0

first commit
Some checks failed
Build / Build (push) Successful in 46s
Build / Deploy (push) Failing after 10s

This commit is contained in:
amy 2024-12-24 16:32:54 +03:30
commit b5a4c0a601
No known key found for this signature in database
42 changed files with 2802 additions and 0 deletions

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

BIN
public/birthday.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
public/explod.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/explod.mp3 Normal file

Binary file not shown.

BIN
public/fireemoji.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

BIN
public/fjonkie.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/gaybackground.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
public/nyaboom.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

51
review/App.tsx Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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>
}

View file

@ -0,0 +1,6 @@
.listeningto {
font-size: smaller;
display: flex;
justify-content: center;
flex-direction: column;
}

View 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
View 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;

View file

@ -0,0 +1,11 @@
.middleparent {
display: flex;
flex-direction: column;
justify-content: space-evenly;
width: 100%;
height: 100%;
}
.middlechild {
text-align: center;
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
/// <reference types="vite/client" />

28
tsconfig.app.json Normal file
View 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
View file

@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.node.json"
}
]
}

13
tsconfig.node.json Normal file
View 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
View 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()],
})