You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
301 lines
8.0 KiB
301 lines
8.0 KiB
<script lang="ts"> |
|
import { onMount } from 'svelte'; |
|
import { goto } from '$app/navigation'; |
|
import { page } from '$app/stores'; |
|
import { getPublicKeyWithNIP07, isNIP07Available } from '../lib/services/nostr/nip07-signer.js'; |
|
import { nip19 } from 'nostr-tools'; |
|
|
|
let userPubkey = $state<string | null>(null); |
|
let userPubkeyHex = $state<string | null>(null); |
|
let checkingAuth = $state(true); |
|
|
|
onMount(async () => { |
|
await checkAuth(); |
|
}); |
|
|
|
async function checkAuth() { |
|
checkingAuth = true; |
|
if (isNIP07Available()) { |
|
try { |
|
userPubkey = await getPublicKeyWithNIP07(); |
|
// Convert npub to hex for API calls |
|
try { |
|
const decoded = nip19.decode(userPubkey); |
|
if (decoded.type === 'npub') { |
|
userPubkeyHex = decoded.data as string; |
|
} |
|
} catch { |
|
userPubkeyHex = userPubkey; // Assume it's already hex |
|
} |
|
} catch (err) { |
|
console.warn('Failed to load user pubkey:', err); |
|
} |
|
} |
|
checkingAuth = false; |
|
} |
|
|
|
async function handleLogin() { |
|
if (isNIP07Available()) { |
|
try { |
|
await checkAuth(); |
|
if (userPubkey) { |
|
// User is logged in, go to repos page |
|
goto('/repos'); |
|
} |
|
} catch (err) { |
|
console.error('Login failed:', err); |
|
alert('Failed to login. Please make sure you have a Nostr extension installed (like nos2x or Alby).'); |
|
} |
|
} else { |
|
alert('Nostr extension not found. Please install a Nostr extension like nos2x or Alby to login.'); |
|
} |
|
} |
|
|
|
function handleViewPublic() { |
|
goto('/repos'); |
|
} |
|
|
|
// Get page data for OpenGraph metadata |
|
const pageData = $page.data as { |
|
title?: string; |
|
description?: string; |
|
image?: string; |
|
url?: string; |
|
ogType?: string; |
|
}; |
|
</script> |
|
|
|
<svelte:head> |
|
<title>{pageData.title || 'GitRepublic - Decentralized Git Hosting on Nostr'}</title> |
|
<meta name="description" content={pageData.description || 'A decentralized git hosting platform built on Nostr. Host your repositories, collaborate with others, and maintain full control of your code.'} /> |
|
|
|
<!-- OpenGraph / Facebook --> |
|
<meta property="og:type" content={pageData.ogType || 'website'} /> |
|
<meta property="og:title" content={pageData.title || 'GitRepublic - Decentralized Git Hosting on Nostr'} /> |
|
<meta property="og:description" content={pageData.description || 'A decentralized git hosting platform built on Nostr. Host your repositories, collaborate with others, and maintain full control of your code.'} /> |
|
<meta property="og:url" content={pageData.url || `https://${$page.url.host}${$page.url.pathname}`} /> |
|
{#if pageData.image} |
|
<meta property="og:image" content={pageData.image} /> |
|
<meta property="og:image:width" content="1200" /> |
|
<meta property="og:image:height" content="630" /> |
|
{/if} |
|
|
|
<!-- Twitter Card --> |
|
<meta name="twitter:card" content="summary_large_image" /> |
|
<meta name="twitter:title" content={pageData.title || 'GitRepublic - Decentralized Git Hosting on Nostr'} /> |
|
<meta name="twitter:description" content={pageData.description || 'A decentralized git hosting platform built on Nostr. Host your repositories, collaborate with others, and maintain full control of your code.'} /> |
|
{#if pageData.image} |
|
<meta name="twitter:image" content={pageData.image} /> |
|
{/if} |
|
</svelte:head> |
|
|
|
<div class="splash-container"> |
|
<div class="splash-background"> |
|
<img src="/logo.png" alt="GitRepublic Logo" class="splash-logo-bg" /> |
|
</div> |
|
|
|
<div class="splash-content"> |
|
<div class="splash-header"> |
|
<h1 class="splash-title">GitRepublic</h1> |
|
<p class="splash-subtitle">Decentralized Git Hosting on Nostr</p> |
|
</div> |
|
|
|
<div class="splash-message"> |
|
{#if checkingAuth} |
|
<p class="splash-text">Checking authentication...</p> |
|
{:else if userPubkey} |
|
<p class="splash-text">Welcome back! You're logged in.</p> |
|
<p class="splash-text-secondary">You can now access all repositories you have permission to view.</p> |
|
{:else} |
|
<p class="splash-text">Login for full functionality</p> |
|
<p class="splash-text-secondary">Access your private repositories, create new ones, and collaborate with others.</p> |
|
<p class="splash-text-secondary">Or browse public repositories without logging in.</p> |
|
{/if} |
|
</div> |
|
|
|
<div class="splash-actions"> |
|
{#if checkingAuth} |
|
<div class="splash-loading">Loading...</div> |
|
{:else if userPubkey} |
|
<button class="splash-button splash-button-primary" onclick={() => goto('/repos')}> |
|
View Repositories |
|
</button> |
|
{:else} |
|
<button class="splash-button splash-button-primary" onclick={handleLogin}> |
|
Login with Nostr |
|
</button> |
|
<button class="splash-button splash-button-secondary" onclick={handleViewPublic}> |
|
View Public Repositories |
|
</button> |
|
{/if} |
|
</div> |
|
|
|
</div> |
|
</div> |
|
|
|
<style> |
|
.splash-container { |
|
min-height: 100vh; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
position: relative; |
|
overflow: hidden; |
|
background: linear-gradient(135deg, var(--bg-primary, #f5f5f5) 0%, var(--bg-secondary, #e8e8e8) 100%); |
|
} |
|
|
|
.splash-background { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
opacity: 0.05; |
|
z-index: 0; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.splash-logo-bg { |
|
width: 80vw; |
|
height: 80vh; |
|
object-fit: contain; |
|
filter: blur(20px); |
|
} |
|
|
|
.splash-content { |
|
position: relative; |
|
z-index: 1; |
|
text-align: center; |
|
padding: 3rem 2rem; |
|
max-width: 800px; |
|
width: 100%; |
|
} |
|
|
|
.splash-header { |
|
margin-bottom: 3rem; |
|
} |
|
|
|
.splash-title { |
|
font-size: 3.5rem; |
|
font-weight: 700; |
|
margin: 0 0 0.5rem; |
|
color: var(--text-primary, #1a1a1a); |
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
.splash-subtitle { |
|
font-size: 1.5rem; |
|
color: var(--text-secondary, #666); |
|
margin: 0; |
|
font-weight: 300; |
|
} |
|
|
|
.splash-message { |
|
margin-bottom: 3rem; |
|
} |
|
|
|
.splash-text { |
|
font-size: 1.5rem; |
|
color: var(--text-primary, #1a1a1a); |
|
margin: 0 0 1rem; |
|
font-weight: 500; |
|
} |
|
|
|
.splash-text-secondary { |
|
font-size: 1.1rem; |
|
color: var(--text-secondary, #666); |
|
margin: 0.5rem 0; |
|
line-height: 1.6; |
|
} |
|
|
|
.splash-actions { |
|
display: flex; |
|
gap: 1rem; |
|
justify-content: center; |
|
flex-wrap: wrap; |
|
margin-bottom: 4rem; |
|
} |
|
|
|
.splash-button { |
|
padding: 1rem 2.5rem; |
|
font-size: 1.1rem; |
|
font-weight: 600; |
|
border: none; |
|
border-radius: 8px; |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
text-decoration: none; |
|
display: inline-block; |
|
min-width: 200px; |
|
} |
|
|
|
.splash-button-primary { |
|
background: var(--accent, #007bff); |
|
color: white; |
|
box-shadow: 0 4px 6px rgba(0, 123, 255, 0.3); |
|
} |
|
|
|
.splash-button-primary:hover { |
|
background: var(--accent-hover, #0056b3); |
|
transform: translateY(-2px); |
|
box-shadow: 0 6px 12px rgba(0, 123, 255, 0.4); |
|
} |
|
|
|
.splash-button-secondary { |
|
background: white; |
|
color: var(--accent, #007bff); |
|
border: 2px solid var(--accent, #007bff); |
|
} |
|
|
|
.splash-button-secondary:hover { |
|
background: var(--accent, #007bff); |
|
color: white; |
|
transform: translateY(-2px); |
|
} |
|
|
|
.splash-loading { |
|
font-size: 1.2rem; |
|
color: var(--text-secondary, #666); |
|
padding: 2rem; |
|
} |
|
|
|
@media (max-width: 768px) { |
|
.splash-title { |
|
font-size: 2.5rem; |
|
} |
|
|
|
.splash-subtitle { |
|
font-size: 1.2rem; |
|
} |
|
|
|
.splash-text { |
|
font-size: 1.2rem; |
|
} |
|
|
|
.splash-button { |
|
width: 100%; |
|
min-width: unset; |
|
} |
|
} |
|
|
|
@media (prefers-color-scheme: dark) { |
|
.splash-container { |
|
background: linear-gradient(135deg, var(--bg-primary, #1a1a1a) 0%, var(--bg-secondary, #2d2d2d) 100%); |
|
} |
|
|
|
.splash-title { |
|
color: var(--text-primary, #f5f5f5); |
|
} |
|
|
|
.splash-text { |
|
color: var(--text-primary, #f5f5f5); |
|
} |
|
|
|
.splash-button-secondary { |
|
background: var(--bg-secondary, #2d2d2d); |
|
border-color: var(--accent, #007bff); |
|
} |
|
} |
|
</style>
|
|
|