This commit is contained in:
2026-01-28 21:06:16 +11:00
parent 109e463724
commit a7669d9014
3 changed files with 303 additions and 0 deletions

189
script.js
View File

@@ -327,4 +327,193 @@ document.addEventListener('DOMContentLoaded', () => {
commentEl.innerHTML = `<span class="comment-user">you</span> ${text}`;
container.appendChild(commentEl);
}
// --- CREATE POST LOGIC ---
const createPostView = document.getElementById('create-post-view');
const cancelPostBtn = document.getElementById('cancel-post-btn');
const sharePostBtn = document.getElementById('share-post-btn');
const uploadTrigger = document.getElementById('upload-trigger');
const imageInput = document.getElementById('post-image-input');
const imagePreview = document.getElementById('image-preview');
const captionInput = document.getElementById('post-caption-input');
const navPostBtn = document.querySelector('.nav-btn:nth-child(2)'); // Center Post Button
const navHomeBtn = document.querySelector('.nav-btn:first-child');
// 1. Navigation
if (navPostBtn) {
navPostBtn.addEventListener('click', () => {
feedView.classList.add('hidden');
createPostView.classList.remove('hidden');
createPostView.classList.add('fade-in');
});
}
if (cancelPostBtn) {
cancelPostBtn.addEventListener('click', () => {
resetPostForm();
createPostView.classList.add('hidden');
feedView.classList.remove('hidden');
});
}
if (navHomeBtn && feedView.classList.contains('hidden') && !createPostView.classList.contains('hidden')) {
// Logic handled by cancel mostly, but good to have explicit nav
navHomeBtn.addEventListener('click', () => {
if (!createPostView.classList.contains('hidden')) {
resetPostForm();
createPostView.classList.add('hidden');
feedView.classList.remove('hidden');
}
});
}
// 2. Image Selection
if (uploadTrigger) {
uploadTrigger.addEventListener('click', () => imageInput.click());
}
if (imageInput) {
imageInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
imagePreview.classList.remove('hidden');
document.querySelector('.upload-placeholder').classList.add('hidden');
};
reader.readAsDataURL(file);
}
});
}
// 3. Share Post
if (sharePostBtn) {
sharePostBtn.addEventListener('click', () => {
if (!imagePreview.src || imagePreview.classList.contains('hidden')) {
alert('Please select an image first.');
return;
}
const caption = captionInput.value.trim();
const imageSrc = imagePreview.src;
const id = 'post_' + Date.now();
const newPost = {
id,
imageSrc,
caption,
timestamp: new Date().toISOString(),
username: 'you', // Mock user
likes: 0
};
// Save to LocalStorage
const userPosts = JSON.parse(localStorage.getItem('socialAppUserPosts') || '[]');
userPosts.unshift(newPost); // Add to top
localStorage.setItem('socialAppUserPosts', JSON.stringify(userPosts));
// Render to Feed
renderPost(newPost, true); // true = prepend
// Reset and Go Back
resetPostForm();
createPostView.classList.add('hidden');
feedView.classList.remove('hidden');
// Re-bind listeners isn't needed strictly due to delegation, but state refresh might be
loadPostState();
});
}
function resetPostForm() {
imageInput.value = '';
captionInput.value = '';
imagePreview.src = '';
imagePreview.classList.add('hidden');
document.querySelector('.upload-placeholder').classList.remove('hidden');
}
function renderPost(post, prepend = false) {
const feedContainer = document.querySelector('.feed-container');
const article = document.createElement('article');
article.className = 'post-card';
article.setAttribute('data-post-id', post.id);
article.innerHTML = `
<div class="post-header">
<div class="post-user">
<img src="https://i.pravatar.cc/150?img=12" alt="User" class="avatar-sm">
<span class="username">${post.username}</span>
</div>
<button class="icon-btn-sm">...</button>
</div>
<div class="post-image">
<img src="${post.imageSrc}" alt="Post">
</div>
<div class="post-actions">
<div class="action-left">
<button class="icon-btn"><svg viewBox="0 0 24 24" width="24" height="24" stroke="white" fill="none" class="heart-icon"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg></button>
<button class="icon-btn"><svg viewBox="0 0 24 24" width="24" height="24" stroke="white" fill="none"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg></button>
</div>
<button class="icon-btn"><svg viewBox="0 0 24 24" width="24" height="24" stroke="white" fill="none"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path></svg></button>
</div>
<div class="post-content">
<span class="likes">0 likes</span>
<p><span class="username">${post.username}</span> ${post.caption}</p>
</div>
<div class="comment-section">
<div class="added-comments"></div>
<div class="comment-input-wrapper">
<input type="text" class="comment-input" placeholder="Add a comment...">
<button class="post-btn">Post</button>
</div>
</div>
`;
// This is a bit tricky with existing static posts.
// Ideally we keep static posts static and just inject dynamic ones.
if (prepend) {
feedContainer.insertBefore(article, feedContainer.firstChild);
// Note: index.html has static articles directly. `firstChild` might be text node or first article.
// A safer insert would be after the first spacer if I had one, or simply `prepend`.
// Let's use `prepend` on the container, but strict ordering might be weird with existing static HTML.
// Actually, `prepend` puts it before the first child, which IS the first post card. Perfect.
} else {
feedContainer.appendChild(article);
}
}
// Load User Posts on Init
const savedUserPosts = JSON.parse(localStorage.getItem('socialAppUserPosts') || '[]');
savedUserPosts.forEach(post => {
// Check if already in DOM to avoid dupes (simple check)
if (!document.querySelector(`[data-post-id="${post.id}"]`)) {
renderPost(post, true); // Keep order inverted?
// If we loop saved posts [newest, ..., oldest], we should Append?
// Actually saved as [newest, oldest].
// If we prepend one by one:
// 1. Newest -> Prepend -> Top.
// 2. Oldest -> Prepend -> Top (Wrong).
// So we should iterate in reverse if we prepend, OR just append at top once properly sorted.
// Let's keep it simple: Iterate in reverse order [oldest ... newest] and prepend each, so newest ends up on top.
}
});
// Fix order: Reverse iteration for prepend logic
// savedUserPosts.reverse().forEach(...) -> Wait, `unshift` adds to start. So [0] is newest.
// Loop:
// Post 0 (Newest) -> Prepend (become first).
// Post 1 (Older) -> Prepend (become first).
// Result: Post 1 is above Post 0. WRONG.
// Correct: Iterate from last to first (reverse) and prepend.
// Post Last (Oldest) -> Prepend.
// ...
// Post 0 (Newest) -> Prepend (Top). CORRECT.
// So:
[...savedUserPosts].reverse().forEach(post => {
if (!document.querySelector(`[data-post-id="${post.id}"]`)) {
renderPost(post, true);
}
});
});