piclets / src /App.svelte
Fraser's picture
fix imps
f0b54f8
<script lang="ts">
import { onMount } from 'svelte';
import { authStore } from './lib/stores/auth';
import { uiStore } from './lib/stores/ui';
import AppHeader from './lib/components/Layout/AppHeader.svelte';
import ProgressBar from './lib/components/Layout/ProgressBar.svelte';
import TabBar, { type TabId } from './lib/components/Layout/TabBar.svelte';
import Scanner from './lib/components/Pages/Scanner.svelte';
import Encounters from './lib/components/Pages/Encounters.svelte';
import Pictuary from './lib/components/Pages/Pictuary.svelte';
import type { HuggingFaceLibs, GradioLibs, GradioClient } from './lib/types';
// import { setQwenClientResetter } from './lib/utils/qwenTimeout'; // Unused since qwen is disabled
// These will be loaded from window after HF libs are loaded
let hfAuth: HuggingFaceLibs | null = $state(null);
let gradioClient: GradioLibs | null = $state(null);
// Gradio client instances
let fluxClient: GradioClient | null = $state(null);
let joyCaptionClient: GradioClient | null = $state(null);
let hunyuanClient: GradioClient | null = $state(null);
// Unused clients (kept for future use but not initialized)
// let zephyrClient: GradioClient | null = $state(null);
// let qwenClient: GradioClient | null = $state(null);
// let commandClient: GradioClient | null = $state(null);
// let dotsClient: GradioClient | null = $state(null);
// Navigation state
let activeTab: TabId = $state('scanner');
// Tab names mapping
const tabNames: Record<TabId, string> = {
scanner: 'Scanner',
encounters: 'Encounters',
pictuary: 'Pictuary'
};
// Auth state from store (unused but authStore is used elsewhere)
// const auth = $derived(authStore);
// UI state
let isDetailPageOpen = $state(false);
let isInBattle = $state(false);
$effect(() => {
const unsubscribe = uiStore.subscribe(state => {
isDetailPageOpen = state.isDetailPageOpen;
isInBattle = state.isInBattle;
});
return unsubscribe;
});
onMount(async () => {
// Load HF libraries
const script1 = document.createElement('script');
script1.type = 'module';
script1.textContent = `
import {
oauthLoginUrl,
oauthHandleRedirectIfPresent
} from "https://cdn.jsdelivr.net/npm/@huggingface/hub@0.21/+esm";
import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
window.hfAuth = { oauthLoginUrl, oauthHandleRedirectIfPresent };
window.gradioClient = { Client };
`;
document.head.appendChild(script1);
// Wait for libraries to load
await new Promise(resolve => {
const checkLibs = setInterval(() => {
if (window.hfAuth && window.gradioClient) {
clearInterval(checkLibs);
resolve(undefined);
}
}, 100);
});
hfAuth = window.hfAuth as HuggingFaceLibs;
gradioClient = window.gradioClient as GradioLibs;
// Handle OAuth redirect
try {
const session = await hfAuth.oauthHandleRedirectIfPresent();
authStore.setSession(session);
// Start the app
await initializeClients(session?.accessToken || null);
} catch (err) {
console.error("OAuth handling error:", err);
authStore.setSession(null);
await initializeClients(null);
}
});
async function initializeClients(hfToken: string | null) {
if (!gradioClient) return;
authStore.setBannerMessage("Connecting to AI services...");
try {
const opts = hfToken ? { hf_token: hfToken } : {};
// Connect to essential spaces only
fluxClient = await gradioClient.Client.connect(
"black-forest-labs/FLUX.1-schnell",
opts
);
joyCaptionClient = await gradioClient.Client.connect(
"fancyfeast/joy-caption-alpha-two",
opts
);
hunyuanClient = await gradioClient.Client.connect(
"tencent/hunyuan-turbos",
opts
);
// Unused clients (commented out to save resources)
// zephyrClient = await gradioClient.Client.connect(
// "Fraser/zephyr-7b",
// opts
// );
// qwenClient = await gradioClient.Client.connect(
// "Qwen/Qwen3-Demo",
// opts
// );
// commandClient = await gradioClient.Client.connect(
// "Fraser/command-a-vision",
// opts
// );
// dotsClient = await gradioClient.Client.connect(
// "Fraser/dots-demo",
// opts
// );
authStore.setBannerMessage("");
// Qwen client reset function (commented out since qwen is not used)
// setQwenClientResetter(async () => {
// console.log('🔄 Resetting qwen client connection...');
// const opts = hfToken ? { hf_token: hfToken } : {};
// qwenClient = await gradioClient.Client.connect(
// "Qwen/Qwen3-Demo",
// opts
// );
// });
} catch (err) {
console.error(err);
authStore.setBannerMessage(`❌ Failed to connect: ${err}`);
}
}
function handleTabChange(tab: TabId) {
activeTab = tab;
}
</script>
<div class="app">
{#if !isDetailPageOpen && !isInBattle}
<ProgressBar />
<AppHeader {hfAuth} currentTab={tabNames[activeTab]} />
{/if}
<main class="app-content" class:detail-open={isDetailPageOpen}>
{#if activeTab === 'scanner'}
<Scanner
{fluxClient}
{joyCaptionClient}
{hunyuanClient}
/>
{:else if activeTab === 'encounters'}
<Encounters />
{:else if activeTab === 'pictuary'}
<Pictuary />
{/if}
</main>
{#if !isDetailPageOpen && !isInBattle}
<TabBar {activeTab} onTabChange={handleTabChange} />
{/if}
</div>
<style>
.app {
display: flex;
flex-direction: column;
height: 100vh;
height: 100dvh; /* Dynamic viewport height for mobile */
background: white;
overflow: hidden;
}
.app-content {
flex: 1;
overflow: hidden;
position: relative;
padding-bottom: calc(70px + env(safe-area-inset-bottom, 0));
}
.app-content.detail-open {
padding-bottom: 0;
}
/* Ensure content scrolls properly on iOS */
:global(.app-content > *) {
height: 100%;
}
</style>