Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions app/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -411,5 +411,107 @@ <h1 class="gh-name"><a href="{{url}}" target="_blank" rel="noopener noreferrer">
</div>
{% endif %}
</main>
<script>
(function() {
var LIKE_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000;
var SWEEP_INTERVAL_MS = 24 * 60 * 60 * 1000;

try {
var now = Date.now();
var lastSweep = parseInt(localStorage.getItem('sw_like_sweep'), 10) || 0;
if (now - lastSweep > SWEEP_INTERVAL_MS) {
for (var i = localStorage.length - 1; i >= 0; i--) {
var key = localStorage.key(i);
if (key && key.indexOf('sw_like_') === 0 && key !== 'sw_like_sweep') {
var ts = parseInt(localStorage.getItem(key), 10);
if (!ts || now - ts > LIKE_EXPIRY_MS) localStorage.removeItem(key);
}
}
localStorage.setItem('sw_like_sweep', now.toString());
}
} catch(e) {}

function likeKey(url, emoji) {
var hash = 0;
for (var i = 0; i < url.length; i++) {
hash = ((hash << 5) - hash + url.charCodeAt(i)) | 0;
}
return 'sw_like_' + hash + '_' + emoji;
}

function hasLiked(url, emoji) {
try {
var val = localStorage.getItem(likeKey(url, emoji));
if (!val) return false;
if (Date.now() - parseInt(val, 10) > LIKE_EXPIRY_MS) {
localStorage.removeItem(likeKey(url, emoji));
return false;
}
return true;
} catch(e) { return false; }
}

function markLiked(url, emoji) {
try { localStorage.setItem(likeKey(url, emoji), Date.now().toString()); }
catch(e) {}
}

document.querySelectorAll('.emoji-form').forEach(function(form) {
var urlInput = form.querySelector('input[name="url"]');
var emojiInput = form.querySelector('input[name="emoji"]');
if (!urlInput || !emojiInput) return;

var url = urlInput.value;
var emoji = emojiInput.value;
var btn = form.querySelector('button[type="submit"]');

if (hasLiked(url, emoji)) {
btn.classList.add('already-liked');
btn.style.opacity = '0.5';
btn.style.pointerEvents = 'none';
btn.title = 'Already liked';
}

form.addEventListener('submit', function(e) {
e.preventDefault();
if (hasLiked(url, emoji)) return;

btn.style.pointerEvents = 'none';

fetch('{{ prefix }}api/like', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: url, emoji: emoji })
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (!data.ok) return;
markLiked(url, emoji);
btn.classList.add('already-liked');
btn.style.opacity = '0.5';
btn.style.pointerEvents = 'none';
btn.title = 'Already liked';

if (emoji === '\uD83D\uDC4D') {
var span = btn.querySelector('span');
if (span) {
span.textContent = data.reaction_count;
} else {
var s = document.createElement('span');
s.textContent = data.reaction_count;
btn.appendChild(s);
}
} else {
var spans = btn.querySelectorAll('span');
if (spans.length >= 2) spans[1].textContent = data.reaction_count;
}
})
.catch(function() {
btn.style.pointerEvents = '';
});
});
});
})();
</script>
</body>
</html>