feat: add url support (wip)

pull/99/head
Raymond 2025-01-04 18:00:08 -05:00
parent f68bd54ccd
commit 82a0473287
3 changed files with 61 additions and 16 deletions

View File

@ -96,6 +96,7 @@
let USERBOX_PROGRESS = 0;
let USERBOX_SETUP_RUN = false;
let USERBOX_SETUP_MODE = false;
let USERBOX_SETUP_TEXT = t("userbox.new.setup");
let USERBOX_ENABLED = useLocalStorage("userboxNew", false);
@ -117,6 +118,20 @@
}) ?? "";
}
function userboxHandleInput(e: KeyboardEvent) {
if (e.key != "Enter")
return;
let baseURL = (e.target as HTMLInputElement).value;
try {
// validate url
new URL(baseURL);
} catch(err) {
return error = t("userbox.new.error.invalidUrl")
}
useLocalStorage("userboxURL", "").value = baseURL;
location.reload();
}
indexedDB.databases().then(async (dbi) => {
let databaseExists = dbi.some(db => db.name == "userboxChusanDDS");
if (databaseExists) {
@ -233,7 +248,7 @@
<button on:click={() => USERBOX_SETUP_RUN = !USERBOX_SETUP_RUN}>{t(!USERBOX_INSTALLED ? `userbox.new.activate_first` : `userbox.new.activate_update`)}</button>
</p>
{/if}
{#if !USERBOX_SUPPORT || !USERBOX_INSTALLED || !USERBOX_ENABLED.value}
<!--{#if !USERBOX_SUPPORT || !USERBOX_INSTALLED || !USERBOX_ENABLED.value}
<h2>{t("userbox.header.preview")}</h2>
<p class="notice">{t("userbox.preview.notice")}</p>
<input bind:value={preview} placeholder={t("userbox.preview.url")}/>
@ -247,7 +262,7 @@
{/each}
</div>
{/if}
{/if}
{/if}-->
{/if}
</div>
{/if}
@ -256,21 +271,28 @@
<div class="overlay" transition:fade>
<div>
<h2>{t('userbox.new.name')}</h2>
<span>{USERBOX_SETUP_TEXT}</span>
<span>{USERBOX_SETUP_MODE ? t('userbox.preview.notice') + " " + t('userbox.new.url_warning') : USERBOX_SETUP_TEXT}</span>
<div class="actions">
{#if USERBOX_PROGRESS != 0}
<div class="progress">
<div class="progress-bar" style="width: {USERBOX_PROGRESS}%"></div>
</div>
{#if USERBOX_SETUP_MODE}
<input type="text" on:keyup={userboxHandleInput} class="base-url-text" placeholder="Base URL">
{:else}
<button class="drop-btn">
<input type="file" on:input={userboxSafeDrop} on:click={e => e.preventDefault()}>
{t('userbox.new.drop')}
</button>
{#if USERBOX_PROGRESS != 0}
<div class="progress">
<div class="progress-bar" style="width: {USERBOX_PROGRESS}%"></div>
</div>
{:else}
<button class="drop-btn">
<input type="file" on:input={userboxSafeDrop} on:click={e => e.preventDefault()}>
{t('userbox.new.drop')}
</button>
{/if}
{/if}
<button on:click={() => USERBOX_SETUP_RUN = false}>
{t('back')}
</button>
{/if}
<button on:click={() => USERBOX_SETUP_MODE = !USERBOX_SETUP_MODE}>
{t(USERBOX_SETUP_MODE ? 'userbox.new.switch.to_drop' : 'userbox.new.switch.to_url')}
</button>
</div>
</div>
</div>
@ -304,13 +326,15 @@ p.notice
border-radius: 25px
.base-url-text, .drop-btn
margin-bottom: 1em
.drop-btn
position: relative
width: 100%
aspect-ratio: 3
background: transparent
box-shadow: 0 0 1px 1px vars.$ov-lighter
margin-bottom: 1em
> input
position: absolute

View File

@ -92,7 +92,7 @@ export const EN_REF_HOME = {
'home.linkcard.account-card': 'Account Card',
'home.linkcard.registered': 'Registered',
'home.linkcard.lastused': 'Last used',
'home.linkcard.enter-info': 'Please enter the following information',
'home.linkcard.enter-info': 'Please enter the following information, or drag and drop your aime.txt / felica.txt file here',
'home.linkcard.access-code': 'The 20-digit access code on the back of your card. (If it doesn\'t work, please try scanning your card in game and enter the access code shown on screen)',
'home.linkcard.enter-sn1': 'Download the NFC Tools app on your phone',
'home.linkcard.enter-sn2': 'and scan your card. Then, enter the Serial Number.',
@ -180,18 +180,30 @@ export const EN_REF_USERBOX = {
'userbox.preview.url': 'Image URL',
'userbox.error.nodata': 'Chuni data not found',
'userbox.matching.select': 'Select Matching Server',
'userbox.matching.select.sub': 'Choose the matching server you want to use.',
'userbox.matching.option.ui': 'Rooms',
'userbox.matching.option.guide': 'Guide',
'userbox.matching.option.collab': 'Collaborators',
'userbox.matching.custom.name': 'Custom',
'userbox.matching.custom.sub': 'Enter your own URL',
'userbox.new.name': 'AquaBox',
'userbox.new.setup': 'Drag and drop your Chuni game folder (Lumi or newer) into the box below to display UserBoxes with their nameplate & avatar. All files are handled in-browser.',
'userbox.new.setup.processing_file': 'Processing',
'userbox.new.setup.finalizing': 'Saving to internal storage',
'userbox.new.drop': 'Drop game folder here',
'userbox.new.switch.to_url': 'Switch to URL mode',
'userbox.new.switch.to_drop': 'Switch to drop mode',
'userbox.new.url_warning': 'You are responsible for the results in this state. Please read the documentation.',
'userbox.new.activate_first': 'Enable AquaBox (game files required)',
'userbox.new.activate_update': 'Update AquaBox (game files required)',
'userbox.new.activate': 'Use AquaBox',
'userbox.new.activate_desc': 'Enable displaying UserBoxes with their nameplate & avatar',
'userbox.new.activate_profile': 'Use AquaBox on profiles',
'userbox.new.activate_profile_desc': 'Enable displaying UserBoxes with their nameplate & avatar on profile pages',
'userbox.new.error.invalidFolder': 'The folder you selected is invalid. Ensure that your game\'s version is Lumi or newer and that the "A001" option pack is present.'
'userbox.new.error.invalidFolder': 'The folder you selected is invalid. Ensure that your game\'s version is Lumi or newer and that the "A000" option pack is present.',
'userbox.new.error.invalidUrl': 'The URL you inputted is invalid.'
}
export const EN_REF = { ...EN_REF_USER, ...EN_REF_Welcome, ...EN_REF_GENERAL,

View File

@ -1,3 +1,5 @@
import useLocalStorage from "../hooks/useLocalStorage.svelte";
export default class DDSCache {
constructor(db: IDBDatabase | undefined) {
this.db = db;
@ -43,7 +45,13 @@ export default class DDSCache {
* @param path Image path
*/
getFromDatabase(path: string): Promise<Blob | null> {
return new Promise((resolve, reject) => {
return new Promise(async (resolve, reject) => {
if (this.userboxURL.value) {
let targetPath = path.replaceAll(":", "/");
let response = await fetch(`${this.userboxURL.value}/${targetPath}.dds`).then(b => b.blob()).catch(reject);
if (response)
return resolve(response);
};
if (!this.db)
return resolve(null);
let transaction = this.db.transaction(["dds"], "readonly");
@ -61,4 +69,5 @@ export default class DDSCache {
private urlCache: {scale: number, path: string, url: string}[] = [];
private db: IDBDatabase | undefined;
private userboxURL = useLocalStorage("userboxURL", "");
}