// 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 = `
No scripts found
Be the first to upload a script!
`;
feather.replace();
return;
}
let html = '';
scripts.forEach(script => {
html += `
${script.username || 'Anonymous'}
${script.title}
${script.description || 'No description provided'}
${script.view_count || 0}
${script.like_count || 0}
${formatDate(script.created_at)}
`;
});
scriptsContainer.innerHTML = html;
feather.replace();
loadMoreBtn.classList.toggle('hidden', scripts.length < 10);
} catch (error) {
console.error('Render error:', error);
scriptsContainer.innerHTML = `
${contributor.avatar_url ?
`

` :
`
`}
${contributor.username}
${contributor.script_count || 0} scripts
`;
});
contributorsContainer.innerHTML = html;
feather.replace();
} catch (error) {
console.error('Contributors error:', error);
contributorsContainer.innerHTML = `
Error loading contributors
`;
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
}
});
});