From 2552568ac1b57870d73d3d26b2455e91f27c548a Mon Sep 17 00:00:00 2001 From: Yonle Date: Sat, 23 May 2026 08:01:50 +0700 Subject: [PATCH] feat: improved announcement management, custom qr access code handler, fixes --- AquaNet/{.env => .env.example} | 8 +++++- AquaNet/.gitignore | 4 ++- AquaNet/public/announcement.txt | 0 AquaNet/src/App.svelte | 9 ++++--- AquaNet/src/libs/acUrl.ts | 35 ++++++++++++++++++++++++++ AquaNet/src/libs/announcement.ts | 11 ++++++++ AquaNet/src/libs/config.ts | 7 ++++-- AquaNet/src/libs/i18n/en_ref.ts | 1 + AquaNet/src/pages/Home.svelte | 5 ++++ AquaNet/src/pages/Home/LinkCard.svelte | 15 +++++++++++ AquaNet/src/pages/Ranking.svelte | 3 ++- AquaNet/src/pages/Welcome.svelte | 18 +++++++++++++ 12 files changed, 107 insertions(+), 9 deletions(-) rename AquaNet/{.env => .env.example} (65%) create mode 100644 AquaNet/public/announcement.txt create mode 100644 AquaNet/src/libs/acUrl.ts create mode 100644 AquaNet/src/libs/announcement.ts diff --git a/AquaNet/.env b/AquaNet/.env.example similarity index 65% rename from AquaNet/.env rename to AquaNet/.env.example index 2c5fa305..c374df19 100644 --- a/AquaNet/.env +++ b/AquaNet/.env.example @@ -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 \ No newline at end of file +VITE_GITHUB_REPOSITORY=https://github.com/MewoLab/AquaDX + +# example: +# https://aquadx.net/#accesskey=.... +VITE_ACCESSCODE_QKEY=accesskey + +VITE_DEFAULT_GAME=mai2 \ No newline at end of file diff --git a/AquaNet/.gitignore b/AquaNet/.gitignore index 69166fea..6deb399a 100644 --- a/AquaNet/.gitignore +++ b/AquaNet/.gitignore @@ -35,4 +35,6 @@ dist-ssr public/chu3 # local env file -*.local \ No newline at end of file +*.local + +.env diff --git a/AquaNet/public/announcement.txt b/AquaNet/public/announcement.txt new file mode 100644 index 00000000..e69de29b diff --git a/AquaNet/src/App.svelte b/AquaNet/src/App.svelte index 948ebb61..7ff3e1ae 100644 --- a/AquaNet/src/App.svelte +++ b/AquaNet/src/App.svelte @@ -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 @@ AquaNet {/if} - {#if ANNOUNCEMENT} + {#if $ANNOUNCEMENT}
- {t('navigation.notice')}: {ANNOUNCEMENT} + {t('navigation.notice')}: {$ANNOUNCEMENT}
{/if} {t('navigation.home').toLowerCase()} diff --git a/AquaNet/src/libs/acUrl.ts b/AquaNet/src/libs/acUrl.ts new file mode 100644 index 00000000..9d79c7b9 --- /dev/null +++ b/AquaNet/src/libs/acUrl.ts @@ -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(" "); +} \ No newline at end of file diff --git a/AquaNet/src/libs/announcement.ts b/AquaNet/src/libs/announcement.ts new file mode 100644 index 00000000..63b0f2ff --- /dev/null +++ b/AquaNet/src/libs/announcement.ts @@ -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()) +})() \ No newline at end of file diff --git a/AquaNet/src/libs/config.ts b/AquaNet/src/libs/config.ts index df32060b..a668266c 100644 --- a/AquaNet/src/libs/config.ts +++ b/AquaNet/src/libs/config.ts @@ -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"], }, -] +] \ No newline at end of file diff --git a/AquaNet/src/libs/i18n/en_ref.ts b/AquaNet/src/libs/i18n/en_ref.ts index c0cadac9..a2eb5ab1 100644 --- a/AquaNet/src/libs/i18n/en_ref.ts +++ b/AquaNet/src/libs/i18n/en_ref.ts @@ -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 = { diff --git a/AquaNet/src/pages/Home.svelte b/AquaNet/src/pages/Home.svelte index c36f120c..681d6307 100644 --- a/AquaNet/src/pages/Home.svelte +++ b/AquaNet/src/pages/Home.svelte @@ -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" + }
diff --git a/AquaNet/src/pages/Home/LinkCard.svelte b/AquaNet/src/pages/Home/LinkCard.svelte index db1ad025..513e69a9 100644 --- a/AquaNet/src/pages/Home/LinkCard.svelte +++ b/AquaNet/src/pages/Home/LinkCard.svelte @@ -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() + }
diff --git a/AquaNet/src/pages/Ranking.svelte b/AquaNet/src/pages/Ranking.svelte index c942835f..52269922 100644 --- a/AquaNet/src/pages/Ranking.svelte +++ b/AquaNet/src/pages/Ranking.svelte @@ -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`); diff --git a/AquaNet/src/pages/Welcome.svelte b/AquaNet/src/pages/Welcome.svelte index 9442fc57..0676cffd 100644 --- a/AquaNet/src/pages/Welcome.svelte +++ b/AquaNet/src/pages/Welcome.svelte @@ -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 @@

AquaNet

+
+ {#if hasAc} + {t('welcome.login_link')}:
+ {previewAc} + {/if} +
+ {#if state === "home"}
@@ -329,6 +344,9 @@ margin-bottom: 32px opacity: 0.9 + #welcome + margin-bottom: 32px + .btn-group display: flex gap: 8px