hfstudio / frontend /src /routes /+layout.svelte
GitHub Action
Sync from GitHub: ffdd28283d24c66d2e788d9b4a630d7d9f76b0a1
d3f86d8
raw
history blame
5.83 kB
<script>
import '../app.css';
import { Home, Settings, History, Github, Menu } from 'lucide-svelte';
import { onMount } from 'svelte';
let currentPage = 'tts';
let sidebarOpen = true;
let isLoggedIn = false;
let username = '';
onMount(() => {
// Check if user is logged in
checkLoginStatus();
// Re-check login status when page becomes visible (e.g., after OAuth redirect)
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
checkLoginStatus();
}
});
// Listen for storage changes (e.g., when token is set from OAuth callback)
window.addEventListener('storage', checkLoginStatus);
// Also check periodically to catch cases where localStorage changes in same tab
const interval = setInterval(checkLoginStatus, 1000);
return () => {
window.removeEventListener('storage', checkLoginStatus);
clearInterval(interval);
};
});
function checkLoginStatus() {
const token = localStorage.getItem('hf_access_token');
if (token) {
// Fetch user info from HuggingFace API
fetchUserInfo(token);
} else {
isLoggedIn = false;
username = '';
}
}
async function fetchUserInfo(token) {
try {
// For OAuth tokens, we need to use the OAuth API endpoint
const isOAuthToken = token.startsWith('hf_oauth_');
const apiUrl = isOAuthToken
? 'https://huggingface.co/oauth/userinfo'
: 'https://huggingface.co/api/whoami';
const response = await fetch(apiUrl, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const userData = await response.json();
isLoggedIn = true;
const fullName = userData.name || userData.login || 'User';
username = fullName.split(' ')[0]; // Extract first name only
} else {
// Token might be invalid, remove it
localStorage.removeItem('hf_access_token');
isLoggedIn = false;
username = '';
}
} catch (error) {
// Token might be invalid, remove it
localStorage.removeItem('hf_access_token');
isLoggedIn = false;
username = '';
}
}
function handleAuthAction() {
if (isLoggedIn) {
// Logout
localStorage.removeItem('hf_access_token');
sessionStorage.removeItem('oauth_state');
isLoggedIn = false;
username = '';
} else {
// Login
const clientId = 'cdf32a17-e40f-4a84-b683-f66aa1105793';
const redirectUri = 'http://localhost:11111/auth/callback';
const scope = 'read-repos';
const state = Math.random().toString(36).substring(2, 15);
const authUrl = `https://huggingface.co/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&scope=${scope}&response_type=code&state=${state}`;
sessionStorage.setItem('oauth_state', state);
window.location.href = authUrl;
}
}
</script>
<div class="flex h-screen bg-white">
<!-- Sidebar -->
<aside class="w-56 border-r border-gray-200 bg-white flex-shrink-0 {sidebarOpen ? '' : 'hidden'}">
<div class="p-4 border-b border-gray-200">
<div class="flex items-center gap-3">
<img src="/assets/hf-studio-logo.png" alt="HF Logo" class="w-8 h-8" />
<h1 class="text-xl font-semibold">HFStudio<sup class="text-xs text-gray-500 ml-1">BETA</sup></h1>
</div>
</div>
<nav class="p-2 text-sm">
<div class="mt-2 mb-1 px-2 text-xs font-medium text-gray-500 uppercase">
Tasks
</div>
<button
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100 transition-colors text-left
{currentPage === 'tts' ? 'bg-gray-100' : ''}"
on:click={() => currentPage = 'tts'}
>
<span>πŸŽ™οΈ</span>
<span>Text to Speech</span>
</button>
<button
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
disabled
>
<span>🎡</span>
<span>Voice Cloning</span>
</button>
<button
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
disabled
>
<span>🎧</span>
<span>Speech to Text</span>
</button>
<button
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
disabled
>
<span>🎼</span>
<span>Sound Effects</span>
</button>
<button
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
disabled
>
<span>🎸</span>
<span>Music Generation</span>
</button>
<button
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
disabled
>
<span>πŸ”Š</span>
<span>Audio Enhancement</span>
</button>
</nav>
<!-- Sign in with Hugging Face at bottom -->
<div class="absolute bottom-4 left-2 right-2 w-52">
<button
on:click={handleAuthAction}
class="w-full px-6 py-3 bg-black text-white rounded-lg font-medium hover:bg-gray-800 transition-colors shadow-sm flex items-center justify-center gap-2 text-sm"
>
<img src="/assets/hf-logo.png" alt="HF Logo" class="w-5 h-5" />
{#if isLoggedIn}
<span>Sign Out, {username}</span>
{:else}
<span>Sign In</span>
{/if}
</button>
</div>
</aside>
<!-- Main content -->
<main class="flex-1 overflow-auto">
<slot />
</main>
</div>