diff --git a/AquaNet/.env b/AquaNet/.env
index 16146a10..2c5fa305 100644
--- a/AquaNet/.env
+++ b/AquaNet/.env
@@ -7,3 +7,4 @@ VITE_TURNSTILE_SITE_KEY=0x4AAAAAAASGA2KQEIelo9P9
VITE_DISCORD_INVITE=https://discord.gg/FNgveqFF7s
VITE_TELEGRAM_INVITE=https://t.me/+zBL4RZdyfvUzZGU1
VITE_QQ_INVITE=https://qm.qq.com/q/dpYmGoVHnG
+VITE_GITHUB_REPOSITORY=https://github.com/MewoLab/AquaDX
\ No newline at end of file
diff --git a/AquaNet/public/assets/theme/cn.css b/AquaNet/public/assets/theme/cn.css
deleted file mode 100644
index ba1fd70b..00000000
--- a/AquaNet/public/assets/theme/cn.css
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
-
-Happy April Fools!
-This theme will stay here.
-Note that I made it with Stylish in mind, it's quite jank.
-
-*/
-* {
- font-family: "ヒラギノ角ゴ Pro W3", "メイリオ", Meiryo, "MS Pゴシック",
- "MS P Gothic", sans-serif;
-}
-nav > a,
-nav > *.active,
-.setting-icon path {
- color: unset !important;
-}
-.aqua-tooltip {
- background: black;
-}
-.fw-block {
- background: none !important;
- box-shadow: none !important;
-}
-#app {
- background: url(/assets/theme/cn/logo.bin),
- #f9f9db;
- background-repeat: no-repeat;
- background-position: 50% 4px;
- max-width: 528px !important;
- margin: 0 auto;
- padding: 100px 0 0 0 !important;
- height: unset !important;
- box-shadow: -8px 0 0 0 #fdd500, -12px 0 0 0 #f9f9db, 8px 0 0 0 #fdd500,
- 12px 0 0 0 #f9f9db;
-}
-nav:has(.logo) {
- position: absolute !important;
- top: 0;
- left: 0;
- width: calc(100% - 96px);
-}
-nav {
- color: black;
-}
-.user-pfp {
- margin-top: -56px !important;
-}
-.outer-title-options,
-.outer-title-options *,
-nav.tabs {
- color: white !important;
-}
-.outer-title-options {
- margin-top: 0 !important;
- display: unset !important;
-}
-.outer-title-options h2 {
- width: 460px;
- position: relative;
- right: 20px;
- display: flex;
- justify-content: center;
- margin: 0 0 10px 0 !important;
- background: url(/assets/theme/cn/header.bin);
-}
-.chuni-userbox-row {
- flex-wrap: wrap;
-}
-.chuni-userbox button {
- width: calc(100% / 4) !important;
- font-size: 0px;
-}
-.chuni-userbox-row button {
- width: unset !important;
- flex: 0 1 calc(100% / 3) !important;
-}
-.chuni-userbox-row button img {
- overflow: hidden;
- font-size: 10px;
-}
-.chuni-nameplate {
- background: none !important;
- position: relative !important;
- left: 20px;
-}
-.chuni-userbox {
- background: none !important;
-}
-main {
- max-width: calc(460px - 40px) !important;
- margin: 16px auto 0 auto !important;
- background: #2c4056 !important;
- border-radius: unset !important;
- padding: 10px 20px !important;
-}
-main:has(.user-pfp) {
- margin: 64px auto 0 auto !important;
-}
-.rating-composition {
- display: flex !important;
- flex-wrap: wrap;
- gap: 0 !important;
-}
-.rating-composition > div {
- width: 47.5%;
- margin: 1.25%;
-}
-.map-detail-container {
- background: none !important;
- border-radius: 0 !important;
-}
-.lv {
- border-radius: 0 !important;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 0 !important;
- width: 50px !important;
-}
-.rank-text {
- min-width: 20px !important;
-}
-.chuni-userbox-container {
- flex-wrap: wrap;
-}
-.profile-bio-text {
- white-space: unset !important;
-}
-.chuni-penguin-container {
- padding: 64px 0;
- width: 100%;
- background: linear-gradient(
- 180deg,
- rgba(249, 249, 219, 1) 0%,
- rgba(249, 249, 219, 1) 69%,
- rgba(231, 231, 202, 1) 70%,
- rgba(231, 231, 202, 1) 100%
- );
-}
-body {
- background: #fdd500 !important;
- color: white;
-}
-
-@media (max-width: 1200px) {
- #app {
- background-position: 50% 60px !important;
- padding-top: 150px !important;
- }
-}
-
-@media (max-width: 1028px) {
- #app {
- background-size: 90%;
- }
-
- .user-pfp {
- margin-top: -36px !important;
- }
- .user-pfp nav {
- top: -10px !important;
- }
-}
\ No newline at end of file
diff --git a/AquaNet/public/assets/theme/cn/header.bin b/AquaNet/public/assets/theme/cn/header.bin
deleted file mode 100644
index a92eec75..00000000
Binary files a/AquaNet/public/assets/theme/cn/header.bin and /dev/null differ
diff --git a/AquaNet/public/assets/theme/cn/logo.bin b/AquaNet/public/assets/theme/cn/logo.bin
deleted file mode 100644
index 4e0e6965..00000000
Binary files a/AquaNet/public/assets/theme/cn/logo.bin and /dev/null differ
diff --git a/AquaNet/src/App.svelte b/AquaNet/src/App.svelte
index 5403b50c..127d820e 100644
--- a/AquaNet/src/App.svelte
+++ b/AquaNet/src/App.svelte
@@ -16,6 +16,7 @@
import Communities from "./pages/Home/Communities.svelte";
import LinkCard from "./pages/Home/LinkCard.svelte";
import SetupInstructions from "./pages/Home/SetupInstructions.svelte";
+ import PageNotFound from "./pages/PageNotFound.svelte";
console.log(`%c
┏━┓ ┳━┓━┓┏━
@@ -41,15 +42,6 @@
playedMai = !!game.mai2
})
}).catch(e => console.error(e))
-
- const themeStyle = document.createElement("link");
- themeStyle.rel = "stylesheet";
- switch (localStorage.getItem("theme")) {
- case "cn":
- themeStyle.href = "/assets/theme/cn.css";
- };
- if (themeStyle.href)
- document.head.appendChild(themeStyle);
}
let path = window.location.pathname;
@@ -93,8 +85,10 @@
+
+
diff --git a/AquaNet/src/components/settings/WaccaSettings.svelte b/AquaNet/src/components/settings/WaccaSettings.svelte
index 9d442758..9997517a 100644
--- a/AquaNet/src/components/settings/WaccaSettings.svelte
+++ b/AquaNet/src/components/settings/WaccaSettings.svelte
@@ -4,6 +4,6 @@
import GameSettingFields from "./GameSettingFields.svelte";
-
+
diff --git a/AquaNet/src/components/ui/Error.svelte b/AquaNet/src/components/ui/Error.svelte
index 7055ecd2..585976f4 100644
--- a/AquaNet/src/components/ui/Error.svelte
+++ b/AquaNet/src/components/ui/Error.svelte
@@ -10,15 +10,15 @@
@@ -26,14 +26,19 @@
diff --git a/AquaNet/src/libs/config.ts b/AquaNet/src/libs/config.ts
index 3f62b182..e8cb12e6 100644
--- a/AquaNet/src/libs/config.ts
+++ b/AquaNet/src/libs/config.ts
@@ -10,6 +10,7 @@ export const TURNSTILE_SITE_KEY = import.meta.env.VITE_TURNSTILE_SITE_KEY
export const DISCORD_INVITE = import.meta.env.VITE_DISCORD_INVITE
export const TELEGRAM_INVITE = import.meta.env.VITE_TELEGRAM_INVITE
export const QQ_INVITE = import.meta.env.VITE_QQ_INVITE
+export const GITHUB_REPOSITORY = import.meta.env.VITE_GITHUB_REPOSITORY
// UI
export const FADE_OUT = { duration: 200 }
diff --git a/AquaNet/src/libs/i18n/en_ref.ts b/AquaNet/src/libs/i18n/en_ref.ts
index 49b31724..fb727efa 100644
--- a/AquaNet/src/libs/i18n/en_ref.ts
+++ b/AquaNet/src/libs/i18n/en_ref.ts
@@ -77,17 +77,19 @@ export const EN_REF_GENERAL = {
'game.ongeki': 'Ongeki',
'game.wacca': 'Wacca',
'status.error': 'Error',
- 'status.error.hint': 'Something went wrong, please try again later or ',
- 'status.error.hint.link': 'join our discord for support.',
+ 'status.error.hint': 'Support',
'status.detail': 'Detail: ${detail}',
- 'action.refresh': 'Refresh',
+ 'action.refresh': 'Retry',
'action.cancel': 'Cancel',
'action.confirm': 'Confirm',
+ 'action.home': 'Home',
'navigation.profile': 'Profile',
'navigation.maps': 'Maps',
'navigation.home': 'Home',
'navigation.rankings': 'Rankings',
- 'navigation.notice': 'Notice'
+ 'navigation.notice': 'Notice',
+ 'loading': `Please wait...`,
+ '404': 'Page not found (${pathname}). If this is in error, please report it via an appropriate support channel.'
}
export const EN_REF_HOME = {
@@ -102,7 +104,7 @@ export const EN_REF_HOME = {
'home.manage-cards-description': 'Link, unlink, and manage your cards.',
'home.link-card': 'Link Card',
'home.link-cards-description': 'Link your Amusement IC / Aime card to play games.',
- 'home.join-community': 'Join Community',
+ 'home.join-community': 'Community & Support',
'home.join-community-description': 'Join our community for support and chatting with other players.',
'home.setup': 'Setup Network Connection',
'home.setup-description': 'Configure a game to connect to our servers.',
@@ -131,13 +133,13 @@ export const EN_REF_HOME = {
'home.community.discord': 'Discord',
'home.community.telegram': 'Telegram (Chinese)',
'home.community.qq': 'QQ (Chinese)',
+ 'home.community.github': 'GitHub Repository',
'home.import.unknown-game': 'Unknown game type. Currently only Mai and Chuni are supported for importing.',
'home.import.new-data': 'Data to import',
'home.import.data-conflict': 'Proceed will override your current data',
}
export const EN_REF_SETUP = {
- 'loading': `Please wait...`,
'setup.welcome': `Welcome! If you have a game set up, please follow the instructions below to set up the connection with AquaDX.`,
'setup.keychip-warning': `Your keychip is linked to your account and should be kept secure. Do not give others your keychip.`,
'setup.steps.one': `Pick a method of setting up network communications. Some browsers may not be able to do automatic setup.`,
@@ -157,6 +159,7 @@ export const EN_REF_SETUP = {
export const EN_REF_SETTINGS = {
'settings.title': 'Settings',
+ 'settings.page-title': '${page} Settings',
'settings.tabs.profile': 'Profile',
'settings.tabs.global': 'Global',
'settings.tabs.chu3': 'Chuni',
diff --git a/AquaNet/src/pages/Home.svelte b/AquaNet/src/pages/Home.svelte
index fe4480d5..e335ab96 100644
--- a/AquaNet/src/pages/Home.svelte
+++ b/AquaNet/src/pages/Home.svelte
@@ -5,7 +5,7 @@
import ActionCard from "../components/ActionCard.svelte";
import { t } from "../libs/i18n";
import ImportDataAction from "./Home/ImportDataAction.svelte";
- import DashboardTabs from "./Home/DashboardTabs.svelte";
+ import DashboardTabs from "../components/DashboardTabs.svelte";
USER.ensureLoggedIn();
diff --git a/AquaNet/src/pages/Home/Communities.svelte b/AquaNet/src/pages/Home/Communities.svelte
index 7abaf3b6..34f543c8 100644
--- a/AquaNet/src/pages/Home/Communities.svelte
+++ b/AquaNet/src/pages/Home/Communities.svelte
@@ -3,30 +3,36 @@
{t('home.join-community')}
-
+
{#if DISCORD_INVITE}
- {t('home.community.discord')}
+ {t('home.community.discord')}
{/if}
{#if TELEGRAM_INVITE}
- {t('home.community.telegram')}
+ {t('home.community.telegram')}
{/if}
{#if QQ_INVITE}
- {t('home.community.qq')}
+ {t('home.community.qq')}
+
+ {/if}
+
+ {#if GITHUB_REPOSITORY}
+
+ {t('home.community.github')}
{/if}
@@ -34,5 +40,6 @@
diff --git a/AquaNet/src/pages/Home/LinkCard.svelte b/AquaNet/src/pages/Home/LinkCard.svelte
index 47923bf5..1b076b35 100644
--- a/AquaNet/src/pages/Home/LinkCard.svelte
+++ b/AquaNet/src/pages/Home/LinkCard.svelte
@@ -8,7 +8,7 @@
import Icon from "@iconify/svelte"
import StatusOverlays from "../../components/StatusOverlays.svelte"
import { t } from "../../libs/i18n"
- import DashboardTabs from "./DashboardTabs.svelte";
+ import DashboardTabs from "../../components/DashboardTabs.svelte";
// State
let state: 'ready' | 'linking-AC' | 'linking-SN' | 'loading' = "loading"
diff --git a/AquaNet/src/pages/Home/SetupInstructions.svelte b/AquaNet/src/pages/Home/SetupInstructions.svelte
index 1ee885e3..aa6f153a 100644
--- a/AquaNet/src/pages/Home/SetupInstructions.svelte
+++ b/AquaNet/src/pages/Home/SetupInstructions.svelte
@@ -7,7 +7,7 @@
import { codeToHtml } from 'shiki'
import { AQUA_CONNECTION, DISCORD_INVITE, FADE_IN, FADE_OUT } from "../../libs/config";
import { t } from "../../libs/i18n";
- import DashboardTabs from "./DashboardTabs.svelte";
+ import DashboardTabs from "../../components/DashboardTabs.svelte";
import { patchUserSegatools } from "../../libs/setup";
let user: AquaNetUser
diff --git a/AquaNet/src/pages/PageNotFound.svelte b/AquaNet/src/pages/PageNotFound.svelte
new file mode 100644
index 00000000..7c8a704f
--- /dev/null
+++ b/AquaNet/src/pages/PageNotFound.svelte
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/AquaNet/src/pages/User/Settings.svelte b/AquaNet/src/pages/User/Settings.svelte
index d9c60778..c98aab94 100644
--- a/AquaNet/src/pages/User/Settings.svelte
+++ b/AquaNet/src/pages/User/Settings.svelte
@@ -5,281 +5,58 @@
import type { AquaNetUser } from "../../libs/generalTypes";
import { CARD, USER } from "../../libs/sdk";
import StatusOverlays from "../../components/StatusOverlays.svelte";
- import Icon from "@iconify/svelte";
- import { pfp } from "../../libs/ui";
import { t, ts } from "../../libs/i18n";
- import { FADE_IN, FADE_OUT } from "../../libs/config";
- import Cropper from "svelte-easy-crop";
- import UserBox from "../../components/settings/ChuniSettings.svelte";
+ import ChuniSettings from "../../components/settings/ChuniSettings.svelte";
import Mai2Settings from "../../components/settings/Mai2Settings.svelte";
import WaccaSettings from "../../components/settings/WaccaSettings.svelte";
import GeneralGameSettings from "../../components/settings/GeneralGameSettings.svelte";
import OngekiSettings from "../../components/settings/OngekiSettings.svelte";
- import useLocalStorage from "../../libs/hooks/useLocalStorage.svelte";
+ import UserSettings from "../../components/settings/UserSettings.svelte";
+ import type { Component } from "svelte";
+ import { EN_REF } from "../../libs/i18n/en_ref";
USER.ensureLoggedIn()
let me: AquaNetUser;
let error: string;
- let submitting = ""
- let tab = 0
- let tabs = ['profile']
+ export let page: string = "profile";
- const profileFields = [
- [ 'displayName', t('settings.profile.name') ],
- [ 'username', t('settings.profile.username') ],
- [ 'password', t('settings.profile.password') ],
- /* Neither of these did anything of importance
- [ 'country', t('settings.profile.country') ],
- [ 'profileLocation', t('settings.profile.location') ],*/
- [ 'profileBio', t('settings.profile.bio') ],
- ] as const
-
- // Fetch user data
- const getMe = () => USER.me().then((m) => {
- if (pfpCropURL != null) {
- URL.revokeObjectURL(pfpCropURL);
- pfpField.value = "";
- pfpCropURL = null;
- }
- me = m
-
- CARD.userGames(m.username).then(games => {
- tabs = [
- ...tabs,
- ...['chu3', 'mai2','wacca', 'ongeki'].filter(v => games[v as keyof typeof games]), // :xdx:
- 'global'
- ]
- })
- }).catch(e => error = e.message)
- getMe()
-
- let changed: string[] = []
- let pfpField: HTMLInputElement
- let pfpCropURL: string | null = null;
- let pfpCrop = { width: 0, height: 0, x: 0, y: 0 };
-
- function submit(field: string, value: string) {
- if (submitting) return
- submitting = field
-
- USER.setting(field, value).then(() => {
- changed = changed.filter(c => c !== field)
- }).catch(e => error = e.message).finally(() => submitting = "")
+ const pages: Record
= {
+ "profile": UserSettings, "chu3": ChuniSettings,
+ "mai2": Mai2Settings, "wacca": WaccaSettings,
+ "ongeki": OngekiSettings, "global": GeneralGameSettings
}
- function uploadPfp() {
- if (submitting) return
- // Don't know why this isn't just a part of the cropper module. Have to do this myself.. What a shame
- let canvas = document.createElement("canvas");
- let ctx = canvas.getContext("2d");
- const size = Math.round(Math.min(pfpCrop.width, pfpCrop.height, 1024));
- canvas.width = size;
- canvas.height = size;
- let img = document.createElement("img");
- img.onload = () => {
- ctx?.drawImage(img, pfpCrop.x, pfpCrop.y, pfpCrop.width, pfpCrop.height, 0, 0, size, size);
- canvas.toBlob(blob => {
- if (!blob) return;
- submitting = 'profilePicture'
- USER.uploadPfp(blob as File).then(() => {
- me.profilePicture = me.username
- // reload
- // this doesn't work btw
- setTimeout(getMe, 200);
- }).catch(e => error = e.message).finally(() => submitting = "")
- });
- }
- img.src = pfpCropURL ?? "";
- }
- function handlePfpUpload(e: Event & { target: HTMLInputElement }) {
- if (!e.target) return;
- let files = e?.target?.files;
- if (!files || files.length <= 0) return;
- let file = files[0];
- console.log(me.username, me);
- switch (file.type) {
- case "image/gif":
- USER.uploadPfp(file).then(() => {
- me.profilePicture = me.username
- // reload
- setTimeout(getMe, 200);
- }).catch(e => error = e.message).finally(() => submitting = "")
- break;
- case "image/png":
- case "image/jpeg":
- case "image/webp":
- pfpCropURL = URL.createObjectURL(file);
- break;
- default:
- error = t("settings.profile.bad-format");
- }
- };
- function logOut() {
- localStorage.removeItem("token");
- location.href = "/";
- }
+ if (!pages[page] && page)
+ error = t("404", {pathname: new URL(location.href).pathname});
- const passwordAction = (node: HTMLInputElement, whether: boolean) => {
- if (whether) node.type = 'password'
- }
+ USER.me().then(m => me = m)
+ .catch(e => error = e.message)
{t('settings.title')}
- {#each tabs as tabName, i}
- tab = i} on:keydown={e => e.key === 'Enter' && (tab = i)}
- role="button" tabindex="0">
- {ts(`settings.tabs.${tabName}`)}
-
+ {#each Object.entries(pages) as tab}
+
+ {ts(`settings.tabs.${tab[0]}`)}
+
{/each}
- {#if tab === 0 && me}
-
-
-
-
{t('settings.profile.picture')}
-
- {#if me && me.profilePicture}
-
pfpField.click()} on:keydown={e => e.key === 'Enter' && pfpField.click()}
- role="button" tabindex="0" class="clickable">
-
-
- {:else}
-
pfpField.click()}>
- {t('settings.profile.upload-new')}
-
- {/if}
-
-
-
-
+
- {#each profileFields as [field, name], i (field)}
-
-
{name}
-
- {#if field == "profileBio"}
-
- {:else}
- changed = [...changed, field]}
- placeholder={field === 'password' ? t('settings.profile.unchanged') : t('settings.profile.unset')}/>
- {/if}
-
- {#if changed.includes(field) && me[field]}
- submit(field, me[field])}>
- {#if submitting === field}
-
- {:else}
- {t('settings.profile.save')}
- {/if}
-
- {/if}
-
-
- {/each}
-
-
- submit('optOutOfLeaderboard', me.optOutOfLeaderboard.toString())}/>
-
- {ts(`settings.fields.optOutOfLeaderboard.name`)}
- {ts(`settings.fields.optOutOfLeaderboard.desc`)}
-
-
-
-
-
- {ts(`settings.profile.logout`)}
-
-
-
- {:else if tabs[tab] === 'chu3'}
-
-
- {:else if tabs[tab] === 'mai2'}
-
- {:else if tabs[tab] === 'wacca'}
-
- {:else if tabs[tab] === 'ongeki'}
-
- {:else if tabs[tab] === 'global'}
-
+ {#if pages[page]}
+
{/if}
-
-
-
-{#if pfpCropURL != null}
-
-
-
- pfpCrop = e.pixels} image={pfpCropURL ?? "assets/imgs/no_profile.png"} aspect={1} cropShape="round">
-
-
- {t("settings.profile.save")}
-
-
- {t("back")}
-
-
-
-{/if}
-
+
+ h2.header
+ margin: 0 0 0.5rem 0
+
\ No newline at end of file
diff --git a/AquaNet/src/pages/UserHome.svelte b/AquaNet/src/pages/UserHome.svelte
index b7ecea7c..87b3ce80 100644
--- a/AquaNet/src/pages/UserHome.svelte
+++ b/AquaNet/src/pages/UserHome.svelte
@@ -30,15 +30,13 @@
registerChart()
export let username: string;
- export let game: GameName | "auto" = "auto"
+ export let game: GameName;
let calElement: HTMLElement
let error: string;
let me: AquaNetUser
title(`User ${username}`)
const rounding = useLocalStorage("rounding", true);
- const titleText = game != "auto" ? GAME_TITLE[game] : "?"
-
interface MusicAndPlay extends MusicMeta, GenericGamePlaylog {}
let d: {
@@ -57,7 +55,7 @@
USER.isLoggedIn() && USER.me().then(u => me = u)
CARD.userGames(username).then(games => {
- if (game == "auto") {
+ if (!game) {
let targetGames = Object.entries(games)
.map(d => {
if (d[1])
@@ -66,9 +64,7 @@
}).sort((a,b) => {
return b[1]?.lastLogin - a[1]?.lastLogin;
});
- if (targetGames[0])
- window.location.href = `/u/${username}/${targetGames[0][0]}`
- return;
+ game = targetGames[0][0] as GameName;
}
if (!games[game]) {
// Find a valid game
@@ -118,11 +114,10 @@
}).catch((e) => { error = e.message; console.error(e) } );
}
- if (Object.keys(GAME_TITLE).includes(game) || game == "auto") init()
+ if (Object.keys(GAME_TITLE).includes(game) || !game) init()
else error = t("UserHome.InvalidGame", {game})
const setRival = (isAdd: boolean) => {
- if (game == "auto") return;
isLoading = true
GAME.setRival(game, username, isAdd).then(() => {
d!.user.rival = isAdd
@@ -167,7 +162,7 @@
{/each}
{#if me && me.username === username}
-
+
{/if}
@@ -188,7 +183,7 @@
-
{titleText} {t('UserHome.Statistics')}
+
{GAME_TITLE[game] ?? "?"} {t('UserHome.Statistics')}
@@ -313,16 +308,16 @@
-
-
-
+
+
+
{#if d.user.ratingComposition.new}
{:else}
-
+
{/if}
@@ -344,12 +339,12 @@
{r.notes?.[r.level === 10 ? 0 : r.level]?.lv?.toFixed(1) ?? r.worldsEndTag ?? '-'}
-
- {("" + getMult(r.achievement, game != "auto" ? game : "mai2")[2]).replace("p", "+")}
+
+ {("" + getMult(r.achievement, game)[2]).replace("p", "+")}
{
rounding.value ?
- roundFloor(r.achievement, game != "auto" ? game : "mai2", 1) :
+ roundFloor(r.achievement, game, 1) :
(r.achievement / 10000).toFixed(4)
}%