LikeandCommentSave
This commit is contained in:
20
index.html
20
index.html
@@ -108,7 +108,7 @@
|
||||
<!-- Feed Section -->
|
||||
<section class="feed-container">
|
||||
<!-- Post Card -->
|
||||
<article class="post-card">
|
||||
<article class="post-card" data-post-id="1">
|
||||
<div class="post-header">
|
||||
<div class="post-user">
|
||||
<img src="https://i.pravatar.cc/150?img=1" alt="User" class="avatar-sm">
|
||||
@@ -142,10 +142,18 @@
|
||||
<span class="likes">124 likes</span>
|
||||
<p><span class="username">sarah_j</span> Exploring the Cinque Terre! 🇮🇹✨</p>
|
||||
</div>
|
||||
<!-- Comment Section -->
|
||||
<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>
|
||||
</article>
|
||||
|
||||
<!-- Post Card 2 -->
|
||||
<article class="post-card">
|
||||
<article class="post-card" data-post-id="2">
|
||||
<div class="post-header">
|
||||
<div class="post-user">
|
||||
<img src="https://i.pravatar.cc/150?img=2" alt="User" class="avatar-sm">
|
||||
@@ -179,6 +187,14 @@
|
||||
<span class="likes">892 likes</span>
|
||||
<p><span class="username">mike_photo</span> Golden hour in the mountains 🏔️</p>
|
||||
</div>
|
||||
<!-- Comment Section -->
|
||||
<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>
|
||||
</article>
|
||||
|
||||
<!-- Spacer for bottom nav -->
|
||||
|
||||
168
script.js
168
script.js
@@ -96,6 +96,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
void feedView.offsetWidth;
|
||||
feedView.classList.add('fade-in');
|
||||
|
||||
// Load persisted state for posts
|
||||
loadPostState();
|
||||
|
||||
// Remove fade-in class after animation to fix fixed positioning context
|
||||
setTimeout(() => {
|
||||
feedView.classList.remove('fade-in');
|
||||
@@ -159,4 +162,169 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- PERSISTENCE LOGIC ---
|
||||
function getPostState() {
|
||||
return JSON.parse(localStorage.getItem('socialAppPostState') || '{}');
|
||||
}
|
||||
|
||||
function savePostState(state) {
|
||||
localStorage.setItem('socialAppPostState', JSON.stringify(state));
|
||||
}
|
||||
|
||||
function loadPostState() {
|
||||
const state = getPostState();
|
||||
const posts = document.querySelectorAll('.post-card');
|
||||
|
||||
posts.forEach(card => {
|
||||
const id = card.getAttribute('data-post-id');
|
||||
if (id && state[id]) {
|
||||
const data = state[id];
|
||||
|
||||
// Restore Likes
|
||||
const likeIcon = card.querySelector('.heart-icon');
|
||||
const likesText = card.querySelector('.likes');
|
||||
|
||||
if (data.liked) {
|
||||
likeIcon.classList.add('liked');
|
||||
likeIcon.style.fill = '#EF4444';
|
||||
likeIcon.style.stroke = '#EF4444';
|
||||
} else {
|
||||
likeIcon.classList.remove('liked');
|
||||
likeIcon.style.fill = 'none';
|
||||
likeIcon.style.stroke = 'white';
|
||||
}
|
||||
likesText.innerText = data.likesCount + ' likes';
|
||||
|
||||
// Restore Comments
|
||||
const commentsContainer = card.querySelector('.added-comments');
|
||||
commentsContainer.innerHTML = ''; // Clear existing to prevent dupes on re-run
|
||||
if (data.comments && data.comments.length > 0) {
|
||||
data.comments.forEach(text => {
|
||||
const commentEl = document.createElement('div');
|
||||
commentEl.classList.add('comment-item');
|
||||
commentEl.innerHTML = `<span class="comment-user">you</span> ${text}`;
|
||||
commentsContainer.appendChild(commentEl);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- FEED INTERACTIONS ---
|
||||
if (feedView) {
|
||||
feedView.addEventListener('click', (e) => {
|
||||
const target = e.target;
|
||||
|
||||
// 1. LIKE ACTION
|
||||
const likeBtn = target.closest('.heart-icon')?.closest('.icon-btn');
|
||||
if (likeBtn) {
|
||||
const icon = likeBtn.querySelector('.heart-icon');
|
||||
const postCard = likeBtn.closest('.post-card');
|
||||
const likesText = postCard.querySelector('.likes');
|
||||
const postId = postCard.getAttribute('data-post-id');
|
||||
|
||||
// Toggle State
|
||||
icon.classList.toggle('liked');
|
||||
|
||||
// Update Count (Simple parsing)
|
||||
let count = parseInt(likesText.innerText);
|
||||
let isLiked = false;
|
||||
|
||||
if (icon.classList.contains('liked')) {
|
||||
icon.style.fill = '#EF4444';
|
||||
icon.style.stroke = '#EF4444';
|
||||
count++;
|
||||
isLiked = true;
|
||||
} else {
|
||||
icon.style.fill = 'none';
|
||||
icon.style.stroke = 'white';
|
||||
count--;
|
||||
isLiked = false;
|
||||
}
|
||||
likesText.innerText = count + ' likes';
|
||||
|
||||
// Save State
|
||||
if (postId) {
|
||||
const state = getPostState();
|
||||
if (!state[postId]) state[postId] = { comments: [] };
|
||||
state[postId].liked = isLiked;
|
||||
state[postId].likesCount = count;
|
||||
// Preserve existing comments if we didn't just load them
|
||||
if (!state[postId].comments) state[postId].comments = [];
|
||||
savePostState(state);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. COMMENT TOGGLE ACTION
|
||||
const commentBtn = target.closest('.icon-btn');
|
||||
if (commentBtn && !commentBtn.querySelector('.heart-icon')) {
|
||||
// Check if it's the comment button (has specific path)
|
||||
const path = commentBtn.querySelector('path');
|
||||
if (path && (path.getAttribute('d').startsWith('M21 11.5') || path.closest('svg')?.innerHTML.includes('M21 11.5'))) {
|
||||
const postCard = commentBtn.closest('.post-card');
|
||||
const commentSection = postCard.querySelector('.comment-section');
|
||||
commentSection.classList.toggle('active');
|
||||
if (commentSection.classList.contains('active')) {
|
||||
commentSection.querySelector('input').focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. POST COMMENT ACTION
|
||||
if (target.classList.contains('post-btn')) {
|
||||
const wrapper = target.closest('.comment-input-wrapper');
|
||||
const input = wrapper.querySelector('.comment-input');
|
||||
const text = input.value.trim();
|
||||
const postCard = wrapper.closest('.post-card');
|
||||
const postId = postCard.getAttribute('data-post-id');
|
||||
|
||||
if (text) {
|
||||
addComment(wrapper.closest('.comment-section'), text);
|
||||
|
||||
if (postId) {
|
||||
const state = getPostState();
|
||||
if (!state[postId]) state[postId] = { liked: false, likesCount: parseInt(postCard.querySelector('.likes').innerText) || 0, comments: [] };
|
||||
if (!state[postId].comments) state[postId].comments = [];
|
||||
state[postId].comments.push(text);
|
||||
savePostState(state);
|
||||
}
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Enter key for comments
|
||||
feedView.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter' && e.target.classList.contains('comment-input')) {
|
||||
const text = e.target.value.trim();
|
||||
const wrapper = e.target.closest('.comment-input-wrapper');
|
||||
const postCard = wrapper.closest('.post-card');
|
||||
const postId = postCard.getAttribute('data-post-id');
|
||||
|
||||
if (text) {
|
||||
addComment(e.target.closest('.comment-section'), text);
|
||||
|
||||
if (postId) {
|
||||
const state = getPostState();
|
||||
if (!state[postId]) state[postId] = { liked: false, likesCount: parseInt(postCard.querySelector('.likes').innerText) || 0, comments: [] };
|
||||
if (!state[postId].comments) state[postId].comments = [];
|
||||
state[postId].comments.push(text);
|
||||
savePostState(state);
|
||||
}
|
||||
e.target.value = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addComment(section, text) {
|
||||
const container = section.querySelector('.added-comments');
|
||||
const commentEl = document.createElement('div');
|
||||
commentEl.classList.add('comment-item');
|
||||
commentEl.innerHTML = `<span class="comment-user">you</span> ${text}`;
|
||||
container.appendChild(commentEl);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -518,6 +518,88 @@ p {
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
/* Feed Interactions */
|
||||
.icon-btn .heart-icon.liked {
|
||||
fill: #EF4444;
|
||||
stroke: #EF4444;
|
||||
animation: likeBounce 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
|
||||
@keyframes likeBounce {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Comment Section */
|
||||
.comment-section {
|
||||
padding: 0 15px 15px;
|
||||
display: none;
|
||||
/* Hidden by default */
|
||||
}
|
||||
|
||||
.comment-section.active {
|
||||
display: block;
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
.comment-input-wrapper {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.comment-input {
|
||||
flex: 1;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: var(--radius-full);
|
||||
padding: 8px 15px;
|
||||
color: var(--text-main);
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.comment-input:focus {
|
||||
border-color: var(--text-muted);
|
||||
}
|
||||
|
||||
.post-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #3B82F6;
|
||||
/* Blue accent */
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.added-comments {
|
||||
margin-top: 10px;
|
||||
font-size: 13px;
|
||||
color: var(--text-main);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.comment-item {
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.comment-user {
|
||||
font-weight: 600;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Bottom Navigation */
|
||||
.bottom-nav {
|
||||
position: fixed;
|
||||
|
||||
Reference in New Issue
Block a user