Nothing works please make everything work and everything only be fro the database with a modern nice ui
f58c9d4 verified | // Initialize Supabase | |
| const supabase = createClient( | |
| 'https://iiwthrqlshgmzvgudpkt.supabase.co', | |
| 'sb_publishable_slaECC8UMtgUni2caodaZA_N-uidsoa' | |
| ); | |
| // DOM Elements | |
| const scriptsContainer = document.getElementById('scripts-container'); | |
| const contributorsContainer = document.getElementById('contributors-container'); | |
| const newestBtn = document.getElementById('newest-btn'); | |
| const popularBtn = document.getElementById('popular-btn'); | |
| const trendingBtn = document.getElementById('trending-btn'); | |
| const loadMoreBtn = document.getElementById('load-more'); | |
| // State | |
| let currentSort = 'newest'; | |
| let currentPage = 1; | |
| let isLoading = false; | |
| // Format date | |
| function formatDate(dateString) { | |
| const date = new Date(dateString); | |
| return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }); | |
| } | |
| // Render scripts | |
| async function renderScripts(sortBy = 'newest', page = 1) { | |
| try { | |
| isLoading = true; | |
| scriptsContainer.innerHTML = ` | |
| <div class="col-span-3 text-center py-12"> | |
| <div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-indigo-500 mx-auto mb-4"></div> | |
| <p>Loading scripts...</p> | |
| </div> | |
| `; | |
| const scripts = await fetchScripts(sortBy, page); | |
| if (scripts.error) throw scripts.error; | |
| if (scripts.length === 0) { | |
| scriptsContainer.innerHTML = ` | |
| <div class="col-span-3 text-center py-12"> | |
| <i data-feather="alert-circle" class="w-12 h-12 text-indigo-500 mx-auto mb-4"></i> | |
| <p class="text-xl">No scripts found</p> | |
| <p class="text-gray-400 mt-2">Be the first to upload a script!</p> | |
| </div> | |
| `; | |
| feather.replace(); | |
| return; | |
| } | |
| let html = ''; | |
| scripts.forEach(script => { | |
| html += ` | |
| <div class="bg-gray-800 rounded-xl p-6 hover:shadow-lg transition"> | |
| <div class="flex items-center space-x-3 mb-4"> | |
| <div class="w-10 h-10 rounded-full bg-indigo-500 flex items-center justify-center"> | |
| <i data-feather="user" class="text-white"></i> | |
| </div> | |
| <span class="font-medium">${script.username || 'Anonymous'}</span> | |
| </div> | |
| <h3 class="text-xl font-bold mb-2">${script.title}</h3> | |
| <p class="text-gray-400 mb-4">${script.description || 'No description provided'}</p> | |
| <div class="flex justify-between text-sm text-gray-500"> | |
| <span><i data-feather="eye" class="inline mr-1"></i> ${script.view_count || 0}</span> | |
| <span><i data-feather="heart" class="inline mr-1"></i> ${script.like_count || 0}</span> | |
| <span><i data-feather="calendar" class="inline mr-1"></i> ${formatDate(script.created_at)}</span> | |
| </div> | |
| </div> | |
| `; | |
| }); | |
| scriptsContainer.innerHTML = html; | |
| feather.replace(); | |
| loadMoreBtn.classList.toggle('hidden', scripts.length < 10); | |
| } catch (error) { | |
| console.error('Render error:', error); | |
| scriptsContainer.innerHTML = ` | |
| <div class="col-span-3 text-center py-12"> | |
| <i data-feather="alert-triangle" class="w-12 h-12 text-red-500 mx-auto mb-4"></i> | |
| <p class="text-xl">Error loading scripts</p> | |
| <p class="text-gray-400 mt-2">${error.message}</p> | |
| </div> | |
| `; | |
| feather.replace(); | |
| } finally { | |
| isLoading = false; | |
| } | |
| } | |
| // Render contributors | |
| async function renderContributors() { | |
| try { | |
| contributorsContainer.innerHTML = ` | |
| <div class="col-span-6 text-center py-8"> | |
| <div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-indigo-500 mx-auto mb-4"></div> | |
| <p>Loading contributors...</p> | |
| </div> | |
| `; | |
| const { data: contributors, error } = await supabase | |
| .from('profiles') | |
| .select('username, avatar_url, script_count') | |
| .order('script_count', { ascending: false }) | |
| .limit(6); | |
| if (error) throw error; | |
| let html = ''; | |
| contributors.forEach(contributor => { | |
| html += ` | |
| <div class="bg-gray-800 rounded-lg p-4 text-center"> | |
| <div class="w-16 h-16 rounded-full bg-indigo-500 mx-auto mb-3 flex items-center justify-center overflow-hidden"> | |
| ${contributor.avatar_url ? | |
| `<img src="${contributor.avatar_url}" alt="${contributor.username}" class="w-full h-full object-cover">` : | |
| `<i data-feather="user" class="text-white text-2xl"></i>`} | |
| </div> | |
| <h4 class="font-medium">${contributor.username}</h4> | |
| <p class="text-sm text-gray-400">${contributor.script_count || 0} scripts</p> | |
| </div> | |
| `; | |
| }); | |
| contributorsContainer.innerHTML = html; | |
| feather.replace(); | |
| } catch (error) { | |
| console.error('Contributors error:', error); | |
| contributorsContainer.innerHTML = ` | |
| <div class="col-span-6 text-center py-8"> | |
| <i data-feather="alert-triangle" class="w-12 h-12 text-red-500 mx-auto mb-4"></i> | |
| <p>Error loading contributors</p> | |
| </div> | |
| `; | |
| feather.replace(); | |
| } | |
| } | |
| // Event Listeners | |
| newestBtn.addEventListener('click', () => { | |
| if (currentSort === 'newest' || isLoading) return; | |
| currentSort = 'newest'; | |
| currentPage = 1; | |
| newestBtn.classList.replace('bg-gray-700', 'bg-indigo-600'); | |
| popularBtn.classList.replace('bg-indigo-600', 'bg-gray-700'); | |
| trendingBtn.classList.replace('bg-indigo-600', 'bg-gray-700'); | |
| renderScripts('newest', 1); | |
| }); | |
| popularBtn.addEventListener('click', () => { | |
| if (currentSort === 'most_liked' || isLoading) return; | |
| currentSort = 'most_liked'; | |
| currentPage = 1; | |
| newestBtn.classList.replace('bg-indigo-600', 'bg-gray-700'); | |
| popularBtn.classList.replace('bg-gray-700', 'bg-indigo-600'); | |
| trendingBtn.classList.replace('bg-indigo-600', 'bg-gray-700'); | |
| renderScripts('most_liked', 1); | |
| }); | |
| trendingBtn.addEventListener('click', () => { | |
| if (currentSort === 'trending' || isLoading) return; | |
| currentSort = 'trending'; | |
| currentPage = 1; | |
| newestBtn.classList.replace('bg-indigo-600', 'bg-gray-700'); | |
| popularBtn.classList.replace('bg-indigo-600', 'bg-gray-700'); | |
| trendingBtn.classList.replace('bg-gray-700', 'bg-indigo-600'); | |
| renderScripts('trending', 1); | |
| }); | |
| loadMoreBtn.addEventListener('click', () => { | |
| if (isLoading) return; | |
| currentPage++; | |
| renderScripts(currentSort, currentPage); | |
| }); | |
| // Initialize | |
| document.addEventListener('DOMContentLoaded', () => { | |
| renderScripts(); | |
| renderContributors(); | |
| feather.replace(); | |
| // Auth state listener | |
| supabase.auth.onAuthStateChange((event, session) => { | |
| if (event === 'SIGNED_IN') { | |
| console.log('User signed in:', session.user); | |
| // Update UI for logged in state | |
| } else if (event === 'SIGNED_OUT') { | |
| console.log('User signed out'); | |
| // Update UI for logged out state | |
| } | |
| }); | |
| }); | |
| // Auth functions | |
| async function handleSignUp(email, password) { | |
| try { | |
| const { data, error } = await supabase.auth.signUp({ | |
| email, | |
| password, | |
| }); | |
| if (error) throw error; | |
| return data; | |
| } catch (error) { | |
| console.error('Sign up error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| async function handleSignIn(email, password) { | |
| try { | |
| const { data, error } = await supabase.auth.signInWithPassword({ | |
| email, | |
| password, | |
| }); | |
| if (error) throw error; | |
| return data; | |
| } catch (error) { | |
| console.error('Sign in error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| async function handleSignOut() { | |
| try { | |
| const { error } = await supabase.auth.signOut(); | |
| if (error) throw error; | |
| return { success: true }; | |
| } catch (error) { | |
| console.error('Sign out error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| // Script functions | |
| async function fetchScripts(sortBy = 'newest', page = 1, searchQuery = '') { | |
| try { | |
| let query = supabase | |
| .from('scripts') | |
| .select('*') | |
| .eq('visibility', 'public') | |
| .order('created_at', { ascending: sortBy === 'newest' ? false : true }); | |
| if (searchQuery) { | |
| query = query.or(`title.ilike.%${searchQuery}%,description.ilike.%${searchQuery}%`); | |
| } | |
| if (sortBy === 'most_liked') { | |
| query = query.order('like_count', { ascending: false }); | |
| } else if (sortBy === 'trending') { | |
| // Trending could be a combination of views and likes over time | |
| query = query.order('view_count', { ascending: false }); | |
| } | |
| const { data, error } = await query.range((page - 1) * 10, page * 10 - 1); | |
| if (error) throw error; | |
| return data; | |
| } catch (error) { | |
| console.error('Fetch scripts error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| async function fetchScriptById(id) { | |
| try { | |
| // Increment view count | |
| await supabase.rpc('increment_script_views', { script_id: id }); | |
| const { data, error } = await supabase | |
| .from('scripts') | |
| .select('*, script_versions(*), profiles(username, avatar_url)') | |
| .eq('id', id) | |
| .single(); | |
| if (error) throw error; | |
| return data; | |
| } catch (error) { | |
| console.error('Fetch script error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| // Comment functions | |
| async function fetchComments(scriptId) { | |
| try { | |
| const { data, error } = await supabase | |
| .from('comments_safe') | |
| .select('*') | |
| .eq('script_id', scriptId) | |
| .order('created_at', { ascending: true }); | |
| if (error) throw error; | |
| return data; | |
| } catch (error) { | |
| console.error('Fetch comments error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| async function postComment(scriptId, content, parentId = null) { | |
| try { | |
| const { data: { user } } = await supabase.auth.getUser(); | |
| if (!user) throw new Error('Not authenticated'); | |
| const { data, error } = await supabase | |
| .from('comments') | |
| .insert({ | |
| script_id: scriptId, | |
| user_id: user.id, | |
| content, | |
| parent_id: parentId | |
| }) | |
| .select() | |
| .single(); | |
| if (error) throw error; | |
| return data; | |
| } catch (error) { | |
| console.error('Post comment error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| // Like functions | |
| async function toggleLike(scriptId) { | |
| try { | |
| const { data: { user } } = await supabase.auth.getUser(); | |
| if (!user) throw new Error('Not authenticated'); | |
| // Check if already liked | |
| const { data: existingLike, error: likeError } = await supabase | |
| .from('likes') | |
| .select('id') | |
| .eq('script_id', scriptId) | |
| .eq('user_id', user.id) | |
| .maybeSingle(); | |
| if (likeError) throw likeError; | |
| if (existingLike) { | |
| // Unlike | |
| const { error } = await supabase | |
| .from('likes') | |
| .delete() | |
| .eq('id', existingLike.id); | |
| if (error) throw error; | |
| return { action: 'unliked' }; | |
| } else { | |
| // Like | |
| const { error } = await supabase | |
| .from('likes') | |
| .insert({ | |
| script_id: scriptId, | |
| user_id: user.id | |
| }); | |
| if (error) throw error; | |
| return { action: 'liked' }; | |
| } | |
| } catch (error) { | |
| console.error('Toggle like error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| // Report functions | |
| async function submitReport(scriptId, reason) { | |
| try { | |
| const { data: { user } } = await supabase.auth.getUser(); | |
| if (!user) throw new Error('Not authenticated'); | |
| const { data, error } = await supabase | |
| .from('reports') | |
| .insert({ | |
| script_id: scriptId, | |
| reporter_id: user.id, | |
| reason | |
| }) | |
| .select() | |
| .single(); | |
| if (error) throw error; | |
| return data; | |
| } catch (error) { | |
| console.error('Submit report error:', error.message); | |
| return { error }; | |
| } | |
| } | |
| // Initialize event listeners when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Check auth state | |
| supabase.auth.onAuthStateChange((event, session) => { | |
| if (event === 'SIGNED_IN') { | |
| console.log('User signed in:', session.user); | |
| // Update UI to show logged in state | |
| } else if (event === 'SIGNED_OUT') { | |
| console.log('User signed out'); | |
| // Update UI to show logged out state | |
| } | |
| }); | |
| }); |