moduler sayfa yapısına gecıldı
This commit is contained in:
+72
-172
@@ -1,190 +1,90 @@
|
|||||||
import './style.css'
|
import './style.css'
|
||||||
import PocketBase from 'pocketbase'
|
import PocketBase from 'pocketbase'
|
||||||
|
import { renderSettings } from './pages/settings.js'
|
||||||
|
import { renderDesktop } from './pages/desktop.js'
|
||||||
|
|
||||||
const pb = new PocketBase('https://pocketbase.iontalp.com')
|
const pb = new PocketBase('https://pocketbase.iontalp.com')
|
||||||
const app = document.getElementById('app')
|
const app = document.getElementById('app')
|
||||||
|
|
||||||
|
let activeTab = 'desktop'
|
||||||
|
|
||||||
async function render() {
|
async function render() {
|
||||||
const user = pb.authStore.model
|
const user = pb.authStore.model
|
||||||
|
|
||||||
if (user) {
|
if (!user) {
|
||||||
// 1. PocketBase'den Arka Plan Resimlerini Çek
|
renderLogin()
|
||||||
let bgUrl = 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?q=80&w=1920' // Varsayılan görsel
|
return
|
||||||
try {
|
}
|
||||||
const records = await pb.collection('backgrounds').getFullList()
|
|
||||||
if (records.length > 0) {
|
|
||||||
// Rastgele bir arka plan seç
|
|
||||||
const randomBg = records[Math.floor(Math.random() * records.length)]
|
|
||||||
bgUrl = pb.files.getURL(randomBg, randomBg.image)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log('Arka plan yüklenirken hata oluştu, varsayılan görsel kullanılıyor.', err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Masaüstü Arayüzü (WeTransfer Tarzı Hibrit Tasarım)
|
let currentBg = localStorage.getItem('selected_bg') || 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?q=80&w=1920'
|
||||||
app.innerHTML = `
|
|
||||||
<div class="relative min-h-screen w-full overflow-hidden text-slate-100 flex">
|
|
||||||
|
|
||||||
<!-- Dinamik Arka Plan Görseli -->
|
|
||||||
<div class="absolute inset-0 z-10 bg-cover bg-center transition-all duration-1000"
|
|
||||||
style="background-image: url('${bgUrl}');">
|
|
||||||
</div>
|
|
||||||
<div class="absolute inset-0 z-0 bg-slate-950/30 backdrop-blur-[2px]"></div>
|
|
||||||
|
|
||||||
<!-- Sol Açılır / Kapanır Menü (Sidebar) -->
|
// Sayfayı Yükle
|
||||||
<aside id="sidebar"
|
let currentPage
|
||||||
class="relative z-20 w-72 h-screen bg-slate-900/80 backdrop-blur-xl border-r border-white/10 p-6 flex flex-col justify-between transition-all duration-300 transform translate-x-0">
|
if (activeTab === 'settings') {
|
||||||
|
currentPage = await renderSettings(pb, currentBg, (newBg) => {
|
||||||
<div>
|
localStorage.setItem('selected_bg', newBg)
|
||||||
<!-- Header & Toggle -->
|
|
||||||
<div class="flex items-center justify-between mb-8">
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<div class="w-10 h-10 rounded-xl bg-indigo-600/30 border border-indigo-500/30 flex items-center justify-center font-bold text-indigo-400">
|
|
||||||
OS
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h1 class="font-bold text-white leading-none">Dashboard</h1>
|
|
||||||
<span class="text-xs text-slate-400">v1.0.0</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button id="toggleSidebarBtn" class="text-slate-400 hover:text-white transition-colors p-1">
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Menü Linkleri -->
|
|
||||||
<nav class="space-y-2">
|
|
||||||
<a href="#" class="flex items-center gap-3 px-4 py-3 bg-white/10 text-white rounded-xl font-medium transition-all">
|
|
||||||
<span>🏠</span> Masaüstü
|
|
||||||
</a>
|
|
||||||
<a href="#" class="flex items-center gap-3 px-4 py-3 text-slate-400 hover:bg-white/5 hover:text-white rounded-xl transition-all">
|
|
||||||
<span>📁</span> Dosyalarım
|
|
||||||
</a>
|
|
||||||
<a href="#" class="flex items-center gap-3 px-4 py-3 text-slate-400 hover:bg-white/5 hover:text-white rounded-xl transition-all">
|
|
||||||
<span>⚙️</span> Ayarlar
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Alt Kullanıcı Profili & Çıkış -->
|
|
||||||
<div class="pt-6 border-t border-white/10">
|
|
||||||
<div class="flex items-center gap-3 mb-4">
|
|
||||||
<div class="w-9 h-9 rounded-full bg-emerald-500/20 text-emerald-400 font-bold flex items-center justify-center border border-emerald-500/30">
|
|
||||||
${user.email.charAt(0).toUpperCase()}
|
|
||||||
</div>
|
|
||||||
<div class="overflow-hidden">
|
|
||||||
<p class="text-sm font-medium text-white truncate">${user.email}</p>
|
|
||||||
<p class="text-xs text-emerald-400 flex items-center gap-1">● Çevrimiçi</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button id="logoutBtn" class="w-full bg-rose-500/20 hover:bg-rose-500/30 text-rose-300 border border-rose-500/30 font-medium py-2 rounded-xl transition-all text-sm flex items-center justify-center gap-2">
|
|
||||||
<span>🚪</span> Çıkış Yap
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<!-- Sidebar Kapalıyken Çıkan Açma Butonu -->
|
|
||||||
<button id="openSidebarBtn" class="hidden absolute top-6 left-6 z-30 bg-slate-900/80 backdrop-blur-md border border-white/10 p-3 rounded-xl text-white hover:bg-slate-800 transition-all">
|
|
||||||
☰
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Ana Masaüstü Alanı (WeTransfer Widget Tarzı) -->
|
|
||||||
<main class="relative z-10 flex-1 h-screen p-8 flex items-center justify-center">
|
|
||||||
|
|
||||||
<!-- WeTransfer Tarzı Ortalanmış Transparan Kart -->
|
|
||||||
<div class="bg-slate-900/40 backdrop-blur-2xl border border-white/10 p-8 rounded-3xl shadow-2xl max-w-lg w-full text-center space-y-6">
|
|
||||||
<div class="inline-flex p-3 bg-indigo-500/20 border border-indigo-500/30 rounded-2xl text-indigo-300 text-3xl mb-2">
|
|
||||||
✨
|
|
||||||
</div>
|
|
||||||
<h2 class="text-3xl font-bold text-white">Hayırla Geldiniz!</h2>
|
|
||||||
<p class="text-slate-300 text-sm leading-relaxed">
|
|
||||||
Kendi bulut sunucunda çalışan bağımsız masaüstü panelindesin. Sol menüyü kullanarak navigasyonu yönetebilir veya arka planın tadını çıkarabilirsin.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="pt-4 flex gap-3 justify-center">
|
|
||||||
<button onclick="location.reload()" class="bg-white/10 hover:bg-white/20 text-white border border-white/10 px-5 py-2.5 rounded-xl text-sm font-medium transition-all">
|
|
||||||
🔄 Arka Planı Değiştir
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
|
|
||||||
// Sidebar Açma / Kapama Mantığı
|
|
||||||
const sidebar = document.getElementById('sidebar')
|
|
||||||
const toggleBtn = document.getElementById('toggleSidebarBtn')
|
|
||||||
const openBtn = document.getElementById('openSidebarBtn')
|
|
||||||
|
|
||||||
toggleBtn.addEventListener('click', () => {
|
|
||||||
sidebar.classList.add('-translate-x-full', 'absolute')
|
|
||||||
openBtn.classList.remove('hidden')
|
|
||||||
})
|
|
||||||
|
|
||||||
openBtn.addEventListener('click', () => {
|
|
||||||
sidebar.classList.remove('-translate-x-full', 'absolute')
|
|
||||||
openBtn.classList.add('hidden')
|
|
||||||
})
|
|
||||||
|
|
||||||
document.getElementById('logoutBtn').addEventListener('click', () => {
|
|
||||||
pb.authStore.clear()
|
|
||||||
render()
|
render()
|
||||||
})
|
})
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Giriş yapılmamışsa mevcut Login ekranını göster...
|
currentPage = renderDesktop()
|
||||||
app.innerHTML = `
|
|
||||||
<div class="min-h-screen bg-slate-950 text-slate-100 flex items-center justify-center p-4">
|
|
||||||
<div class="bg-slate-900 border border-slate-800 p-8 rounded-2xl shadow-2xl w-full max-w-md">
|
|
||||||
<div class="text-center mb-8">
|
|
||||||
<h1 class="text-3xl font-bold tracking-tight text-white mb-2">Giriş Yap</h1>
|
|
||||||
<p class="text-slate-400 text-sm">PocketBase hesabınızla oturum açın</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="loginForm" class="space-y-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-slate-300 mb-1.5">E-posta</label>
|
|
||||||
<input type="text" id="identity" required
|
|
||||||
class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-slate-100 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all placeholder-slate-600"
|
|
||||||
placeholder="kullanici@mail.com" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-slate-300 mb-1.5">Şifre</label>
|
|
||||||
<input type="password" id="password" required
|
|
||||||
class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-slate-100 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all placeholder-slate-600"
|
|
||||||
placeholder="••••••••" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="errorMsg" class="text-rose-400 text-sm hidden bg-rose-500/10 border border-rose-500/20 p-3 rounded-lg text-center"></div>
|
|
||||||
|
|
||||||
<button type="submit"
|
|
||||||
class="w-full bg-indigo-600 hover:bg-indigo-500 text-white font-medium py-2.5 rounded-xl transition-all shadow-lg shadow-indigo-600/20 active:scale-[0.98]">
|
|
||||||
Giriş Yap
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
|
|
||||||
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
const identity = document.getElementById('identity').value
|
|
||||||
const password = document.getElementById('password').value
|
|
||||||
const errorMsg = document.getElementById('errorMsg')
|
|
||||||
|
|
||||||
try {
|
|
||||||
errorMsg.classList.add('hidden')
|
|
||||||
await pb.collection('users').authWithPassword(identity, password)
|
|
||||||
render()
|
|
||||||
} catch (err) {
|
|
||||||
errorMsg.textContent = 'Giriş başarısız! E-posta veya şifre hatalı.'
|
|
||||||
errorMsg.classList.remove('hidden')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.innerHTML = `
|
||||||
|
<div class="relative w-full h-screen overflow-hidden bg-slate-950 text-slate-100 flex">
|
||||||
|
<div class="absolute inset-0 z-0 bg-cover bg-center bg-no-repeat transition-all duration-700" style="background-image: url('${currentBg}');"></div>
|
||||||
|
<div class="absolute inset-0 z-10 bg-slate-950/50 backdrop-blur-[2px]"></div>
|
||||||
|
|
||||||
|
<aside class="relative z-30 w-72 h-screen bg-slate-900/80 backdrop-blur-xl border-r border-white/10 p-6 flex flex-col justify-between">
|
||||||
|
<div>
|
||||||
|
<h1 class="font-bold text-white mb-6 text-xl">Dashboard OS</h1>
|
||||||
|
<nav class="space-y-2">
|
||||||
|
<button id="navDesktop" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl font-medium ${activeTab === 'desktop' ? 'bg-white/10 text-white' : 'text-slate-400 hover:text-white'}">🏠 Masaüstü</button>
|
||||||
|
<button id="navSettings" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl font-medium ${activeTab === 'settings' ? 'bg-white/10 text-white' : 'text-slate-400 hover:text-white'}">⚙️ Ayarlar</button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<button id="logoutBtn" class="bg-rose-500/20 text-rose-300 py-2 rounded-xl border border-rose-500/30">🚪 Çıkış Yap</button>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main id="mainContent" class="relative z-20 flex-1 h-screen p-8 flex items-center justify-center">
|
||||||
|
${currentPage.html}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
// Etkinlikleri bağla
|
||||||
|
const mainContent = document.getElementById('mainContent')
|
||||||
|
currentPage.initEvents(mainContent)
|
||||||
|
|
||||||
|
document.getElementById('navDesktop').addEventListener('click', () => { activeTab = 'desktop'; render() })
|
||||||
|
document.getElementById('navSettings').addEventListener('click', () => { activeTab = 'settings'; render() })
|
||||||
|
document.getElementById('logoutBtn').addEventListener('click', () => { pb.authStore.clear(); render() })
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderLogin() {
|
||||||
|
app.innerHTML = `
|
||||||
|
<div class="min-h-screen bg-slate-950 text-slate-100 flex items-center justify-center p-4">
|
||||||
|
<div class="bg-slate-900 border border-slate-800 p-8 rounded-2xl shadow-2xl w-full max-w-md">
|
||||||
|
<h1 class="text-2xl font-bold text-center mb-6">Giriş Yap</h1>
|
||||||
|
<form id="loginForm" class="space-y-4">
|
||||||
|
<input type="text" id="identity" placeholder="E-posta" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white" />
|
||||||
|
<input type="password" id="password" placeholder="Şifre" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white" />
|
||||||
|
<button type="submit" class="w-full bg-indigo-600 py-2 rounded-xl text-white font-medium">Giriş</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
try {
|
||||||
|
await pb.collection('users').authWithPassword(
|
||||||
|
document.getElementById('identity').value,
|
||||||
|
document.getElementById('password').value
|
||||||
|
)
|
||||||
|
render()
|
||||||
|
} catch {
|
||||||
|
alert('Giriş başarısız!')
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
render()
|
render()
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export function renderDesktop() {
|
||||||
|
const html = `
|
||||||
|
<div class="bg-slate-900/40 backdrop-blur-2xl border border-white/10 p-8 rounded-3xl shadow-2xl max-w-lg w-full text-center space-y-4">
|
||||||
|
<div class="inline-flex p-3 bg-indigo-500/20 border border-indigo-500/30 rounded-2xl text-indigo-300 text-3xl">
|
||||||
|
✨
|
||||||
|
</div>
|
||||||
|
<h2 class="text-3xl font-bold text-white">Masaüstü</h2>
|
||||||
|
<p class="text-slate-300 text-sm leading-relaxed">
|
||||||
|
Modüler mimariye geçtik! Arka planı değiştirmek için sol menüdeki <b>Ayarlar</b> sekmesine geçebilirsin.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
return { html, initEvents: () => {} }
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
export async function renderSettings(pb, currentBg, onBgSelect) {
|
||||||
|
let bgList = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const records = await pb.collection('backgrounds').getFullList()
|
||||||
|
bgList = records.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
title: item.title || 'Duvar Kağıdı',
|
||||||
|
url: `https://pocketbase.iontalp.com/api/files/${item.collectionId}/${item.id}/${item.image || item.file}`
|
||||||
|
}))
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Görseller yüklenemedi:', err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = `
|
||||||
|
<div class="bg-slate-900/60 backdrop-blur-2xl border border-white/10 p-8 rounded-3xl shadow-2xl max-w-4xl w-full h-[80vh] flex flex-col">
|
||||||
|
<h2 class="text-2xl font-bold text-white mb-2">⚙️ Sistem Ayarları</h2>
|
||||||
|
<p class="text-slate-400 text-sm mb-6">PocketBase sunucundaki duvar kağıtlarından birini seçerek arka planı özelleştir.</p>
|
||||||
|
|
||||||
|
<div class="flex-1 overflow-y-auto pr-2">
|
||||||
|
<h3 class="text-sm font-semibold text-slate-300 mb-4">Arka Plan Galerisi (${bgList.length})</h3>
|
||||||
|
|
||||||
|
${bgList.length === 0 ? `
|
||||||
|
<div class="text-center py-12 border border-dashed border-white/10 rounded-2xl text-slate-500">
|
||||||
|
PocketBase 'backgrounds' koleksiyonunda henüz görsel bulunamadı.
|
||||||
|
</div>
|
||||||
|
` : `
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||||
|
${bgList.map(bg => `
|
||||||
|
<div data-url="${bg.url}" class="bg-card group relative h-40 rounded-2xl overflow-hidden border-2 cursor-pointer transition-all duration-300 hover:scale-[1.02] ${currentBg === bg.url ? 'border-indigo-500 ring-4 ring-indigo-500/20' : 'border-white/10 hover:border-white/30'}">
|
||||||
|
<img src="${bg.url}" alt="${bg.title}" class="w-full h-full object-cover" />
|
||||||
|
<div class="absolute inset-0 bg-gradient-to-t from-slate-950/80 via-transparent to-transparent opacity-80 group-hover:opacity-100 transition-opacity flex items-end p-3">
|
||||||
|
<span class="text-xs font-medium text-white truncate">${bg.title}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
return {
|
||||||
|
html,
|
||||||
|
initEvents: (container) => {
|
||||||
|
container.querySelectorAll('.bg-card').forEach(card => {
|
||||||
|
card.addEventListener('click', () => {
|
||||||
|
const selectedUrl = card.getAttribute('data-url')
|
||||||
|
onBgSelect(selectedUrl)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user