feat: improved announcement management, custom qr access code handler, fixes

This commit is contained in:
Yonle
2026-05-22 21:01:50 -04:00
committed by GitHub
parent 512a791aa4
commit 2552568ac1
12 changed files with 107 additions and 9 deletions
+7 -1
View File
@@ -7,4 +7,10 @@ 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
VITE_GITHUB_REPOSITORY=https://github.com/MewoLab/AquaDX
# example:
# https://aquadx.net/#accesskey=....
VITE_ACCESSCODE_QKEY=accesskey
VITE_DEFAULT_GAME=mai2
+3 -1
View File
@@ -35,4 +35,6 @@ dist-ssr
public/chu3
# local env file
*.local
*.local
.env
View File
+5 -4
View File
@@ -9,7 +9,8 @@
import Settings from "./pages/User/Settings.svelte";
import MaiPhoto from "./pages/MaiPhoto.svelte";
import { pfp, tooltip } from "./libs/ui"
import { ANNOUNCEMENT } from "./libs/config";
import { ANNOUNCEMENT } from "./libs/announcement";
import { DEFAULT_GAME } from "./libs/config"
import { t } from "./libs/i18n";
import Transfer from "./pages/Transfer/Transfer.svelte";
import { link } from "d3";
@@ -34,7 +35,7 @@
let me: AquaNetUser
let playedMai = false
let recentGame: string = "mai2";
let recentGame: string = DEFAULT_GAME;
if (USER.isLoggedIn())
{
@@ -60,9 +61,9 @@
<span>AquaNet</span>
</a>
{/if}
{#if ANNOUNCEMENT}
{#if $ANNOUNCEMENT}
<div class="announcement">
<strong>{t('navigation.notice')}</strong>: {ANNOUNCEMENT}
<strong>{t('navigation.notice')}</strong>: {$ANNOUNCEMENT}
</div>
{/if}
<a href="/home">{t('navigation.home').toLowerCase()}</a>
+35
View File
@@ -0,0 +1,35 @@
// card handler. for dealing user QR scan.
// this will assumes that the link of the generated QR code in [access code]
// page has been altered by modder to link to custom
import { ACCESSCODE_QKEY } from "./config";
const query = new URLSearchParams(location.hash.slice(1));
const lsKey = "acurl"
export const url_has = (): boolean => query.has(ACCESSCODE_QKEY);
export const get = (): string => localStorage.getItem(lsKey) || "";
export const has = (): boolean => !!localStorage.getItem(lsKey);
export const clear = (): void => localStorage.removeItem(lsKey);
export function check() {
if (!url_has()) return
console.log("Found access code in URL. Saving.")
localStorage.setItem(lsKey, query.get(ACCESSCODE_QKEY) || "")
}
export function preview() {
const card = get()
const masked =
card.slice(0, 4) +
"x".repeat(card.length - 4);
return masked.match(/.{1,4}/g)?.join(" ");
}
export function previewR() {
const card = get()
return card.match(/.{1,4}/g)?.join(" ");
}
+11
View File
@@ -0,0 +1,11 @@
import { writable } from "svelte/store"
export const ANNOUNCEMENT = writable('')
// This task must not bother the existing one. Keep it async in the background instead
void (async () => {
let r = await fetch("/announcement.txt")
if (!r.ok) return;
ANNOUNCEMENT.set(await r.text())
})()
+5 -2
View File
@@ -17,7 +17,8 @@ export const FADE_OUT = { duration: 200 }
export const FADE_IN = { delay: 400 }
export const DEFAULT_PFP = '/assets/imgs/no_profile.png'
export const ANNOUNCEMENT = '' // If set, will add an announcement to the top bar. Keep it short.
// Key name for access key scanned from QR code
export const ACCESSCODE_QKEY = import.meta.env.VITE_ACCESSCODE_QKEY || "accesskey"
// Documentation for Userbox mode can be found in `docs/aquabox-url-mode.md`
// Please note that if this is set, it must be manually unset by users in Chuni Settings -> Update Userbox -> Switch to URL mode -> (empty value) -> Enter key
@@ -25,6 +26,8 @@ export const USERBOX_DEFAULT_URL = ""
export const HAS_USERBOX_ASSETS = true
export const DEFAULT_GAME = import.meta.env.VITE_DEFAULT_GAME || "mai2"
// Meow meow meow
// Matching servers
@@ -45,4 +48,4 @@ export const CHU3_MATCHINGS: ChusanMatchingOption[] = [
reflector: "http://reflector.naominet.live:18080/",
coop: ["RinNET", "MysteriaNET"],
},
]
]
+1
View File
@@ -60,6 +60,7 @@ export const EN_REF_Welcome = {
'welcome.verified': 'Your email has been verified! You can now log in now.',
'welcome.verification-failed': 'Verification failed: ${message}. Please try again.',
'welcome.password-reset-done': 'Your password has been updated! Please log back in.',
'welcome.login_link': 'Login / register to link your card.'
}
export const EN_REF_LEADERBOARD = {
+5
View File
@@ -6,6 +6,7 @@
import { t } from "../libs/i18n";
import ImportDataAction from "./Home/ImportDataAction.svelte";
import DashboardTabs from "../components/DashboardTabs.svelte";
import * as acUrl from "../libs/acUrl";
USER.ensureLoggedIn();
@@ -13,6 +14,10 @@
let error = "";
USER.me().then((m) => me = m).catch(e => error = e.message)
if (acUrl.has()) {
location.href = "/cards"
}
</script>
<main class="content">
+15
View File
@@ -9,6 +9,8 @@
import StatusOverlays from "../../components/StatusOverlays.svelte"
import { t } from "../../libs/i18n"
import DashboardTabs from "../../components/DashboardTabs.svelte";
import * as acUrl from "../../libs/acUrl"
import { ACCESSCODE_QKEY } from "../../libs/config";
// State
let state: 'ready' | 'linking-AC' | 'linking-SN' | 'loading' = "loading"
@@ -27,7 +29,10 @@
// Always put the ghost card at the top
m.cards.sort((a, b) => a.isGhost ? -1 : 1)
state = "ready"
linkQR()
}).catch(e => error = e.message)
acUrl.check()
updateMe()
// Data conflict overlay
@@ -273,6 +278,16 @@
};
inputACChange();
}
function linkQR() {
if (!acUrl.has()) return;
inputAC = acUrl.get()
if (inputAC.length !== 20) return inputAC = "";
inputACChange()
acUrl.clear()
}
</script>
<main class="content">
+2 -1
View File
@@ -9,8 +9,9 @@
import UserCard from "../components/UserCard.svelte";
import Tooltip from "../components/Tooltip.svelte";
import Cap from "./Ranking/Cap.svelte";
import { DEFAULT_GAME } from "../libs/config";
export let game: GameName = 'mai2';
export let game: GameName = DEFAULT_GAME;
title(`Ranking`);
+18
View File
@@ -6,6 +6,14 @@
import { USER } from "../libs/sdk";
import { t } from "../libs/i18n"
import * as acUrl from "../libs/acUrl"
const hasAc = acUrl.has()
let previewAc = ""
if (hasAc) {
previewAc = acUrl.preview() || ""
}
let params = new URLSearchParams(window.location.search)
let state = "home"
@@ -178,6 +186,13 @@
<main id="home" class="no-margin">
<div>
<h1 id="title">AquaNet</h1>
<div id="welcome">
{#if hasAc}
<span>{t('welcome.login_link')}:</span><br>
<small>{previewAc}</small>
{/if}
</div>
{#if state === "home"}
<div class="btn-group" transition:slide>
<button on:click={() => state = 'login'}>{t('welcome.btn-login')}</button>
@@ -329,6 +344,9 @@
margin-bottom: 32px
opacity: 0.9
#welcome
margin-bottom: 32px
.btn-group
display: flex
gap: 8px