1
0
Fork 0
forked from suyu/website

Compare commits

..

No commits in common. "old-master" and "master" have entirely different histories.

80 changed files with 10762 additions and 773 deletions

11
.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
ssl

1
.npmrc Normal file
View file

@ -0,0 +1 @@
engine-strict=true

4
.prettierignore Normal file
View file

@ -0,0 +1,4 @@
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

14
.prettierrc Normal file
View file

@ -0,0 +1,14 @@
{
"useTabs": true,
"tabWidth": 4,
"printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"overrides": [
{
"files": "*.svelte",
"options": {
"parser": "svelte"
}
}
]
}

View file

@ -1,3 +1,38 @@
# website # create-svelte
WIP NOT DONE YET. DO NOT DEPLOY! Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

View file

@ -1,3 +0,0 @@
DONE -Autoclose announcment bar after 7 seconds
make download page wish uses a yaml file to list builds.
TODO - ambient background if possible --- do this later tried it was breaking a lot of stuff. need to do this after converting suyu.png and favicon.png to to transparent

154
app.js
View file

@ -1,154 +0,0 @@
// Smooth Transition For Everything
const allElements = document.querySelectorAll('*');
allElements.forEach(element => {
element.style.transition = 'all 1000ms ease-in-out';
});
// Rgb Effect
// Select Card elements
const elements = document.querySelectorAll('.card');
// Counter
let counter = 0;
function changeColors() {
const color = getRandomColor();
elements.forEach(element => {
if(element.classList.contains('card')) {
element.style.setProperty('border-color', color, 'important');
}
});
counter++;
counter %= elements.length;
setTimeout(changeColors, 1000);
}
// Random color function
function getRandomColor() {
return `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)})`;
}
// Start changing colors
changeColors();
// Next Section: Make Site Mobile Compatible
const sectionOne = document.getElementById('header');
const sectionOneHead = document.getElementById('headertext')
const sectionOneSubtext = document.getElementById('headersubtext')
const sectionOnebutton = document.getElementById('downloadbutton')
const Sectionthree = document.getElementById('featuresection')
const cards = document.getElementsByClassName('card');
let prevMobile = false;
function checkWidth() {
const isMobile = window.innerWidth <= 1000;
if(isMobile !== prevMobile) {
if(isMobile) {
console.log("Mobile mode on");
sectionOne.classList.add('flex-column');
sectionOne.style.marginLeft = "0px";
sectionOneSubtext.style.marginLeft = "0px"
sectionOnebutton.style.marginLeft = "0px"
Sectionthree.classList.add('flex-column');
for (var i = 0; i < cards.length; i++) {
cards[i].classList.add('mt-5');
}
} else {
console.log("Mobile mode off");
sectionOne.classList.remove('flex-column');
sectionOne.style.marginLeft = "";
sectionOneSubtext.style.marginLeft = ""
sectionOnebutton.style.marginLeft = ""
Sectionthree.classList.remove('flex-column');
for (var i = 0; i < cards.length; i++) {
cards[i].classList.remove('mt-5');
}
}
prevMobile = isMobile;
}
}
// Initial check
checkWidth();
window.addEventListener('resize', checkWidth);
// Next Section : Button Hyperlinks
const downloadbtn = document.getElementById('downloadbtnone')
const discordBtn = document.getElementById('discordbtnone');
const sourceBtn = document.getElementById('sourcebtnone');
const downloadbtn2 = document.getElementById('downloadbutton')
const discordBtn2 = document.getElementById('discordbtnthree');
const sourceBtn2 = document.getElementById('sourcebtntwo');
const sourceBtn3 = document.getElementById('sourcebtnthree');
const downloadBtn3 = document.getElementById('downloadbtnthree')
discordBtn.addEventListener('click', () => {
const url = 'https://discord.gg/2gQRBp44KT';
window.open(url, '_blank');
});
;
sourceBtn.addEventListener('click', () => {
const url = 'https://gitlab.com/suyu2/suyu';
window.open(url, '_blank');
});
downloadbtn.addEventListener('click', () => {
const url = "download.html"
window.open(url, '_blank')
})
discordBtn2.addEventListener('click', () => {
const url = 'https://discord.gg/2gQRBp44KT';
window.open(url, '_blank');
});
;
sourceBtn2.addEventListener('click', () => {
const url = 'https://gitlab.com/suyu2/suyu';
window.open(url, '_blank');
});
downloadbtn2.addEventListener('click', () => {
const url = "download.html"
window.open(url, '_blank')
})
sourceBtn3.addEventListener('click', () => {
const url = 'https://gitlab.com/suyu2/suyu';
window.open(url, '_blank');
});
downloadBtn3.addEventListener('click', () => {
const url = "download.html"
window.open(url, '_blank')
})
// Next Section: Functionality
setTimeout(function(){
document.getElementById('announcement').remove()
}, 7000)

129
blog.html
View file

@ -1,129 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Suyu Emulator</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="description" content="" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3
/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="style.css" />
<link rel="icon" href="img/favicon.png">
<meta name="theme-color" content="#3584e4
">
<meta property="og:title" content="Suyu Emulator" />
<meta property="og:description" content="A Open Source Switch Emulator" />
<meta property="og:image" content="" />
<meta name="twitter:card" content="" />
<meta name="twitter:site" content="" />
<meta name="twitter:title" content="Suyu Emulator" />
<meta name="twitter:description" content="A Open Source Switch Emulator" />
<meta name="twitter:image" content="" />
</head>
<body>
<div id="loader-wrapper" class="bg-white position-fixed top-0 z-3 w-100 h-100 text-center">
<div class="spinner-border mt-5" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<header>
<h1>Hello, world!</h1>
</header>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown link
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<main>
<section></section>
<section></section>
<section></section>
</main>
<!--[if IE]><div class="position-fixed bottom-0 w-100 p-2 text-bg-dark d-flex justify-content-between"><p>Outdated browser dectected. Please use a modern browser for a better browsing experience.</p><button type="button" class="btn-close btn-close-white" onClick="parentNode.remove()" aria-label="Close"></button></div><![endif]-->
<footer>
<small>© <script>document.write(new Date().getFullYear())</script> Your company name. All Rights Reserved.</small>
</footer>
<script src="https://code.jquery.com/jquery-3.7.1
.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3
/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script type="text/javascript">
$(window).on('load', function() {
$("#loader-wrapper").fadeOut(700);
});
</script>
<script src="app.js"></script>
</body>

View file

@ -1,11 +0,0 @@
builds:
- name: Suyu Alpha # Type A Short Name For The Release: Ex: Suyu Alpha, Suyu Beta
fullname: Suyu Alpha Build 32doqnks9 # full name
id: 1 # Increase This Every Time A Build Get Released. This Id Identifies The Build For The Website To Sort Them By Newest To Oldest.
date: 2024-03-06 # date when id get published used to display how long ago was the build releeased
description: Added Feature X # description of the build can put changelogs here
downloadurlwindows: https://example.com
downloadurllinux: https://example.com
- name: Suyu Beta
fullname:

View file

@ -1,91 +0,0 @@
body {
background-color: black !important;
}
/* USE THIS FOR DEBUGGING * {
border: 1px solid red;
} */
#announcement {
background-color: rgb(46, 46, 46) !important;
}
.navbar, .navbar-brand{
background-color: black !important;
color: white !important;
}
.navbar-toggler-icon {
background-color: rgb(83, 82, 82) !important;
}
.nav-link {
color: white !important;
}
.nav-link:hover {
color: cyan !important;
}
#suyu-logo {
height: 420px;
}
#headertext {
color: white;
text-align: top;
}
#headersubtext {
color: white !important;
text-align: top;
display: flex;
align-items: flex-start;
margin-left: 20%;
}
#downloadbutton {
margin-left: 20%;
}
#downloadicon, #sourceicon, #discordicon, #giticon, #windows, #linux-icon {
filter: invert(100%);
}
/* #information {
border-top: 2px solid white;
border-bottom: 2px solid white;
} */
#infoheadtext, #infotext {
color: white;
}
#featuresheadertext, .card-title, .card-text, .card-header {
color: white;
}
.card {
background-color: rgb(37, 32, 32);
}
.card {
border: 5px solid red;
}
.btn {
color: white;
}
.btn:hover {
transform: scale(1.1);
}
footer {
color: white;
text-align: center;
}

View file

@ -1,117 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Suyu Emulator</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="description" content="" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3
/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="download.css" />
<link rel="icon" href="img/favicon.png">
<meta name="theme-color" content="#3584e4
">
</head>
<body>
<div id="loader-wrapper" class="bg-white position-fixed top-0 z-3 w-100 h-100 text-center">
<div class="spinner-border mt-5" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid ">
<a class="navbar-brand" href="#">
<img src="img/favicon.png" alt="Suyu Logo" height="30" class="d-inline-block align-text-top">
Suyu
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="downloadbtnone">Download</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Compatibility List</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="discordbtnone">
<img src="img/discord.svg" alt="Discord Logo" height="24" id="discordicon">
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="sourcebtnone">
<img src="img/gitlab.svg" alt="Git Logo" height="24" id="giticon">
</li>
</ul>
</div>
</div>
</nav>
<main>
<section class="container" id="header">
<div class="d-flex flex-column align-items-center" id="header">
<h1 class="pb-5 mt-4" id="headertext">Downloads ( Latest )</h1>
</div>
</section>
<section class="container" id="downloadsection">
<div class="d-flex flex-column align-items-center" id="downloads">
<p class="d-inline-flex gap-1">
<a class="btn btn-primary" data-bs-toggle="collapse" href="#collapseWindows" role="button" aria-expanded="false" aria-controls="collapseExample">
<img class="mr-5" id="windows" src="img/windows.svg" height="24" alt="Windows Logo">&nbspWindows
</a>
<a class="btn btn-primary" data-bs-toggle="collapse" href="#collapseLinux" role="button" aria-expanded="false" aria-controls="collapseExample">
<img class="mr-5" id="linux-icon" src="img/linux.svg" height="24" alt="Windows Logo">&nbspLinux
</a>
</p>
<div class="collapse" id="collapseWindows">
<div class="card" id="featuredbuild">
<h5 class="card-header">Featured Windows Build</h5>
<div class="card-body">
<h5 class="card-title">Legacy Artifact</h5>
<p class="card-text">Legacy Artifact</p>
<a href="https://github.com/pineappleEA/pineapple-src/releases/download/EA-4176/Windows-Yuzu-EA-4176.zi" class="btn btn-primary">Download</a>
</div>
</div>
<div class="collapse" id="collapseWindows">
<div class="container">
<h3 class="pb-5 mt-4" id="headertext">All Builds</h3>
</div>
</div>
</div>
<div class="collapse" id="collapseLinux">
<div class="card" id="featuredbuild">
<h5 class="card-header">Featured Linux Build</h5>
<div class="card-body">
<h5 class="card-title">Legacy Artifact</h5>
<p class="card-text">Legacy Artifact</p>
<a href="https://github.com/pineappleEA/pineapple-src/releases/download/EA-4176/Linux-Yuzu-EA-4176.AppImage" class="btn btn-primary">Download</a>
</div>
</div>
<div class="collapse" id="collapseLinux">
<div class="container">
<h3 class="pb-5 mt-4" id="headertext">All Builds</h3>
</div>
</div>
</section>
<section></section>
</main>
<!--[if IE]><div class="position-fixed bottom-0 w-100 p-2 text-bg-dark d-flex justify-content-between"><p>Outdated browser dectected. Please use a modern browser for a better browsing experience.</p><button type="button" class="btn-close btn-close-white" onClick="parentNode.remove()" aria-label="Close"></button></div><![endif]-->
<footer>
<small>© <script>document.write(new Date().getFullYear())</script> Suyu emulator is not affiliated or endorsed by Tropic Haze LLC Or Nintendo Co. Ltd.</small>
</footer>
<script src="https://code.jquery.com/jquery-3.7.1
.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3
/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script type="text/javascript">
$(window).on('load', function() {
$("#loader-wrapper").fadeOut(700);
});
</script>
<script src="app.js"></script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.59 5.88997C17.36 5.31997 16.05 4.89997 14.67 4.65997C14.5 4.95997 14.3 5.36997 14.17 5.69997C12.71 5.47997 11.26 5.47997 9.83001 5.69997C9.69001 5.36997 9.49001 4.95997 9.32001 4.65997C7.94001 4.89997 6.63001 5.31997 5.40001 5.88997C2.92001 9.62997 2.25001 13.28 2.58001 16.87C4.23001 18.1 5.82001 18.84 7.39001 19.33C7.78001 18.8 8.12001 18.23 8.42001 17.64C7.85001 17.43 7.31001 17.16 6.80001 16.85C6.94001 16.75 7.07001 16.64 7.20001 16.54C10.33 18 13.72 18 16.81 16.54C16.94 16.65 17.07 16.75 17.21 16.85C16.7 17.16 16.15 17.42 15.59 17.64C15.89 18.23 16.23 18.8 16.62 19.33C18.19 18.84 19.79 18.1 21.43 16.87C21.82 12.7 20.76 9.08997 18.61 5.88997H18.59ZM8.84001 14.67C7.90001 14.67 7.13001 13.8 7.13001 12.73C7.13001 11.66 7.88001 10.79 8.84001 10.79C9.80001 10.79 10.56 11.66 10.55 12.73C10.55 13.79 9.80001 14.67 8.84001 14.67ZM15.15 14.67C14.21 14.67 13.44 13.8 13.44 12.73C13.44 11.66 14.19 10.79 15.15 10.79C16.11 10.79 16.87 11.66 16.86 12.73C16.86 13.79 16.11 14.67 15.15 14.67Z" fill="#000000"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none"><path fill="#000000" d="M14.975 8.904L14.19 6.55l-1.552-4.67a.268.268 0 00-.255-.18.268.268 0 00-.254.18l-1.552 4.667H5.422L3.87 1.879a.267.267 0 00-.254-.179.267.267 0 00-.254.18l-1.55 4.667-.784 2.357a.515.515 0 00.193.583l6.78 4.812 6.778-4.812a.516.516 0 00.196-.583z"/></svg>

Before

Width:  |  Height:  |  Size: 500 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>windows [#174]</title>
<desc>Created with Sketch.</desc>
<defs>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Dribbble-Light-Preview" transform="translate(-60.000000, -7439.000000)" fill="#000000">
<g id="icons" transform="translate(56.000000, 160.000000)">
<path d="M13.1458647,7289.43426 C13.1508772,7291.43316 13.1568922,7294.82929 13.1619048,7297.46884 C16.7759398,7297.95757 20.3899749,7298.4613 23.997995,7299 C23.997995,7295.84873 24.002005,7292.71146 23.997995,7289.71311 C20.3809524,7289.71311 16.7649123,7289.43426 13.1458647,7289.43426 M4,7289.43526 L4,7296.22153 C6.72581454,7296.58933 9.45162907,7296.94113 12.1724311,7297.34291 C12.1774436,7294.71736 12.1704261,7292.0908 12.1704261,7289.46524 C9.44661654,7289.47024 6.72380952,7289.42627 4,7289.43526 M4,7281.84344 L4,7288.61071 C6.72581454,7288.61771 9.45162907,7288.57673 12.1774436,7288.57973 C12.1754386,7285.96017 12.1754386,7283.34361 12.1724311,7280.72405 C9.44461153,7281.06486 6.71679198,7281.42567 4,7281.84344 M24,7288.47179 C20.3879699,7288.48578 16.7759398,7288.54075 13.1619048,7288.55175 C13.1598997,7285.88921 13.1598997,7283.22967 13.1619048,7280.56914 C16.7689223,7280.01844 20.3839599,7279.50072 23.997995,7279 C24,7282.15826 23.997995,7285.31353 24,7288.47179" id="windows-[#174]">
</path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -1,140 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Suyu Emulator</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="description" content="" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3
/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="style.css" />
<link rel="icon" href="img/favicon.png">
<meta name="theme-color" content="#3584e4
">
<meta property="og:title" content="Suyu Emulator" />
<meta property="og:description" content="A Open Source Switch Emulator" />
<meta property="og:image" content="" />
<meta name="twitter:card" content="" />
<meta name="twitter:site" content="" />
<meta name="twitter:title" content="Suyu Emulator" />
<meta name="twitter:description" content="A Open Source Switch Emulator" />
<meta name="twitter:image" content="" />
</head>
<body>
<div id="loader-wrapper" class="bg-white position-fixed top-0 z-3 w-100 h-100 text-center">
<div class="spinner-border mt-5" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid ">
<a class="navbar-brand" href="#">
<img src="img/favicon.png" alt="Suyu Logo" height="30" class="d-inline-block align-text-top">
Suyu
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="downloadbtnone">Download</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Compatibility List</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="discordbtnone">
<img src="img/discord.svg" alt="Discord Logo" height="24" id="discordicon">
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="sourcebtnone">
<img src="img/gitlab.svg" alt="Git Logo" height="24" id="giticon">
</li>
</ul>
</div>
</div>
</nav>
<main>
<section class="container pb-5" id="introduction">
<div class="d-flex align-items-center" id="header">
<img class="mr-5" id="suyu-logo" src="img/suyu.png" alt="Suyu Logo">
<div>
<h2 class="pb-3" id="headertext">A Open Source Switch Emulator</h2>
<p class="pb-3" id="headersubtext">Suyu is a Switch emulator that is based on a previously open-source switch emulator project, that had ceased its development on March 5th, 2024.<br>
The Suyu team has taken up the responsibility of continuing its development.<br>
Suyu will exclusively support already decrypted ROMs and will not provide support for encrypted ROMs.<br>
It will not rely on Prod keys or any other method to decrypt ROMs within the emulator.</p>
<button type="button" class="btn btn-success" id="downloadbutton">
<img src="img/download.png" id="downloadicon" width="20"/>&nbspDownload
</button>
<button type="button" class="btn btn-primary sourcebtn" id="sourcebtntwo">
<img src="img/gitlab.svg" id="sourceicon" width="20"/>&nbspSource Code
</button>
</div>
</div>
</section>
<section class="container-fluid pb-5" id="information">
<div class="d-flex flex-column align-items-center" id="info">
<h1 class="pb-3 mt-4" id="infoheadtext">About Suyu</h1>
<p id="infotext">Suyu is a Switch emulator that is based on a previously open-source switch emulator project,
<br> that had ceased its development on March 5th, 2024. The Suyu team has taken up the responsibility of <br>
continuing its development. Suyu will exclusively support already decrypted ROMs and will not provide support for encrypted ROMs. <br>
It will not rely on Prod keys or any other method to decrypt ROMs within the emulator.
</div>
</section>
<section class="container pb-5" id="features">
<h1 class="mt-4 pb-5 text-center" id="featuresheadertext">Features</h1>
<div class="d-flex flex-row align-items-center justify-content-center" id="featuresection">
<div class="card text-center mx-3" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Open Source</h5>
<p class="card-text">The project's source code is available in gitlab</p>
<a href="#" class="btn btn-primary sourcebtn" id="sourcebtnthree">
<img src="img/gitlab.svg" alt="Git Logo" height="24" id="giticon">&nbspSource Code
</a>
</div>
</div>
<div class="card text-center mx-3" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Cross Platform</h5>
<p class="card-text">Suyu is available for Linux & Windows</p>
<a href="#" class="btn btn-success" id="downloadbtnthree">
<img src="img/download.png" id="downloadicon" width="20"/>&nbspDownload
</a>
</div>
</div>
<div class="card text-center mx-3" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Well Supported</h5>
<p class="card-text">Suyu has a discord server for support inqueries <br> Full of passionate emulation community members</p>
<a href="#" class="btn btn-info discordbtn" id="discordbtnthree">
<img src="img/discord.svg" alt="Discord Logo" height="24" id="discordicon">&nbspJoin
</a>
</div>
</div>
</div>
</section>
</main>
<div class="position-fixed top-0 w-100 p-2 text-bg-dark d-flex justify-content-between" id="announcement"><p id="annoucement-text">We Need Developers! Join Our Discord Server To Join Our Development Team!</p><button type="button" id="announceclose" class="btn-close btn-close-white" onClick="parentNode.remove()" aria-label="Close"></button></div>
<!--[if IE]><div class="position-fixed bottom-0 w-100 p-2 text-bg-dark d-flex justify-content-between"><p>Outdated browser dectected. Please use a modern browser for a better browsing experience.</p><button type="button" class="btn-close btn-close-white" onClick="parentNode.remove()" aria-label="Close"></button></div><![endif]-->
<footer>
<small>© <script>document.write(new Date().getFullYear())</script> Suyu emulator is not affiliated or endorsed by Tropic Haze LLC Or Nintendo Co. Ltd.</small>
</footer>
<script src="https://code.jquery.com/jquery-3.7.1
.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3
/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script type="text/javascript">
$(window).on('load', function() {
$("#loader-wrapper").fadeOut(700);
});
</script>
<script src="app.js"></script>
</body>
</html>

0
module.d.ts vendored Normal file
View file

5698
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

47
package.json Normal file
View file

@ -0,0 +1,47 @@
{
"name": "suyu-site",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"build-prod": "vite build && pm2 restart suyu-site",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check .",
"format": "prettier --write ."
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-node": "^5.0.1",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"autoprefixer": "^10.4.16",
"express": "^4.18.3",
"flowbite": "^2.3.0",
"flowbite-svelte": "^0.44.24",
"flowbite-svelte-icons": "1",
"nintendo-switch-eshop": "^7.1.3",
"postcss": "^8.4.32",
"postcss-load-config": "^5.0.2",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"prettier-plugin-tailwindcss": "^0.5.9",
"sharp": "^0.33.2",
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"svgo": "^3.2.0",
"tailwindcss": "^3.3.6",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^5.0.3",
"vite-plugin-image-optimizer": "^1.1.7"
},
"type": "module",
"dependencies": {
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/enhanced-img": "^0.1.8",
"vite-plugin-vsharp": "^1.7.3"
}
}

2755
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load diff

13
postcss.config.cjs Normal file
View file

@ -0,0 +1,13 @@
const tailwindcss = require("tailwindcss");
const autoprefixer = require("autoprefixer");
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer,
],
};
module.exports = config;

33
server.js Normal file
View file

@ -0,0 +1,33 @@
import { handler } from "./build/handler.js";
import express from "express";
import fs from "fs";
import http from "http";
import https from "https";
const privateKey = fs.readFileSync("./ssl/key.pem", "utf8");
const certificate = fs.readFileSync("./ssl/cert.pem", "utf8");
const credentials = { key: privateKey, cert: certificate };
const app = express();
const httpServer = http.createServer(app);
const httpsServer = https.createServer(credentials, app);
const PORT = 3000;
const SSLPORT = 3001;
httpServer.listen(PORT, function () {
console.log("HTTP Server is running on: http://localhost:%s", PORT);
});
httpsServer.listen(SSLPORT, function () {
console.log("HTTPS Server is running on: https://localhost:%s", SSLPORT);
});
// add a route that lives separately from the SvelteKit app
app.get("/healthcheck", (req, res) => {
res.end("ok");
});
// let SvelteKit handle everything else, including serving prerendered pages and static assets
app.use(handler);

13
src/app.d.ts vendored Normal file
View file

@ -0,0 +1,13 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}
export {};

25
src/app.html Normal file
View file

@ -0,0 +1,25 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Jost:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet"
/>
<meta property="og:type" content="summary">
<meta property="og:site_name" content="suyu">
<meta property="og:title" content="suyu">
<meta property="og:description" content="suyu, pronounced sue-you (wink wink) is the continuation of the world's most popular, open-source, Nintendo Switch emulator, yuzu. It is written in C++ with portability in mind, and we actively maintain builds for Windows, Linux and Android.">
<meta property="og:image" content="https://suyu.dev/img/suyu.png">
<meta property="og:image:alt" content="suyu">
<meta property="og:url" content="https://suyu.dev">
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

4
src/app.pcss Normal file
View file

@ -0,0 +1,4 @@
/* Write your global styles here, in PostCSS syntax */
@tailwind base;
@tailwind components;
@tailwind utilities;

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
src/assets/cards/totk.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
src/assets/fonts/suivar.ttf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 KiB

View file

@ -0,0 +1,3 @@
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.6161 10.5657L10.5656 9.61618L6.23239 5.28293L10.5658 0.949519L9.61625 7.92742e-06L5.28288 4.33342L0.949503 0L0 0.949511L4.33338 5.28293L0.000157237 9.61619L0.94966 10.5657L5.28288 6.23244L9.6161 10.5657Z" fill="white" fill-opacity="0.8"/>
</svg>

After

Width:  |  Height:  |  Size: 394 B

View file

@ -0,0 +1,3 @@
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.4 1C10.4 0.447715 9.95228 0 9.4 0H1C0.447715 0 0 0.447716 0 1V9.4C0 9.95228 0.447716 10.4 1 10.4H9.4C9.95228 10.4 10.4 9.95228 10.4 9.4V1ZM2.4 9C1.84772 9 1.4 8.55229 1.4 8V2.4C1.4 1.84772 1.84771 1.4 2.4 1.4H8C8.55228 1.4 9 1.84771 9 2.4V8C9 8.55228 8.55229 9 8 9H2.4Z" fill="white" fill-opacity="0.8"/>
</svg>

After

Width:  |  Height:  |  Size: 461 B

View file

@ -0,0 +1,3 @@
<svg width="11" height="3" viewBox="0 0 11 3" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.4 0.800007H0V2.20001H10.4V0.800007Z" fill="white" fill-opacity="0.8"/>
</svg>

After

Width:  |  Height:  |  Size: 225 B

BIN
src/assets/mockups/smo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

View file

@ -0,0 +1,115 @@
<script lang="ts">
import { onMount } from "svelte";
import OutlinedLogo from "./OutlinedLogo.svelte";
export let size = 80;
export let gap = 12;
export let speed = 4;
const offsetCount = 2;
$: offsetX = (size + gap) * offsetCount;
$: speedSecs = (1 / speed) * 4;
let countX = 0;
let countY = 0;
function onResize() {
countX = Math.ceil(window.innerWidth / (gap + size));
countY = Math.ceil(window.innerHeight / (gap + size));
console.log(countX, countY);
}
onMount(() => {
onResize();
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
});
function getColor(x: number, y: number) {
const red = "#FF3A3A";
const blue = "#3A99FF";
const evenX = x % 2 === 0;
const evenY = y % 2 === 0;
return evenX === evenY ? red : blue;
}
</script>
<div class="gradient" />
<div class="background-container">
<div
class="background"
style="--size: {size}px; --gap: {gap}px; --offsetX: {offsetX}px; --speed: {speedSecs || 0}s"
>
<div class="scroll" style="--gap: {gap}px">
{#each Array(countX + offsetCount) as _, x}
<div class="group">
{#each Array(countY + offsetCount) as _, y}
<OutlinedLogo {size} color={getColor(x, y)} />
{/each}
</div>
{/each}
</div>
</div>
</div>
<style>
@keyframes scroll {
from {
transform: rotateZ(-4deg)
translate3d(calc(0px - var(--offsetX)), calc(0px - var(--offsetX)), 0);
}
to {
transform: rotateZ(-4deg)
translate3d(
calc(((var(--size) + var(--gap)) * 2) - var(--offsetX)),
calc(0px - var(--offsetX)),
0
);
}
}
.background-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.background {
width: calc(100% + var(--offsetX));
height: 100%;
opacity: 0.5;
animation: scroll infinite linear;
animation-duration: var(--speed);
}
.gradient {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(
180deg,
transparent,
color-mix(in srgb, var(--page-bg), transparent 20%) 25%,
var(--page-bg)
);
background-size: 100% 100%;
z-index: 5;
}
.scroll {
display: flex;
gap: var(--gap);
}
.group {
display: flex;
flex-direction: column;
gap: var(--gap);
width: fit-content;
}
</style>

View file

@ -0,0 +1,78 @@
<script lang="ts">
export let compatibility: "goated" | "based" | "cringe";
export let image: string;
export let title: string;
export let releaseYear: number;
function capitalizeFirstLetter(string: typeof compatibility) {
if (string === "goated") {
return "Good";
} else if (string === "based") {
return "Okay";
} else if (string === "cringe") {
return "Bad";
}
}
</script>
<div class="card">
<div class="card-image">
<img src={image || ""} alt="Mario Odyssey" />
</div>
<div class="info">
<h3 class="header">{title}</h3>
<div class="content">Released: {releaseYear}</div>
<div>
Compatibility: <span class={compatibility}>{capitalizeFirstLetter(compatibility)}</span>
</div>
</div>
</div>
<style>
.card {
aspect-ratio: 1.5/2;
width: fit-content;
height: 450px;
background-color: rgb(47, 57, 76);
border-radius: 8px;
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
box-shadow: 0 0 24px rgb(32, 33, 45);
border: solid thin rgb(101, 109, 132);
}
.card-image {
border-radius: 4px;
overflow: hidden;
width: 100%;
height: 100%;
border: solid thin rgb(101, 109, 132);
}
.card-image > img {
object-fit: cover;
width: 100%;
height: 100%;
}
.header {
font-size: 28px;
}
.goated {
color: #78dca0;
text-shadow: 0px 0px 8px #78dca0;
}
.based {
color: #eab876;
text-shadow: 0px 0px 8px #eab876;
}
.cringe {
color: #ff3a3a;
text-shadow: 0px 0px 8px #ff3a3a;
}
</style>

View file

@ -0,0 +1,283 @@
<script lang="ts">
import { onMount, tick } from "svelte";
import Card from "$components/Card.svelte";
import type { ICard } from "$lib/util/types";
export let cards: ICard[];
let selectedCard = 0;
let instantSelectedCard = 0;
let animating = false;
async function go(dir: number) {
if (dir > 0) {
cardScroll({
deltaY: 100,
shiftKey: true,
preventDefault: () => {},
} as any);
} else {
cardScroll({
deltaY: -100,
shiftKey: true,
preventDefault: () => {},
} as any);
}
}
onMount(() => {
const key = (e: KeyboardEvent) => {
// right arrow, run cardScroll with positive
if (e.key === "ArrowRight") {
e.preventDefault();
go(1);
}
if (e.key === "ArrowLeft") {
e.preventDefault();
go(-1);
}
};
window.addEventListener("keydown", key);
return () => {
window.removeEventListener("keydown", key);
};
});
async function cardScroll(e: WheelEvent) {
if (!e.shiftKey || window.innerWidth < 560) return;
e.preventDefault();
const animations: Animation[] = [];
const duration = 500;
const easing = "cubic-bezier(.29,1.03,.5,1)";
if (animating) return;
animating = true;
if (e.deltaY > 0) {
instantSelectedCard = (selectedCard + 1) % cards.length;
} else {
instantSelectedCard = (selectedCard - 1 + cards.length) % cards.length;
}
const cardLeft = document.querySelector(".card-3d.left") as HTMLElement;
const cardRight = document.querySelector(".card-3d.right") as HTMLElement;
const cardCenter = document.querySelector(
".card-3d:not(.left):not(.right):not(.transition-left):not(.transition-right)",
) as HTMLElement;
const cardTransitionLeft = document.querySelector(
".card-3d.transition-left",
) as HTMLElement;
const cardTransitionRight = document.querySelector(
".card-3d.transition-right",
) as HTMLElement;
cardTransitionLeft.style.display = "block";
cardTransitionRight.style.display = "block";
setTimeout(async () => {
selectedCard = instantSelectedCard;
await tick();
cardTransitionLeft.style.display = "none";
cardTransitionRight.style.display = "none";
animations.forEach((anim) => anim.cancel());
setTimeout(() => {
animating = false;
}, 10);
}, duration);
const cardLeftBounds = cardLeft.getBoundingClientRect();
const cardRightBounds = cardRight.getBoundingClientRect();
const cardCenterBounds = cardCenter.getBoundingClientRect();
if (e.deltaY > 0) {
animations.push(
cardRight.animate(
[
{
transform: `translateX(${cardCenterBounds.left - cardRightBounds.left + 62}px)`,
},
],
{
duration,
fill: "forwards",
easing,
},
),
cardCenter.animate(
[
{
transform: `translateX(${cardLeftBounds.left - cardCenterBounds.left - 83}px) perspective(1000px) translateZ(-150px) rotateY(-50deg)`,
},
],
{
duration,
fill: "forwards",
easing,
},
),
cardLeft.animate(
[
{
opacity: 0,
transform:
"perspective(1000px) translateZ(-150px) rotateY(-80deg) translateX(-400px)",
},
],
{
duration,
fill: "forwards",
easing,
},
),
cardTransitionLeft.animate(
[
{
transform:
"translateX(1150px) perspective(1000px) translateZ(-400px) rotateY(80deg)",
opacity: 0,
},
{
transform:
"translateX(1013px) perspective(1000px) translateZ(-150px) rotateY(50deg)",
opacity: 1,
},
],
{
duration,
fill: "forwards",
easing,
},
),
);
} else {
animations.push(
cardLeft.animate(
[
{
transform: `translateX(${cardCenterBounds.left - cardLeftBounds.left + 83}px)`,
},
],
{
duration,
fill: "forwards",
easing,
},
),
cardCenter.animate(
[
{
transform: `translateX(${cardRightBounds.left - cardCenterBounds.left - 62}px) perspective(1000px) translateZ(-150px) rotateY(50deg)`,
},
],
{
duration,
fill: "forwards",
easing,
},
),
cardRight.animate(
[
{
opacity: 0,
transform:
"perspective(1000px) translateZ(-150px) rotateY(80deg) translateX(400px)",
},
],
{
duration,
fill: "forwards",
easing,
},
),
cardTransitionRight.animate(
[
{
transform:
"translateX(-1150px) perspective(1000px) translateZ(-400px) rotateY(-80deg)",
opacity: 0,
},
{
transform:
"translateX(-1013px) perspective(1000px) translateZ(-150px) rotateY(-50deg)",
opacity: 1,
},
],
{
duration,
fill: "forwards",
easing,
},
),
);
}
}
</script>
<!-- look, i don't hate the disabled, but this
site's concept is pretty inaccessible as it
is (and i just so happen to be partially blind
in an eye, so), also we do have keyboard events
we just register them through onMount() so fuck
you a11y -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="cards" on:wheel={cardScroll}>
<div class="card-3d transition-left">
<Card {...cards[(instantSelectedCard + 1) % cards.length]} />
</div>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="card-3d left" on:click={() => go(-1)}>
<Card {...cards[selectedCard - 1 < 0 ? cards.length - 1 : selectedCard - 1]} />
</div>
<div class="card-3d">
<Card {...cards[selectedCard]} />
</div>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="card-3d right" on:click={() => go(1)}>
<Card {...cards[(selectedCard + 1) % cards.length]} />
</div>
<div class="card-3d transition-right">
<Card {...cards[(instantSelectedCard + 2) % cards.length]} />
</div>
</div>
<style>
.cards {
display: flex;
max-width: 100%;
}
.card-3d {
z-index: 3;
}
.card-3d.left {
transform: perspective(1000px) translateZ(-150px) rotateY(-50deg);
z-index: 2;
}
.card-3d.right {
transform: perspective(1000px) translateZ(-150px) rotateY(50deg);
z-index: 2;
}
.card-3d {
position: relative;
}
.card-3d.transition-left,
.card-3d.transition-right {
opacity: 0;
z-index: 1;
display: none;
}
@media (max-width: 560px) {
.card-3d {
transform: none !important;
}
.cards {
flex-direction: column;
gap: 24px;
}
}
</style>

View file

@ -0,0 +1,29 @@
<script lang="ts">
export let size = 512;
</script>
<svg
width={size}
height={size}
class="logo"
viewBox="0 0 512 512"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M394.633 471.208C407.342 448.401 414.583 422.138 414.583 394.194C414.583 306.657 343.529 235.612 255.992 235.612C190.969 235.612 138.192 182.835 138.192 117.806C138.192 52.7762 190.969 0 255.992 0C397.313 0 512 114.688 512 256C512 346.235 465.227 425.613 394.633 471.208ZM255.992 52.7613C244.032 52.7613 234.316 62.4761 234.316 74.4429C234.316 86.4084 244.032 96.1245 255.992 96.1245C267.969 96.1245 277.673 86.4084 277.673 74.4429C277.673 62.4761 267.969 52.7613 255.992 52.7613ZM299.355 96.1245C287.391 96.1245 277.673 105.839 277.673 117.806C277.673 129.772 287.391 139.488 299.355 139.488C311.332 139.488 321.036 129.772 321.036 117.806C321.036 105.839 311.332 96.1245 299.355 96.1245ZM212.634 96.1245C200.669 96.1245 190.954 105.839 190.954 117.806C190.954 129.772 200.669 139.488 212.634 139.488C224.601 139.488 234.316 129.772 234.316 117.806C234.316 105.839 224.601 96.1245 212.634 96.1245ZM255.992 139.488C244.032 139.488 234.316 149.203 234.316 161.168C234.316 173.135 244.032 182.85 255.992 182.85C267.969 182.85 277.673 173.135 277.673 161.168C277.673 149.203 267.969 139.488 255.992 139.488Z"
fill="#FF3554"
/>
<path
d="M117.361 40.7917C104.657 63.5994 97.4173 89.8623 97.4173 117.806C97.4173 205.343 168.461 276.388 255.992 276.388C321.022 276.388 373.805 329.165 373.805 394.194C373.805 459.222 321.022 512 255.992 512C114.687 512 0 397.312 0 256C0 165.766 46.7638 86.3854 117.361 40.7917ZM255.992 329.149C244.032 329.149 234.316 338.865 234.316 350.831C234.316 362.798 244.032 372.512 255.992 372.512C267.969 372.512 277.673 362.798 277.673 350.831C277.673 338.865 267.969 329.149 255.992 329.149ZM299.355 372.512C287.391 372.512 277.673 382.227 277.673 394.194C277.673 406.161 287.391 415.876 299.355 415.876C311.332 415.876 321.036 406.161 321.036 394.194C321.036 382.227 311.332 372.512 299.355 372.512ZM255.992 415.876C244.032 415.876 234.316 425.59 234.316 437.557C234.316 449.523 244.032 459.239 255.992 459.239C267.969 459.239 277.673 449.523 277.673 437.557C277.673 425.59 267.969 415.876 255.992 415.876ZM212.635 372.512C200.669 372.512 190.955 382.227 190.955 394.194C190.955 406.161 200.669 415.876 212.635 415.876C224.601 415.876 234.316 406.161 234.316 394.194C234.316 382.227 224.601 372.512 212.635 372.512Z"
fill="#3A99FF"
/>
</svg>
<style>
@media (max-width: 625px) {
.logo {
flex-shrink: 0;
}
}
</style>

View file

@ -0,0 +1,53 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
export let size = 512;
const dispatcher = createEventDispatcher<{
click: void;
}>();
</script>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<svg
class="pointer"
on:click={() => dispatcher("click")}
width={size * 3.771484375}
height={size}
viewBox="0 0 1931 512"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1761.76 362.559C1828.26 362.559 1865.29 340.974 1877.74 294.87H1878.58C1878.58 316.024 1877.74 343.446 1876.9 358.402H1930.07V153.155H1876.9V237.082C1876.9 289.051 1832 318.973 1779.23 318.973C1720.61 318.973 1701.48 295.702 1701.48 257.882V153.155H1648.34V269.104C1648.34 318.559 1681.97 362.559 1761.76 362.559Z"
fill="white"
/>
<path
d="M1402.72 449C1453.41 449 1476.68 426.588 1509.92 362.978L1618.78 153.155H1564.35L1482.08 311.453H1481.25L1388.59 153.155H1326.68L1447.59 358.402H1457.98C1436.37 399.173 1422.66 407.493 1396.07 407.493C1381.52 407.493 1368.23 404.581 1361.58 402.501V443.181C1369.47 445.68 1385.68 449 1402.72 449Z"
fill="white"
/>
<path
d="M1126.74 362.559C1193.26 362.559 1230.26 340.974 1242.73 294.87H1243.56C1243.56 316.024 1242.73 343.446 1241.9 358.402H1295.04V153.155H1241.9V237.082C1241.9 289.051 1197 318.973 1144.21 318.973C1085.59 318.973 1066.47 295.702 1066.47 257.882V153.155H1013.33V269.104C1013.33 318.559 1046.95 362.559 1126.74 362.559Z"
fill="white"
/>
<path
d="M844.987 362.559C951.791 362.559 975.456 326.453 975.456 294.857C975.456 275.317 966.736 258.688 947.639 249.957C929.784 242.474 902.773 239.98 866.188 238.316C833.76 236.655 807.153 236.655 792.604 232.913C779.299 230.001 775.142 224.182 775.142 215.867C775.142 196.326 798.009 186.765 846.648 186.765C902.773 186.765 912.749 202.147 913.165 222.518H963.416C963.416 183.861 942.657 149 844.987 149C766.424 149 722 176.805 722 218.361C722 235.407 728.643 251.205 744.004 259.52C759.781 268.25 790.94 273.24 833.346 274.485C859.953 275.317 891.132 276.149 905.682 279.059C918.986 281.971 922.312 288.206 922.312 296.521C922.312 312.735 908.178 324.791 844.987 324.791C780.963 324.791 772.651 307.329 772.238 290.286H722C722 321.05 738.606 362.559 844.987 362.559Z"
fill="white"
/>
<path
d="M394.634 471.208C407.342 448.401 414.583 422.138 414.583 394.194C414.583 306.657 343.529 235.612 255.992 235.612C190.969 235.612 138.192 182.835 138.192 117.806C138.192 52.7762 190.969 0 255.992 0C397.313 0 512 114.688 512 256C512 346.235 465.227 425.613 394.634 471.208ZM255.992 52.7613C244.032 52.7613 234.316 62.4761 234.316 74.4429C234.316 86.4084 244.032 96.1245 255.992 96.1245C267.969 96.1245 277.673 86.4084 277.673 74.4429C277.673 62.4761 267.969 52.7613 255.992 52.7613ZM299.355 96.1245C287.391 96.1245 277.673 105.839 277.673 117.806C277.673 129.772 287.391 139.488 299.355 139.488C311.332 139.488 321.036 129.772 321.036 117.806C321.036 105.839 311.332 96.1245 299.355 96.1245ZM212.635 96.1245C200.669 96.1245 190.955 105.839 190.955 117.806C190.955 129.772 200.669 139.488 212.635 139.488C224.601 139.488 234.316 129.772 234.316 117.806C234.316 105.839 224.601 96.1245 212.635 96.1245ZM255.992 139.488C244.032 139.488 234.316 149.203 234.316 161.168C234.316 173.135 244.032 182.85 255.992 182.85C267.969 182.85 277.673 173.135 277.673 161.168C277.673 149.203 267.969 139.488 255.992 139.488Z"
fill="#FF3554"
/>
<path
d="M117.361 40.7917C104.657 63.5994 97.4173 89.8623 97.4173 117.806C97.4173 205.343 168.461 276.388 255.992 276.388C321.022 276.388 373.805 329.165 373.805 394.194C373.805 459.222 321.022 512 255.992 512C114.687 512 0 397.312 0 256C0 165.766 46.7638 86.3854 117.361 40.7917ZM255.992 329.149C244.032 329.149 234.316 338.865 234.316 350.831C234.316 362.798 244.032 372.512 255.992 372.512C267.969 372.512 277.673 362.798 277.673 350.831C277.673 338.865 267.969 329.149 255.992 329.149ZM299.355 372.512C287.391 372.512 277.673 382.227 277.673 394.194C277.673 406.161 287.391 415.876 299.355 415.876C311.332 415.876 321.036 406.161 321.036 394.194C321.036 382.227 311.332 372.512 299.355 372.512ZM255.992 415.876C244.032 415.876 234.316 425.59 234.316 437.557C234.316 449.523 244.032 459.239 255.992 459.239C267.969 459.239 277.673 449.523 277.673 437.557C277.673 425.59 267.969 415.876 255.992 415.876ZM212.634 372.512C200.669 372.512 190.954 382.227 190.954 394.194C190.954 406.161 200.669 415.876 212.634 415.876C224.601 415.876 234.316 406.161 234.316 394.194C234.316 382.227 224.601 372.512 212.634 372.512Z"
fill="#3A99FF"
/>
</svg>
<style>
.pointer {
cursor: pointer;
}
</style>

View file

@ -0,0 +1,20 @@
<script lang="ts">
export let size = 48;
export let color = "#FF3A3A";
</script>
<svg
class="outlined-logo"
width={size}
height={size}
viewBox="0 0 96 96"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M47.9985 2C36.6131 2 27.3713 11.2417 27.3713 22.6287C27.3713 34.0154 36.6131 43.2574 47.9985 43.2574C64.6221 43.2574 78.1148 56.7485 78.1148 73.3723C78.1148 77.301 77.3607 81.0561 75.9891 84.4997C86.9391 76.0868 94 62.8624 94 48.0005C94 22.6085 73.392 2 47.9985 2ZM25.3713 22.6287C25.3713 10.1372 35.5085 0 47.9985 0C74.4965 0 96 21.5039 96 48.0005C96 64.9212 87.228 79.8046 73.9948 88.3518L72.5787 87.0251C74.8311 82.9826 76.1148 78.3278 76.1148 73.3723C76.1148 57.8532 63.5176 45.2574 47.9985 45.2574C35.5085 45.2574 25.3713 35.1199 25.3713 22.6287ZM20.0107 11.5006C9.05987 19.9133 2 33.1381 2 48.0005C2 73.3926 22.6081 94.001 47.9985 94.001C59.3855 94.001 68.6282 84.759 68.6282 73.3723C68.6282 61.9857 59.3855 52.7436 47.9985 52.7436C31.3761 52.7436 17.8852 39.2524 17.8852 22.6287C17.8852 18.6998 18.6393 14.9443 20.0107 11.5006ZM0 48.0005C0 31.0799 8.77019 16.1962 22.0042 7.64919L23.4203 8.97585C21.1686 13.0184 19.8852 17.6732 19.8852 22.6287C19.8852 38.1479 32.4807 50.7436 47.9985 50.7436C60.4899 50.7436 70.6282 60.881 70.6282 73.3723C70.6282 85.8636 60.4899 96.001 47.9985 96.001C21.5034 96.001 0 74.4971 0 48.0005ZM43.0189 14.6674C43.0189 11.9182 45.2503 9.68675 47.9985 9.68675C50.7501 9.68675 52.9791 11.9184 52.9791 14.6674C52.9791 17.4161 50.7502 19.648 47.9985 19.648C45.2503 19.648 43.0189 17.4163 43.0189 14.6674ZM47.9985 11.6867C46.3552 11.6867 45.0189 13.0225 45.0189 14.6674C45.0189 16.3121 46.3552 17.648 47.9985 17.648C49.6448 17.648 50.9791 16.3123 50.9791 14.6674C50.9791 13.0223 49.6449 11.6867 47.9985 11.6867ZM35.0581 22.6287C35.0581 19.8794 37.2893 17.648 40.0384 17.648C42.7877 17.648 45.0189 19.8794 45.0189 22.6287C45.0189 25.3777 42.7877 27.6094 40.0384 27.6094C37.2892 27.6094 35.0581 25.3777 35.0581 22.6287ZM40.0384 19.648C38.3939 19.648 37.0581 20.9839 37.0581 22.6287C37.0581 24.2733 38.394 25.6094 40.0384 25.6094C41.683 25.6094 43.0189 24.2733 43.0189 22.6287C43.0189 20.9839 41.6831 19.648 40.0384 19.648ZM50.9791 22.6287C50.9791 19.8793 53.2109 17.648 55.9596 17.648C58.7113 17.648 60.9402 19.8797 60.9402 22.6287C60.9402 25.3774 58.7113 27.6094 55.9596 27.6094C53.2109 27.6094 50.9791 25.3778 50.9791 22.6287ZM55.9596 19.648C54.3153 19.648 52.9791 20.984 52.9791 22.6287C52.9791 24.2732 54.3154 25.6094 55.9596 25.6094C57.606 25.6094 58.9402 24.2736 58.9402 22.6287C58.9402 20.9836 57.606 19.648 55.9596 19.648ZM43.0189 30.5897C43.0189 27.8407 45.2504 25.6094 47.9985 25.6094C50.7501 25.6094 52.9791 27.841 52.9791 30.5897C52.9791 33.3387 50.7501 35.5704 47.9985 35.5704C45.2503 35.5704 43.0189 33.3389 43.0189 30.5897ZM47.9985 27.6094C46.3551 27.6094 45.0189 28.9451 45.0189 30.5897C45.0189 32.2347 46.3552 33.5704 47.9985 33.5704C49.6449 33.5704 50.9791 32.2349 50.9791 30.5897C50.9791 28.9449 49.6449 27.6094 47.9985 27.6094ZM43.0189 65.411C43.0189 62.6621 45.2503 60.4304 47.9985 60.4304C50.7502 60.4304 52.979 62.6623 52.979 65.411C52.979 68.16 50.7501 70.3917 47.9985 70.3917C45.2503 70.3917 43.0189 68.1602 43.0189 65.411ZM47.9985 62.4304C46.3552 62.4304 45.0189 63.7663 45.0189 65.411C45.0189 67.056 46.3551 68.3917 47.9985 68.3917C49.6449 68.3917 50.979 67.0562 50.979 65.411C50.979 63.7661 49.6448 62.4304 47.9985 62.4304ZM35.058 73.3723C35.058 70.623 37.2892 68.3917 40.0384 68.3917C42.7877 68.3917 45.0189 70.623 45.0189 73.3723C45.0189 76.1217 42.7877 78.353 40.0384 78.353C37.2892 78.353 35.058 76.1216 35.058 73.3723ZM40.0384 70.3917C38.3939 70.3917 37.058 71.7275 37.058 73.3723C37.058 75.0172 38.3939 76.353 40.0384 76.353C41.6831 76.353 43.0189 75.0171 43.0189 73.3723C43.0189 71.7275 41.6831 70.3917 40.0384 70.3917ZM50.979 73.3723C50.979 70.6229 53.2109 68.3917 55.9596 68.3917C58.7113 68.3917 60.9402 70.6233 60.9402 73.3723C60.9402 76.1213 58.7113 78.353 55.9596 78.353C53.2109 78.353 50.979 76.1217 50.979 73.3723ZM55.9596 70.3917C54.3153 70.3917 52.979 71.7276 52.979 73.3723C52.979 75.017 54.3153 76.353 55.9596 76.353C57.606 76.353 58.9402 75.0175 58.9402 73.3723C58.9402 71.7272 57.606 70.3917 55.9596 70.3917ZM43.0189 81.3336C43.0189 78.5844 45.2503 76.353 47.9985 76.353C50.7501 76.353 52.979 78.5846 52.979 81.3336C52.979 84.0823 50.7502 86.3143 47.9985 86.3143C45.2503 86.3143 43.0189 84.0825 43.0189 81.3336ZM47.9985 78.353C46.3551 78.353 45.0189 79.6887 45.0189 81.3336C45.0189 82.9783 46.3552 84.3143 47.9985 84.3143C49.6448 84.3143 50.979 82.9785 50.979 81.3336C50.979 79.6885 49.6449 78.353 47.9985 78.353Z"
fill={color}
/>
</svg>

View file

@ -0,0 +1,75 @@
<script lang="ts">
export let progress = 1;
export let total = 1;
</script>
<div class="progress-bar">
<div class="overflow-handler">
<div
class="progress"
style="width: {((progress === 0 ? 1 : progress) / (total === 0 ? 1 : total)) * 100}%"
></div>
</div>
<div class="glow-container">
<div
class="glow"
style="width: {((progress === 0 ? 1 : progress) / (total === 0 ? 1 : total)) * 100}%"
></div>
</div>
</div>
<style>
.progress-bar {
position: relative;
width: 100%;
height: 8px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 4px;
}
.overflow-handler {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
border-radius: 4px;
}
.progress {
height: 100%;
/* background-color: rgb(77, 156, 199); */
transition: 0.5s ease-in-out width;
clip-path: inset(0);
}
.progress::before {
width: 100%;
content: "";
position: absolute;
inset: 0;
background: linear-gradient(to right, #ff3a3a, rgb(210, 103, 201), #3a99ff);
}
.glow-container {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
filter: blur(18px);
}
.glow {
height: 100%;
transition: 0.5s ease-in-out width;
clip-path: inset(-36px -24px);
}
.glow::before {
width: 100%;
content: "";
position: absolute;
inset: 0;
background: linear-gradient(to right, #ff3a3a, rgb(210, 103, 201), #3a99ff);
}
</style>

View file

@ -0,0 +1,25 @@
<script lang="ts">
export let size: number;
export let color: string;
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width={size}
height={size}
viewBox="0 0 100 125"
style="enable-background:new 0 0 100 100;"
xml:space="preserve"
fill={color}
><path
d="M32,41v18c0,9.9,8.1,18,18,18c9.9,0,18-8.1,18-18V41c0-9.9-8.1-18-18-18C40.1,23,32,31.1,32,41z M50,27c7.7,0,14,6.3,14,14 v18c0,7.7-6.3,14-14,14s-14-6.3-14-14V41C36,33.3,42.3,27,50,27z"
/><path
d="M50,44c1.1,0,2-0.9,2-2v-6c0-1.1-0.9-2-2-2s-2,0.9-2,2v6C48,43.1,48.9,44,50,44z"
/><path
d="M48.6,92.4C49,92.8,49.5,93,50,93s1-0.2,1.4-0.6l5-5c0.8-0.8,0.8-2,0-2.8s-2-0.8-2.8,0L50,88.2l-3.6-3.6 c-0.8-0.8-2-0.8-2.8,0c-0.8,0.8-0.8,2,0,2.8L48.6,92.4z"
/><path
d="M48.6,7.6l-5,5c-0.8,0.8-0.8,2,0,2.8C44,15.8,44.5,16,45,16s1-0.2,1.4-0.6l3.6-3.6l3.6,3.6C54,15.8,54.5,16,55,16 s1-0.2,1.4-0.6c0.8-0.8,0.8-2,0-2.8l-5-5C50.6,6.8,49.4,6.8,48.6,7.6z"
/></svg
>

View file

@ -0,0 +1,74 @@
<div class="spinner">
{#each Array(9) as _, i}
<div class="bounce" />
{/each}
</div>
<style>
@keyframes flash {
0% {
opacity: 1;
box-shadow: 0 0 10px 0px white;
}
30% {
opacity: 0.4;
box-shadow: 0 0 4px 0px white;
}
100% {
opacity: 0;
}
}
.spinner {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 6px;
justify-content: center;
align-items: center;
width: fit-content;
height: fit-content;
}
.bounce {
aspect-ratio: 1/1;
width: 8px;
background-color: white;
opacity: 0.5;
}
.bounce:not(:nth-child(5)) {
animation: linear 0.8s infinite flash;
}
.bounce:nth-child(1) {
animation-delay: 0.1s;
}
.bounce:nth-child(2) {
animation-delay: 0.2s;
}
.bounce:nth-child(3) {
animation-delay: 0.3s;
}
.bounce:nth-child(6) {
animation-delay: 0.4s;
}
.bounce:nth-child(9) {
animation-delay: 0.5s;
}
.bounce:nth-child(8) {
animation-delay: 0.6s;
}
.bounce:nth-child(7) {
animation-delay: 0.7s;
}
.bounce:nth-child(4) {
animation-delay: 0.8s;
}
</style>

View file

@ -0,0 +1,28 @@
<script lang="ts">
export let size = 256;
</script>
<svg
width={size * 4.02734375}
height={size}
viewBox="0 0 1031 256"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M887.264 182.237C944.012 182.237 975.604 163.818 986.232 124.476H986.946C986.946 142.527 986.232 165.928 985.517 178.689H1030.89V3.54565H985.517V75.1629C985.517 119.51 947.205 145.043 902.172 145.043C852.144 145.043 835.826 125.186 835.826 92.9126V3.54565H790.478V102.489C790.478 144.69 819.175 182.237 887.264 182.237Z"
fill="white"
/>
<path
d="M580.878 256C624.135 256 643.991 236.875 672.357 182.594L765.256 3.54565H718.805L648.601 138.626H647.891L568.823 3.54565H515.992L619.17 178.689H628.036C609.599 213.481 597.897 220.581 575.204 220.581C562.795 220.581 551.449 218.096 545.776 216.321V251.035C552.512 253.167 566.341 256 580.878 256Z"
fill="white"
/>
<path
d="M345.383 182.237C402.141 182.237 433.714 163.818 444.354 124.476H445.064C445.064 142.527 444.355 165.928 443.647 178.689H488.994V3.54565H443.647V75.1629C443.647 119.51 405.334 145.043 360.283 145.043C310.265 145.043 293.946 125.186 293.946 92.9126V3.54565H248.599V102.489C248.599 144.69 277.295 182.237 345.383 182.237Z"
fill="white"
/>
<path
d="M104.949 182.237C196.088 182.237 216.283 151.426 216.283 124.465C216.283 107.791 208.842 93.6001 192.545 86.1497C177.31 79.7643 154.26 77.6366 123.04 76.2166C95.3684 74.7989 72.6644 74.7989 60.2485 71.6062C48.8954 69.1212 45.3478 64.1557 45.3478 57.0603C45.3478 40.3845 64.8612 32.2264 106.367 32.2264C154.259 32.2264 162.773 45.3522 163.128 62.7357H206.008C206.008 29.7481 188.294 0 104.949 0C37.9084 0 0 23.7266 0 59.188C0 73.7339 5.66882 87.2146 18.7768 94.3101C32.2398 101.76 58.8286 106.018 95.0157 107.081C117.72 107.791 144.326 108.501 156.742 110.984C168.095 113.469 170.933 118.789 170.933 125.885C170.933 139.72 158.872 150.008 104.949 150.008C50.3154 150.008 43.2222 135.108 42.8694 120.564H0C0 146.816 14.1707 182.237 104.949 182.237Z"
fill="white"
/>
</svg>

80
src/lib/css/fluent.css Normal file
View file

@ -0,0 +1,80 @@
@font-face {
font-family: "Segoe UI Variable";
src: url($assets/fonts/suivar.ttf);
}
:root {
--mica-accent: rgba(47, 53, 72, 0.44);
--fluent-stroke-color: rgba(255, 255, 255, 0.15);
--fluent-stroke-width: thin;
--fluent-stroke: solid var(--fluent-stroke-color) var(--fluent-stroke-width);
--text-font: "Segoe UI Variable", sans-serif !important;
--text-color: #ffffff !important;
--text-size: 11pt !important;
--on-mica-bg: rgba(255, 255, 255, 0.08);
--fluent-ease-in: cubic-bezier(0.6, 0, 0.8, 0.6);
--fluent-ease-out: cubic-bezier(0.2, 0.8, 0.4, 1);
user-select: none;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: "Segoe UI Variable", sans-serif !important;
font-size: 24px !important;
font-weight: 600;
}
.fluent-press {
transition: 0.2s transform var(--fluent-ease-out);
}
.fluent-press:active {
/* transform: scale(0.97); */
opacity: 0.75;
}
.mica-backdrop {
backdrop-filter: blur(200px);
background-color: var(--mica-accent);
}
.on-mica-bg {
background-color: var(--on-mica-bg);
}
.window {
border: var(--fluent-stroke);
border-radius: 8px;
box-shadow: 0 0 40px 0 rgba(0, 0, 0, 0.5);
overflow: hidden;
}
button {
border: var(--fluent-stroke) !important;
border-radius: 4px !important;
background-color: rgba(255, 255, 255, 0.15) !important;
height: 32px;
padding: 0 12px;
font-size: 10pt !important;
transition: 0.3s var(--fluent-ease-out);
transition-property: background-color, opacity;
}
button * {
font-size: 10pt !important;
}
button:hover {
background-color: rgba(255, 255, 255, 0.25);
}
button:active {
filter: none;
transition: 0.3s var(--fluent-ease-out);
background-color: rgba(255, 255, 255, 0.2);
opacity: 0.8;
}

72
src/lib/css/index.css Normal file
View file

@ -0,0 +1,72 @@
:root {
--text-color: #bebbdd;
--text-font: "Jost", sans-serif;
--header-font: "Jost", sans-serif;
--page-bg: rgb(16, 22, 35);
--color-primary: #202b41;
--border-color: rgb(53, 62, 82);
--border-primary: solid thin var(--border-color);
--text-size: 14pt;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
color: var(--text-color);
font-family: var(--text-font);
font-size: var(--text-size);
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: var(--header-font) !important;
font-size: 64px;
}
body {
background-color: black;
height: fit-content;
overflow-x: hidden;
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #2b3947;
}
::-webkit-scrollbar-thumb {
background: #3c4f7c;
border-radius: 12px;
}
::-webkit-scrollbar-thumb:hover {
background: #526ca8;
}
button {
appearance: none;
border: none;
padding: 8px 32px;
background-color: var(--color-primary);
border: var(--border-primary);
border-radius: 16px;
cursor: pointer;
transition: 0.2s ease-in-out filter;
}
button:hover {
filter: brightness(1.1);
}
button:active {
transition: 0.05s ease-in-out filter;
filter: brightness(0.9);
}

View file

@ -0,0 +1,5 @@
{
"landingHeader": "suyu",
"landingOne": "Suyu is an open-source, Switch compatible emulator with almost full coverage of the game library.",
"landingCardHeader": "We care about preservation"
}

1
src/lib/index.ts Normal file
View file

@ -0,0 +1 @@
// place files you want to import through the `$lib` alias in this folder.

18
src/lib/util/index.ts Normal file
View file

@ -0,0 +1,18 @@
export function generateBgSvg(size: number, color: string) {
const svg = `<svg
class="outlined-logo"
width="${size}"
height="${size}"
viewBox="0 0 96 96"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M47.9985 2C36.6131 2 27.3713 11.2417 27.3713 22.6287C27.3713 34.0154 36.6131 43.2574 47.9985 43.2574C64.6221 43.2574 78.1148 56.7485 78.1148 73.3723C78.1148 77.301 77.3607 81.0561 75.9891 84.4997C86.9391 76.0868 94 62.8624 94 48.0005C94 22.6085 73.392 2 47.9985 2ZM25.3713 22.6287C25.3713 10.1372 35.5085 0 47.9985 0C74.4965 0 96 21.5039 96 48.0005C96 64.9212 87.228 79.8046 73.9948 88.3518L72.5787 87.0251C74.8311 82.9826 76.1148 78.3278 76.1148 73.3723C76.1148 57.8532 63.5176 45.2574 47.9985 45.2574C35.5085 45.2574 25.3713 35.1199 25.3713 22.6287ZM20.0107 11.5006C9.05987 19.9133 2 33.1381 2 48.0005C2 73.3926 22.6081 94.001 47.9985 94.001C59.3855 94.001 68.6282 84.759 68.6282 73.3723C68.6282 61.9857 59.3855 52.7436 47.9985 52.7436C31.3761 52.7436 17.8852 39.2524 17.8852 22.6287C17.8852 18.6998 18.6393 14.9443 20.0107 11.5006ZM0 48.0005C0 31.0799 8.77019 16.1962 22.0042 7.64919L23.4203 8.97585C21.1686 13.0184 19.8852 17.6732 19.8852 22.6287C19.8852 38.1479 32.4807 50.7436 47.9985 50.7436C60.4899 50.7436 70.6282 60.881 70.6282 73.3723C70.6282 85.8636 60.4899 96.001 47.9985 96.001C21.5034 96.001 0 74.4971 0 48.0005ZM43.0189 14.6674C43.0189 11.9182 45.2503 9.68675 47.9985 9.68675C50.7501 9.68675 52.9791 11.9184 52.9791 14.6674C52.9791 17.4161 50.7502 19.648 47.9985 19.648C45.2503 19.648 43.0189 17.4163 43.0189 14.6674ZM47.9985 11.6867C46.3552 11.6867 45.0189 13.0225 45.0189 14.6674C45.0189 16.3121 46.3552 17.648 47.9985 17.648C49.6448 17.648 50.9791 16.3123 50.9791 14.6674C50.9791 13.0223 49.6449 11.6867 47.9985 11.6867ZM35.0581 22.6287C35.0581 19.8794 37.2893 17.648 40.0384 17.648C42.7877 17.648 45.0189 19.8794 45.0189 22.6287C45.0189 25.3777 42.7877 27.6094 40.0384 27.6094C37.2892 27.6094 35.0581 25.3777 35.0581 22.6287ZM40.0384 19.648C38.3939 19.648 37.0581 20.9839 37.0581 22.6287C37.0581 24.2733 38.394 25.6094 40.0384 25.6094C41.683 25.6094 43.0189 24.2733 43.0189 22.6287C43.0189 20.9839 41.6831 19.648 40.0384 19.648ZM50.9791 22.6287C50.9791 19.8793 53.2109 17.648 55.9596 17.648C58.7113 17.648 60.9402 19.8797 60.9402 22.6287C60.9402 25.3774 58.7113 27.6094 55.9596 27.6094C53.2109 27.6094 50.9791 25.3778 50.9791 22.6287ZM55.9596 19.648C54.3153 19.648 52.9791 20.984 52.9791 22.6287C52.9791 24.2732 54.3154 25.6094 55.9596 25.6094C57.606 25.6094 58.9402 24.2736 58.9402 22.6287C58.9402 20.9836 57.606 19.648 55.9596 19.648ZM43.0189 30.5897C43.0189 27.8407 45.2504 25.6094 47.9985 25.6094C50.7501 25.6094 52.9791 27.841 52.9791 30.5897C52.9791 33.3387 50.7501 35.5704 47.9985 35.5704C45.2503 35.5704 43.0189 33.3389 43.0189 30.5897ZM47.9985 27.6094C46.3551 27.6094 45.0189 28.9451 45.0189 30.5897C45.0189 32.2347 46.3552 33.5704 47.9985 33.5704C49.6449 33.5704 50.9791 32.2349 50.9791 30.5897C50.9791 28.9449 49.6449 27.6094 47.9985 27.6094ZM43.0189 65.411C43.0189 62.6621 45.2503 60.4304 47.9985 60.4304C50.7502 60.4304 52.979 62.6623 52.979 65.411C52.979 68.16 50.7501 70.3917 47.9985 70.3917C45.2503 70.3917 43.0189 68.1602 43.0189 65.411ZM47.9985 62.4304C46.3552 62.4304 45.0189 63.7663 45.0189 65.411C45.0189 67.056 46.3551 68.3917 47.9985 68.3917C49.6449 68.3917 50.979 67.0562 50.979 65.411C50.979 63.7661 49.6448 62.4304 47.9985 62.4304ZM35.058 73.3723C35.058 70.623 37.2892 68.3917 40.0384 68.3917C42.7877 68.3917 45.0189 70.623 45.0189 73.3723C45.0189 76.1217 42.7877 78.353 40.0384 78.353C37.2892 78.353 35.058 76.1216 35.058 73.3723ZM40.0384 70.3917C38.3939 70.3917 37.058 71.7275 37.058 73.3723C37.058 75.0172 38.3939 76.353 40.0384 76.353C41.6831 76.353 43.0189 75.0171 43.0189 73.3723C43.0189 71.7275 41.6831 70.3917 40.0384 70.3917ZM50.979 73.3723C50.979 70.6229 53.2109 68.3917 55.9596 68.3917C58.7113 68.3917 60.9402 70.6233 60.9402 73.3723C60.9402 76.1213 58.7113 78.353 55.9596 78.353C53.2109 78.353 50.979 76.1217 50.979 73.3723ZM55.9596 70.3917C54.3153 70.3917 52.979 71.7276 52.979 73.3723C52.979 75.017 54.3153 76.353 55.9596 76.353C57.606 76.353 58.9402 75.0175 58.9402 73.3723C58.9402 71.7272 57.606 70.3917 55.9596 70.3917ZM43.0189 81.3336C43.0189 78.5844 45.2503 76.353 47.9985 76.353C50.7501 76.353 52.979 78.5846 52.979 81.3336C52.979 84.0823 50.7502 86.3143 47.9985 86.3143C45.2503 86.3143 43.0189 84.0825 43.0189 81.3336ZM47.9985 78.353C46.3551 78.353 45.0189 79.6887 45.0189 81.3336C45.0189 82.9783 46.3552 84.3143 47.9985 84.3143C49.6448 84.3143 50.979 82.9785 50.979 81.3336C50.979 79.6885 49.6449 78.353 47.9985 78.353Z"
fill="${color}"
/>
</svg>`;
return svg;
}

View file

@ -0,0 +1,6 @@
export interface ICard {
title: string;
compatibility: "goated" | "based" | "cringe";
image: string;
releaseYear: number;
}

113
src/routes/+layout.svelte Normal file
View file

@ -0,0 +1,113 @@
<script lang="ts">
import "../app.pcss";
import { goto } from "$app/navigation";
import BackgroundProvider from "$components/BackgroundProvider.svelte";
import LogoWithTextHorizontal from "$components/LogoWithTextHorizontal.svelte";
import { page } from "$app/stores";
import "$lib/css/index.css";
import { Button } from "flowbite-svelte";
import { CodeBranchOutline, DiscordSolid, DownloadOutline } from "flowbite-svelte-icons";
const excludedRoutesNav = ["/mockup/boot", "/mockup/w11"];
const excludedRoutesBg = ["/mockup", "/mockup/w11"];
console.log($page.url);
$: isNavExcluded = excludedRoutesNav.some((route) => $page.url?.pathname.startsWith(route));
$: isBgExcluded = excludedRoutesBg.some((route) => $page.url?.pathname === route);
</script>
{#if !isNavExcluded}
<div class="header">
<div class="left">
<LogoWithTextHorizontal on:click={() => goto("/")} size={50} />
</div>
<div class="right">
<a href="https://gitlab.com/suyu-emu/suyu" target="_blank" rel="noopener noreferrer">
<Button class="!p-2" pill={true}>
<CodeBranchOutline />
</Button>
</a>
<a href="https://discord.gg/suyu" target="_blank" rel="noopener noreferrer">
<Button class="!p-2" pill={true}>
<DiscordSolid />
</Button>
</a>
</div>
</div>
{/if}
{#if !isBgExcluded}
<BackgroundProvider size={80} gap={12} speed={1}></BackgroundProvider>
<div class="below">
<div class="page-contents">
<slot />
</div>
<div class="bullshit-flex-container">
<div class="bullshit-flex-placeholder"></div>
<div class="bg-below-gradient"></div>
</div>
</div>
{:else}
<slot />
{/if}
<style>
.below {
z-index: 5;
position: relative;
display: flex;
flex-direction: column;
}
.header {
position: sticky;
/* on overscroll, stick to the top */
overscroll-behavior: contain;
top: 0;
left: 0;
width: 100%;
height: 80px;
background-color: color-mix(in srgb, var(--color-primary), transparent 50%);
border-bottom: var(--border-primary);
z-index: 1000;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
align-items: center;
display: flex;
padding: 0 32px 0 16px;
}
.bullshit-flex-container {
display: flex;
height: 100%;
width: 100%;
position: absolute;
flex-direction: column;
z-index: -1;
}
.bullshit-flex-placeholder {
/* 100vh height */
height: calc(100vh - 162px);
width: 100%;
}
.bg-below-gradient {
width: 100%;
flex-grow: 1;
flex-shrink: 0;
background-color: var(--page-bg);
background-size: 100% 100%;
z-index: -1;
}
.left {
display: flex;
align-items: center;
flex-grow: 1;
}
.right {
display: flex;
align-items: center;
gap: 1rem;
}
</style>

204
src/routes/+page.svelte Normal file
View file

@ -0,0 +1,204 @@
<script lang="ts">
import Logo from "$components/Logo.svelte";
import { onMount } from "svelte";
import strings from "$lib/data/strings.json";
import odyssey from "$assets/cards/Super-Mario-Odyssey.jpg";
import ScrollIcon from "$components/ScrollIcon.svelte";
import totk from "$assets/cards/totk.webp";
import scarletviolet from "$assets/cards/scarlet-violet.webp";
import CardCarousel from "$components/CardCarousel.svelte";
import Wordmark from "$components/Wordmark.svelte";
let logoSizes = {
small: 256,
large: 378,
};
let logoSize = logoSizes.large;
onMount(() => {
function onResize() {
if (window.innerWidth < 625) {
logoSize = logoSizes.small;
} else {
logoSize = logoSizes.large;
}
}
onResize();
window.addEventListener("resize", onResize);
return () => {
window.removeEventListener("resize", onResize);
};
});
</script>
<div class="page">
<div class="contents-container">
<Logo size={logoSize} />
<div class="hero-text">
<h1 class="hero-header">
<Wordmark size={80} />
</h1>
<p>
{strings.landingOne}
</p>
</div>
</div>
<div class="below">
<div class="absolute-center">
<h1>We care about preservation...</h1>
<CardCarousel
cards={[
{
title: "Super Mario Odyssey",
compatibility: "goated",
image: odyssey,
releaseYear: 2017,
},
{
title: "The Legend of Zelda: Tears of the Kingdom",
compatibility: "based",
image: totk,
releaseYear: 2023,
},
{
title: "Pokémon Scarlet and Pokémon Violet",
compatibility: "cringe",
image: scarletviolet,
releaseYear: 2022,
},
]}
/>
<div class="instructions">
<div class="key">Shift</div>
<span class="plus">+</span>
<ScrollIcon size={48} color="#bebbdd" />
</div>
<p>
...so we're setting out to continue the beloved Yuzu emulator, as a non-profit drive
for hardware preservation and research.
</p>
<div class="buttons">
<button
on:click={() =>
window.open("https://gitlab.com/suyu-emu/suyu", "_blank", "noopener noreferrer")}
class="download">Git Repo</button
>
<button
class="discord"
on:click={() => window.open("https://discord.gg/suyu", "_blank", "noopener noreferrer")}
>Discord</button
>
</div>
</div>
</div>
</div>
<style>
.buttons {
display: flex;
justify-content: center;
gap: 16px;
margin-top: 20px;
}
.instructions {
display: flex;
align-items: center;
margin-top: 24px;
opacity: 0.25;
position: absolute;
top: calc(100% - 162px);
left: 50%;
transform: translateX(-50%);
}
.plus {
margin-left: 15px;
}
.plus,
.key {
margin-top: -14px;
}
.key {
font-size: 12px;
background-color: rgb(59, 55, 78);
border-radius: 4px;
border: solid 1px rgb(137, 129, 176);
padding: 4px 12px;
}
.contents-container {
width: calc(100vw - 17px);
height: calc(100vh - 160px);
display: flex;
justify-content: center;
align-items: center;
gap: 96px;
box-sizing: border-box;
padding-right: 128px;
}
.hero-header {
margin-top: -2rem;
margin-bottom: 2rem;
}
.hero-text {
max-width: 400px;
}
@media (max-width: 625px) {
.contents-container {
flex-direction: column;
gap: 96px;
padding-right: 0;
text-align: center;
padding-left: 16px;
}
}
@media (max-width: 560px) {
.absolute-center {
position: relative !important;
transform: none !important;
left: 0 !important;
display: flex;
flex-direction: column;
align-items: center;
}
.instructions {
display: none;
}
}
.below {
width: 100%;
min-height: calc(106vh - 80px);
height: fit-content;
padding-bottom: 80px;
position: relative;
}
.absolute-center {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.absolute-center > h1 {
text-align: center;
margin-bottom: 18px;
margin-top: 36px;
}
.absolute-center > p {
text-align: center;
margin-top: 64px;
}
</style>

View file

@ -0,0 +1,11 @@
import type { PageServerLoad } from "./$types";
import { getQueriedGamesAmerica, type GameUS } from "nintendo-switch-eshop";
export const load: PageServerLoad = async ({ params }) => {
const games = await getQueriedGamesAmerica(params.game);
return {
props: {
games,
},
};
};

View file

@ -0,0 +1,150 @@
<script lang="ts">
import ProgressBar from "$components/ProgressBar.svelte";
import { onMount } from "svelte";
import type { PageData } from "./$types";
import Logo from "$components/Logo.svelte";
import { page } from "$app/stores";
let shadersDone = 0;
const shadersTotal = 8146;
export let data: PageData;
$: game =
data.props.games.find(
(g) => g.title.trim().toLowerCase() === $page.params.game.trim().toLowerCase(),
) || data.props.games[0];
onMount(() => {
const interval = setInterval(() => {
shadersDone += Math.floor(Math.random() * 150);
if (shadersDone >= shadersTotal) {
clearInterval(interval);
shadersDone = shadersTotal;
}
}, 100);
});
</script>
<div class="body">
<div class="align-bottom">
<img
alt="Box art for {game.title}"
src={`https://assets.nintendo.com/image/upload/ar_16:9,c_lpad,w_656/b_white/f_auto/q_auto/${game.productImage}`}
/>
<div class="main-text">
<p class="launching">Launching <span class="bold">{game.title}</span></p>
<p>Shaders compiled: {shadersDone} / {shadersTotal}</p>
<div class="progress-bar">
<ProgressBar progress={shadersDone} total={shadersTotal} />
</div>
</div>
<div class="logo-spinner-container">
<div class="logo">
<Logo size={128} />
</div>
</div>
</div>
</div>
<style>
@keyframes spin {
/* 0% {
transform: none;
animation-timing-function: cubic-bezier(1, 0, 1, 1);
}
25% {
animation-timing-function: ease-out;
transform: scale(0.75) rotateZ(30deg);
}
30% {
transform: scale(0.75) rotateZ(10deg);
animation-timing-function: cubic-bezier(0.77, 0, 0.75, 0.37);
}
40% {
transform: scale(1.1) rotateZ(375deg);
animation-timing-function: cubic-bezier(0, 0.92, 0.21, 0.97);
}
42% {
transform: scale(1) rotateZ(780deg);
}
70%,
100% {
transform: scale(1) rotateZ(720deg);
} */
0% {
transform: none;
}
100% {
transform: rotateZ(360deg);
}
}
.logo-spinner-container {
margin-left: 120px;
}
.logo {
animation: spin 2s reverse infinite cubic-bezier(0.8, 0, 0.2, 1);
}
.body {
display: flex;
width: 100vw;
height: 100vh;
padding: 150px;
}
.progress-bar {
width: 100%;
margin-top: 16px;
}
.align-bottom {
display: flex;
justify-content: center;
align-items: flex-end;
height: 100%;
width: 100%;
}
.align-bottom img {
aspect-ratio: 1/1;
width: 300px;
object-fit: cover;
object-position: center center;
border: solid thin rgb(145, 173, 192);
border-radius: 24px;
box-shadow: 0 0 32px 0px rgba(145, 173, 192, 0.463);
}
.main-text {
width: calc(100% - 615px);
margin-left: 64px;
display: flex;
flex-direction: column;
gap: 8px;
flex-grow: 1;
}
.launching,
.launching > * {
font-size: 32px;
white-space: nowrap;
overflow: hidden;
}
.launching {
--mask-image: linear-gradient(
90deg,
black,
black calc(100% - 150px),
transparent calc(100% - 25px)
);
-webkit-mask-image: var(--mask-image);
mask-image: var(--mask-image);
}
.bold {
font-weight: bold;
width: 100%;
}
</style>

View file

@ -0,0 +1,228 @@
<script lang="ts">
import "$lib/css/fluent.css";
import Logo from "$components/Logo.svelte";
import close from "$assets/mockups/close.svg";
import maximize from "$assets/mockups/maximize.svg";
import minimize from "$assets/mockups/minimize.svg";
import Sidebar from "./components/Sidebar.svelte";
import { onMount, type SvelteComponent } from "svelte";
import LibraryPage from "./pages/Library.svelte";
import Library from "./components/icons/Library.svelte";
import Settings from "./components/icons/Settings.svelte";
import Community from "./components/icons/Community.svelte";
import Globe from "./components/icons/Globe.svelte";
import QA from "./components/icons/QA.svelte";
let Page: typeof SvelteComponent<{}>;
let tbMain: HTMLDivElement;
let tbFiller: HTMLDivElement;
let windowEl: HTMLDivElement;
let downPos: { x: number; y: number };
function changePage(e: CustomEvent<{ page: typeof SvelteComponent<{}> }>) {
Page = e.detail.page;
}
onMount(() => {
const left = Math.round((window.innerWidth - windowEl.offsetWidth) / 2);
const top = Math.round((window.innerHeight - windowEl.offsetHeight) / 2);
windowEl.style.left = `${left % 2 === 0 ? left : left + 1}px`;
windowEl.style.top = `${top % 2 === 0 ? top : top + 1}px`;
function onMove(e: MouseEvent) {
windowEl.style.left = `${windowEl.offsetLeft + e.clientX - downPos.x}px`;
windowEl.style.top = `${windowEl.offsetTop + e.clientY - downPos.y}px`;
downPos = { x: e.clientX, y: e.clientY };
}
function onMouseDown(e: MouseEvent) {
downPos = { x: e.clientX, y: e.clientY };
document.addEventListener("mousemove", onMove);
document.addEventListener("mouseup", onMouseUp);
}
function onMouseUp(e: MouseEvent) {
document.removeEventListener("mousemove", onMove);
document.removeEventListener("mouseup", onMouseUp);
}
tbFiller.addEventListener("mousedown", onMouseDown);
tbMain.addEventListener("mousedown", onMouseDown);
return () => {
document.removeEventListener("mousemove", onMove);
document.removeEventListener("mouseup", onMouseUp);
tbFiller.removeEventListener("mousedown", onMouseDown);
tbMain.removeEventListener("mousedown", onMouseDown);
};
});
</script>
<div class="root">
<div class="window mica-backdrop" bind:this={windowEl}>
<div class="window-contents">
<div class="titlebar-sidebar">
<div bind:this={tbMain} class="titlebar on-mica-bg">
<div class="titlebar-contents">
<div class="icon">
<Logo size={16} />
</div>
<div class="title">suyu | dev-1574a6818</div>
</div>
</div>
<div class="sidebar on-mica-bg">
<Sidebar
itemsTop={[
{
icon: Library,
text: "Library",
},
{
icon: Settings,
text: "Settings",
},
{
icon: Community,
text: "Multiplayer",
},
]}
itemsBottom={[
{
text: "Offical Website",
icon: Globe,
onclick: () => window.open("https://suyu.dev", "_blank"),
},
{
text: "Discord",
icon: QA,
onclick: () => window.open("https://discord.gg/suyu", "_blank"),
},
]}
on:changepage={changePage}
/>
</div>
</div>
<div class="filler-with-content">
<div bind:this={tbFiller} class="titlebar-filler on-mica-bg">
<div class="titlebar-buttons">
<div class="tb-button">
<img src={minimize} alt="Minimize" />
</div>
<div class="tb-button">
<img src={maximize} alt="Maximize" />
</div>
<div class="tb-button close">
<img src={close} alt="Close" />
</div>
</div>
</div>
<div class="window-body">
<svelte:component this={Page || LibraryPage} />
</div>
</div>
</div>
<div class="disclaimer">
<h1>Disclaimer</h1>
<p>
This is a <b>concept</b> for suyu's launcher, made by nullptr. It is not<br />a true
desktop application, it is non-functional and running in<br />a browser.
</p>
</div>
</div>
</div>
<style>
@keyframes window-appear {
from {
opacity: 0;
transform: scale(0.85);
}
to {
opacity: 1;
transform: scale(1);
}
}
.window-body {
flex-grow: 1;
}
.filler-with-content {
flex-grow: 1;
flex-shrink: 0;
display: flex;
flex-direction: column;
}
.titlebar-sidebar {
display: flex;
flex-direction: column;
height: 100%;
width: 250px;
}
.titlebar-filler {
height: 40px;
border-bottom: var(--fluent-stroke);
flex-shrink: 0;
}
.window-contents {
width: 100%;
height: 100%;
display: flex;
}
.sidebar {
height: 100%;
flex-grow: 1;
border-right: var(--fluent-stroke);
}
.titlebar-contents {
display: flex;
height: 40px;
padding: 10px 8px;
}
.title {
margin-top: -3px;
margin-left: 8px;
font-size: 14px;
}
.root {
width: 100vw;
height: 100vh;
background-image: url($assets/mockups/Screenshot.png);
background-position: bottom center;
}
.window {
width: 1012px;
height: 600px;
position: absolute;
}
.disclaimer {
text-align: right;
position: absolute;
bottom: 16px;
right: 24px;
}
.titlebar-buttons {
position: absolute;
right: 0;
top: 0;
display: flex;
}
.tb-button {
width: 46px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
</style>

View file

@ -0,0 +1,91 @@
<script lang="ts">
import More from "./icons/More.svelte";
import smo from "$assets/mockups/smo.png";
</script>
<div class="card-container">
<div class="card-content">
<div class="card-image">
<img src={smo} alt="smo" />
</div>
<div class="card-body">
<div class="title">Super Mario Odyssey</div>
<div class="card-stats">1.1 KB • 382 hours</div>
</div>
</div>
<button class="card-more">
<More size={16} />
<span>More</span>
</button>
</div>
<style>
.title {
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-weight: 500;
}
.card-body {
width: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
font-size: 13px;
gap: 2px;
}
.card-stats {
opacity: 0.5;
font-size: 11px;
}
.card-image {
width: 100%;
height: 108px;
overflow: hidden;
flex-shrink: 0;
overflow: hidden;
border-radius: 4px;
border: var(--fluent-stroke);
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
filter: blur(0.5px);
}
.card-content {
flex-grow: 1;
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
}
.card-container {
width: 128px;
height: 212px;
border-radius: 10px;
border: var(--fluent-stroke);
position: relative;
padding: 8px;
display: flex;
flex-direction: column;
gap: 8px;
}
.card-more {
width: 100%;
height: 26px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}
</style>

View file

@ -0,0 +1,193 @@
<script lang="ts">
import { createEventDispatcher, onMount, type SvelteComponent } from "svelte";
interface SidebarItem {
icon: typeof SvelteComponent<{}>;
text: string;
onclick?: () => void;
}
let itemIndex = 0;
let pill: HTMLDivElement;
let sidebar: HTMLDivElement;
export let itemsTop: SidebarItem[];
export let itemsBottom: SidebarItem[];
const dispatch = createEventDispatcher<{
changepage: { page: typeof SvelteComponent<{}> };
}>();
function getIndex(item: SidebarItem) {
return Array.prototype.concat(itemsTop, itemsBottom).indexOf(item);
}
async function itemClick(item: SidebarItem, e: MouseEvent) {
if (item.onclick) return item.onclick();
const button = (e.target as HTMLElement).closest("button");
console.log(button);
if (!button) return;
const rect = button.getBoundingClientRect();
const sidebarRect = sidebar.getBoundingClientRect();
try {
const page = await import(`../pages/${item.text}.svelte`);
let prevItem = itemIndex;
itemIndex = getIndex(item);
if (prevItem === itemIndex) return;
const isDown = itemIndex > prevItem;
if (isDown) {
await pill.animate(
[
{
height: "28px",
},
],
{ duration: 150, easing: "ease-in" },
).finished;
pill.style.top = `${rect.top - sidebarRect.top}px`;
dispatch("changepage", { page: page.default });
await pill.animate(
[
{
height: "28px",
transform: "translateY(-4px)",
},
{
height: "16px",
},
],
{ duration: 150, easing: "ease-out", fill: "forwards" },
).finished;
} else {
await pill.animate(
[
{
height: "28px",
transform: "translateY(-2px)",
},
],
{ duration: 150, easing: "ease-in" },
).finished;
pill.style.top = `${rect.top - sidebarRect.top}px`;
dispatch("changepage", { page: page.default });
await pill.animate(
[
{
height: "28px",
},
{
height: "16px",
},
],
{ duration: 150, easing: "ease-out", fill: "forwards" },
).finished;
}
} catch {
console.error(`Page not found: ${item.text}`);
}
}
onMount(() => {
// i'm sorry orche
const firstItem = document.querySelector(".sidebar-item");
if (!firstItem) return;
const firstItemRect = firstItem.getBoundingClientRect();
const sidebarRect = sidebar.getBoundingClientRect();
pill.style.display = "block";
pill.style.top = `${firstItemRect.top - sidebarRect.top}px`;
pill.style.left = `${firstItemRect.left - sidebarRect.left + 1}px`;
});
</script>
<div class="sidebar" bind:this={sidebar}>
<div class="pill" bind:this={pill} />
<div class="sidebar-content top">
{#each itemsTop as item}
<button
on:click={(e) => {
itemClick(item, e);
}}
class="sidebar-item fluent-press"
>
<svelte:component this={item.icon} size={16} />
<p>{item.text}</p>
</button>
{/each}
</div>
<div class="sidebar-content bottom">
{#each itemsBottom as item}
<button
on:click={(e) => {
itemClick(item, e);
}}
class="sidebar-item fluent-press"
>
<svelte:component this={item.icon} size={16} />
<p>{item.text}</p>
</button>
{/each}
</div>
</div>
<style>
.pill {
width: 3px;
height: 16px;
background-color: #4e92dc;
border-radius: 8px;
display: none;
position: absolute;
transform: translateY(10px);
}
.sidebar {
display: flex;
flex-direction: column;
padding-bottom: 5px;
height: 100%;
position: relative;
}
.sidebar-content {
display: flex;
flex-direction: column;
padding: 0 4px;
gap: 4px;
}
.sidebar-content.top {
flex-grow: 1;
}
.sidebar-content.bottom {
flex-shrink: 0;
}
.sidebar-item {
appearance: none;
display: flex;
align-items: center;
height: 36px !important;
padding: 0 12px;
gap: 10px;
border-radius: 6px !important;
cursor: pointer;
border: none !important;
background-color: transparent !important;
}
.sidebar-item:hover {
background-color: rgba(200, 197, 197, 0.1) !important;
filter: none;
}
.sidebar-item:active {
background-color: rgba(154, 154, 154, 0.15) !important;
filter: none;
}
.sidebar-item > p {
font-size: 14px !important;
margin-top: -2px;
}
</style>

View file

@ -0,0 +1,10 @@
<script lang="ts">
export let size: number = 24;
</script>
<svg width={size} height={size} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
><path
d="M14.75 15c.966 0 1.75.784 1.75 1.75l-.001.962c.117 2.19-1.511 3.297-4.432 3.297-2.91 0-4.567-1.09-4.567-3.259v-1c0-.966.784-1.75 1.75-1.75h5.5Zm0 1.5h-5.5a.25.25 0 0 0-.25.25v1c0 1.176.887 1.759 3.067 1.759 2.168 0 2.995-.564 2.933-1.757V16.75a.25.25 0 0 0-.25-.25Zm-11-6.5h4.376a4.007 4.007 0 0 0-.095 1.5H3.75a.25.25 0 0 0-.25.25v1c0 1.176.887 1.759 3.067 1.759.462 0 .863-.026 1.207-.077a2.743 2.743 0 0 0-1.173 1.576l-.034.001C3.657 16.009 2 14.919 2 12.75v-1c0-.966.784-1.75 1.75-1.75Zm16.5 0c.966 0 1.75.784 1.75 1.75l-.001.962c.117 2.19-1.511 3.297-4.432 3.297l-.169-.002a2.755 2.755 0 0 0-1.218-1.606c.387.072.847.108 1.387.108 2.168 0 2.995-.564 2.933-1.757V11.75a.25.25 0 0 0-.25-.25h-4.28a4.05 4.05 0 0 0-.096-1.5h4.376ZM12 8a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm0 1.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3ZM6.5 3a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm11 0a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm-11 1.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3Zm11 0a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3Z"
fill="#fff"
/></svg
>

View file

@ -0,0 +1,10 @@
<script lang="ts">
export let size: number = 24;
</script>
<svg width={size} height={size} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
><path
d="M12 1.999c5.524 0 10.002 4.478 10.002 10.002 0 5.523-4.478 10.001-10.002 10.001-5.524 0-10.002-4.478-10.002-10.001C1.998 6.477 6.476 1.999 12 1.999ZM14.939 16.5H9.06c.652 2.414 1.786 4.002 2.939 4.002s2.287-1.588 2.939-4.002Zm-7.43 0H4.785a8.532 8.532 0 0 0 4.094 3.411c-.522-.82-.953-1.846-1.27-3.015l-.102-.395Zm11.705 0h-2.722c-.324 1.335-.792 2.5-1.373 3.411a8.528 8.528 0 0 0 3.91-3.127l.185-.283ZM7.094 10H3.735l-.005.017a8.525 8.525 0 0 0-.233 1.984c0 1.056.193 2.067.545 3h3.173a20.847 20.847 0 0 1-.123-5Zm8.303 0H8.603a18.966 18.966 0 0 0 .135 5h6.524a18.974 18.974 0 0 0 .135-5Zm4.868 0h-3.358c.062.647.095 1.317.095 2a20.3 20.3 0 0 1-.218 3h3.173a8.482 8.482 0 0 0 .544-3c0-.689-.082-1.36-.236-2ZM8.88 4.09l-.023.008A8.531 8.531 0 0 0 4.25 8.5h3.048c.314-1.752.86-3.278 1.583-4.41ZM12 3.499l-.116.005C10.62 3.62 9.396 5.622 8.83 8.5h6.342c-.566-2.87-1.783-4.869-3.045-4.995L12 3.5Zm3.12.59.107.175c.669 1.112 1.177 2.572 1.475 4.237h3.048a8.533 8.533 0 0 0-4.339-4.29l-.291-.121Z"
fill="#fff"
/></svg
>

View file

@ -0,0 +1,10 @@
<script lang="ts">
export let size: number = 24;
</script>
<svg width={size} height={size} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
><path
d="M4 3h1c1.054 0 1.918.816 1.995 1.85L7 5v14a2.001 2.001 0 0 1-1.85 1.994L5 21H4a2.001 2.001 0 0 1-1.995-1.85L2 19V5c0-1.054.816-1.918 1.85-1.995L4 3h1-1Zm6 0h1c1.054 0 1.918.816 1.995 1.85L13 5v14a2.001 2.001 0 0 1-1.85 1.994L11 21h-1a2.001 2.001 0 0 1-1.995-1.85L8 19V5c0-1.054.816-1.918 1.85-1.995L10 3h1-1Zm6.974 2c.84 0 1.608.531 1.89 1.346l.047.157 3.015 11.745a2 2 0 0 1-1.296 2.392l-.144.043-.969.248a2.002 2.002 0 0 1-2.387-1.284l-.047-.155-3.016-11.745a2 2 0 0 1 1.298-2.392l.143-.043.968-.248c.166-.043.334-.064.498-.064ZM5 4.5H4a.501.501 0 0 0-.492.41L3.5 5v14c0 .244.177.45.41.492L4 19.5h1c.245 0 .45-.178.492-.41L5.5 19V5a.501.501 0 0 0-.41-.492L5 4.5Zm6 0h-1a.501.501 0 0 0-.492.41L9.5 5v14c0 .244.177.45.41.492l.09.008h1c.245 0 .45-.178.492-.41L11.5 19V5a.501.501 0 0 0-.41-.492L11 4.5Zm5.975 2-.063.004-.063.013-.968.247a.498.498 0 0 0-.376.51l.015.1 3.016 11.745a.5.5 0 0 0 .483.375l.063-.003.062-.012.97-.25a.5.5 0 0 0 .374-.519l-.015-.088-3.015-11.747a.501.501 0 0 0-.483-.375Z"
fill="#fff"
/></svg
>

View file

@ -0,0 +1,10 @@
<script lang="ts">
export let size: number = 24;
</script>
<svg width={size} height={size} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
><path
d="M8 12a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM14 12a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM18 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z"
fill="#ffffff"
/></svg
>

View file

@ -0,0 +1,16 @@
<script lang="ts">
export let size: number = 24;
</script>
<svg width={size} height={size} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
><path
d="M8.144 6.307c.434-.232.901-.306 1.356-.306.526 0 1.138.173 1.632.577.517.424.868 1.074.868 1.922 0 .975-.689 1.504-1.077 1.802l-.085.066c-.424.333-.588.511-.588.882a.75.75 0 0 1-1.5 0c0-1.134.711-1.708 1.162-2.062.513-.403.588-.493.588-.688 0-.397-.149-.622-.32-.761A1.115 1.115 0 0 0 9.5 7.5c-.295 0-.498.049-.65.13-.143.076-.294.21-.44.48a.75.75 0 1 1-1.32-.715c.264-.486.612-.853 1.054-1.089ZM9.5 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
fill="#fff"
/><path
d="M9.5 3a7.5 7.5 0 0 0-6.797 10.673l-.725 2.842a1.25 1.25 0 0 0 1.504 1.524c.75-.18 1.903-.457 2.93-.702A7.5 7.5 0 1 0 9.5 3Zm-6 7.5a6 6 0 1 1 3.33 5.375l-.243-.121-.265.063-2.788.667c.2-.78.462-1.812.69-2.708l.07-.276-.13-.253A5.971 5.971 0 0 1 3.5 10.5Z"
fill="#fff"
/><path
d="M14.5 21c-1.97 0-3.761-.759-5.1-2h.1c.718 0 1.415-.089 2.081-.257.864.482 1.86.757 2.92.757.96 0 1.866-.225 2.669-.625l.243-.121.265.063c.921.22 1.965.445 2.74.61-.176-.751-.415-1.756-.642-2.651l-.07-.276.13-.253A5.971 5.971 0 0 0 20.5 13.5a5.995 5.995 0 0 0-2.747-5.042 8.443 8.443 0 0 0-.8-2.047 7.503 7.503 0 0 1 4.344 10.263c.253 1.008.51 2.1.672 2.803a1.244 1.244 0 0 1-1.468 1.5c-.727-.152-1.87-.396-2.913-.64A7.476 7.476 0 0 1 14.5 21Z"
fill="#fff"
/></svg
>

View file

@ -0,0 +1,10 @@
<script lang="ts">
export let size: number = 24;
</script>
<svg width={size} height={size} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
><path
d="M12.012 2.25c.734.008 1.465.093 2.182.253a.75.75 0 0 1 .582.649l.17 1.527a1.384 1.384 0 0 0 1.927 1.116l1.401-.615a.75.75 0 0 1 .85.174 9.792 9.792 0 0 1 2.204 3.792.75.75 0 0 1-.271.825l-1.242.916a1.381 1.381 0 0 0 0 2.226l1.243.915a.75.75 0 0 1 .272.826 9.797 9.797 0 0 1-2.204 3.792.75.75 0 0 1-.848.175l-1.407-.617a1.38 1.38 0 0 0-1.926 1.114l-.169 1.526a.75.75 0 0 1-.572.647 9.518 9.518 0 0 1-4.406 0 .75.75 0 0 1-.572-.647l-.168-1.524a1.382 1.382 0 0 0-1.926-1.11l-1.406.616a.75.75 0 0 1-.849-.175 9.798 9.798 0 0 1-2.204-3.796.75.75 0 0 1 .272-.826l1.243-.916a1.38 1.38 0 0 0 0-2.226l-1.243-.914a.75.75 0 0 1-.271-.826 9.793 9.793 0 0 1 2.204-3.792.75.75 0 0 1 .85-.174l1.4.615a1.387 1.387 0 0 0 1.93-1.118l.17-1.526a.75.75 0 0 1 .583-.65c.717-.159 1.45-.243 2.201-.252Zm0 1.5a9.135 9.135 0 0 0-1.354.117l-.109.977A2.886 2.886 0 0 1 6.525 7.17l-.898-.394a8.293 8.293 0 0 0-1.348 2.317l.798.587a2.881 2.881 0 0 1 0 4.643l-.799.588c.32.842.776 1.626 1.348 2.322l.905-.397a2.882 2.882 0 0 1 4.017 2.318l.11.984c.889.15 1.798.15 2.687 0l.11-.984a2.881 2.881 0 0 1 4.018-2.322l.905.396a8.296 8.296 0 0 0 1.347-2.318l-.798-.588a2.881 2.881 0 0 1 0-4.643l.796-.587a8.293 8.293 0 0 0-1.348-2.317l-.896.393a2.884 2.884 0 0 1-4.023-2.324l-.11-.976a8.988 8.988 0 0 0-1.333-.117ZM12 8.25a3.75 3.75 0 1 1 0 7.5 3.75 3.75 0 0 1 0-7.5Zm0 1.5a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5Z"
fill="#fff"
/></svg
>

View file

@ -0,0 +1,16 @@
<script>
import Card from "../components/Card.svelte";
</script>
<div class="cards">
<Card />
</div>
<style>
.cards {
padding: 20px;
display: grid;
grid-template-columns: repeat(auto-fill, 128px);
grid-gap: 20px;
}
</style>

View file

@ -0,0 +1 @@
<h1>Multiplayer</h1>

View file

@ -0,0 +1 @@
<h1>Settings</h1>

BIN
static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

0
static/img/.gitkeep Normal file
View file

BIN
static/img/suyu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View file

@ -1,94 +0,0 @@
body {
background-color: black !important;
}
/* USE THIS FOR DEBUGGING * {
border: 1px solid red;
} */
#announcement {
background-color: rgb(46, 46, 46) !important;
}
.navbar, .navbar-brand{
background-color: black !important;
color: white !important;
}
.navbar-toggler-icon {
background-color: rgb(83, 82, 82) !important;
}
.nav-link {
color: white !important;
}
.nav-link:hover {
color: cyan !important;
}
#suyu-logo {
height: 420px;
}
#headertext {
color: white;
text-align: top;
display: flex;
align-items: flex-start;
margin-left: 20%;
}
#headersubtext {
color: white !important;
text-align: top;
display: flex;
align-items: flex-start;
margin-left: 20%;
}
#downloadbutton {
margin-left: 20%;
}
#downloadicon, #sourceicon, #discordicon, #giticon {
filter: invert(100%);
}
/* #information {
border-top: 2px solid white;
border-bottom: 2px solid white;
} */
#infoheadtext, #infotext {
color: white;
}
#featuresheadertext, .card-title, .card-text {
color: white;
}
.card {
background-color: rgb(37, 32, 32);
}
.card {
border: 5px solid red;
}
.btn {
color: white;
}
.btn:hover {
transform: scale(1.1);
}
footer {
color: white;
text-align: center;
}

22
svelte.config.js Normal file
View file

@ -0,0 +1,22 @@
import adapter from "@sveltejs/adapter-node";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: [vitePreprocess({})],
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(),
alias: {
$components: "./src/components",
$assets: "./src/assets",
},
},
};
export default config;

14
tailwind.config.cjs Normal file
View file

@ -0,0 +1,14 @@
/** @type {import('tailwindcss').Config}*/
const config = {
content: [
"./src/**/*.{html,js,svelte,ts}",
"./node_modules/flowbite-svelte-icons/**/*.{html,js,svelte,ts}",],
theme: {
extend: {},
},
plugins: [],
};
module.exports = config;

19
tsconfig.json Normal file
View file

@ -0,0 +1,19 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler",
"noImplicitAny": false
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

7
vite.config.ts Normal file
View file

@ -0,0 +1,7 @@
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
export default defineConfig({
plugins: [ViteImageOptimizer(), sveltekit()],
});