Compare commits
No commits in common. "caf9123cc508e6fe7ab40231f0960bc0163b02a8" and "53e22c84651d9ff57ed89c0515eacac32cc56aea" have entirely different histories.
caf9123cc5
...
53e22c8465
|
@ -337,10 +337,6 @@ async def on_message(message: discord.Message) -> None:
|
||||||
if not (is_dm or is_mention):
|
if not (is_dm or is_mention):
|
||||||
return
|
return
|
||||||
|
|
||||||
if is_dm and message.author.id != 199680010267656192:
|
|
||||||
await message.channel.send("Only authorized users are allowed to use this bot.")
|
|
||||||
return
|
|
||||||
|
|
||||||
url = extract_first_url(message.content)
|
url = extract_first_url(message.content)
|
||||||
if not url:
|
if not url:
|
||||||
await message.channel.send("Please send me a link to a news article.")
|
await message.channel.send("Please send me a link to a news article.")
|
||||||
|
|
|
@ -100,13 +100,7 @@
|
||||||
max-width:900px;
|
max-width:900px;
|
||||||
margin:0 auto;
|
margin:0 auto;
|
||||||
}
|
}
|
||||||
/* make each paragraph a little flex-box so we can place
|
|
||||||
the coloured badge on the right-hand side */
|
|
||||||
.paragraph-card{
|
.paragraph-card{
|
||||||
display:flex;
|
|
||||||
justify-content:space-between;
|
|
||||||
align-items:flex-start;
|
|
||||||
gap:.75rem;
|
|
||||||
background:var(--card-bg);
|
background:var(--card-bg);
|
||||||
border-radius:6px;
|
border-radius:6px;
|
||||||
padding:1rem 1.2rem;
|
padding:1rem 1.2rem;
|
||||||
|
@ -116,63 +110,12 @@
|
||||||
.paragraph-card:hover{
|
.paragraph-card:hover{
|
||||||
box-shadow:0 3px 8px rgba(0,0,0,.14);
|
box-shadow:0 3px 8px rgba(0,0,0,.14);
|
||||||
}
|
}
|
||||||
.paragraph-card--active{
|
|
||||||
outline:3px solid #1565c0; /* blue focus ring */
|
|
||||||
outline-offset:2px;
|
|
||||||
box-shadow:0 0 6px rgba(21,101,192,.35); /* soft glow */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─────────── Relevance badge ─────────── */
|
|
||||||
.relevance-badge{
|
|
||||||
min-width:72px;
|
|
||||||
font-size:.75rem;
|
|
||||||
font-weight:600;
|
|
||||||
line-height:1.4;
|
|
||||||
color:#fff;
|
|
||||||
padding:.25rem .4rem;
|
|
||||||
border-radius:4px;
|
|
||||||
text-align:center;
|
|
||||||
user-select:none;
|
|
||||||
flex-shrink:0;
|
|
||||||
}
|
|
||||||
.relevance-low {background:#d32f2f;} /* red */
|
|
||||||
.relevance-med {background:#f57c00;} /* amber */
|
|
||||||
.relevance-high {background:#388e3c;} /* green */
|
|
||||||
.error{
|
.error{
|
||||||
color:#c00;
|
color:#c00;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
margin-top:2rem;
|
margin-top:2rem;
|
||||||
}
|
}
|
||||||
/* ─────────── Floating navigation arrows ─────────── */
|
|
||||||
.nav-arrow{
|
|
||||||
position:fixed;
|
|
||||||
top:50%;
|
|
||||||
transform:translateY(-50%);
|
|
||||||
width:42px;
|
|
||||||
height:42px;
|
|
||||||
border:none;
|
|
||||||
border-radius:50%;
|
|
||||||
background:#0d47a1;
|
|
||||||
color:#fff;
|
|
||||||
font-size:1.35rem;
|
|
||||||
line-height:1;
|
|
||||||
display:flex;
|
|
||||||
align-items:center;
|
|
||||||
justify-content:center;
|
|
||||||
cursor:pointer;
|
|
||||||
box-shadow:0 2px 6px rgba(0,0,0,.25);
|
|
||||||
z-index:110;
|
|
||||||
transition:background .2s ease;
|
|
||||||
}
|
|
||||||
.nav-arrow:hover{
|
|
||||||
background:#1565c0;
|
|
||||||
}
|
|
||||||
.nav-arrow:disabled{
|
|
||||||
opacity:.35;
|
|
||||||
cursor:default;
|
|
||||||
}
|
|
||||||
.nav-arrow--left {left:.75rem;}
|
|
||||||
.nav-arrow--right{right:.75rem;}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -266,136 +209,20 @@
|
||||||
const card = document.createElement('div');
|
const card = document.createElement('div');
|
||||||
card.className = 'paragraph-card';
|
card.className = 'paragraph-card';
|
||||||
|
|
||||||
/* main paragraph text */
|
/* store ratings for future use */
|
||||||
|
card.dataset.summaryRating = pData.summary_rating ?? '';
|
||||||
|
card.dataset.topicRatings = JSON.stringify(
|
||||||
|
(pData.topic_ratings ?? []).map(r => !!r.rating)
|
||||||
|
);
|
||||||
|
|
||||||
const p = document.createElement('p');
|
const p = document.createElement('p');
|
||||||
p.textContent = pData.text;
|
p.textContent = pData.text;
|
||||||
p.style.margin = 0;
|
|
||||||
card.appendChild(p);
|
card.appendChild(p);
|
||||||
|
|
||||||
/* relevance badge --------------------------------------- */
|
|
||||||
const badge = document.createElement('span');
|
|
||||||
badge.classList.add('relevance-badge');
|
|
||||||
|
|
||||||
/* fall-back to 0 if the API did not supply a number */
|
|
||||||
const summary_rating = Number.parseFloat(pData.summary_rating ?? 0) / 100;
|
|
||||||
const ratingsArr = pData.topic_ratings ?? [];
|
|
||||||
const totalTrue = ratingsArr.reduce(
|
|
||||||
(sum, r) => sum + (r.rating ? 1 : 0),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const topic_ratings = totalTrue / ratingsArr.length;
|
|
||||||
const rating = (summary_rating + topic_ratings) / 2;
|
|
||||||
|
|
||||||
let cssClass = 'relevance-low';
|
|
||||||
if (rating >= 0.66) cssClass = 'relevance-high';
|
|
||||||
else if (rating >= 0.33) cssClass = 'relevance-med';
|
|
||||||
badge.classList.add(cssClass);
|
|
||||||
|
|
||||||
/* display as percentage for clarity */
|
|
||||||
const pct = Math.round(rating * 100);
|
|
||||||
badge.textContent = pct + '% relevant';
|
|
||||||
card.appendChild(badge);
|
|
||||||
|
|
||||||
card.dataset.summaryRating = rating; /* keep numeric value for sorting */
|
|
||||||
|
|
||||||
elParagraphs.appendChild(card);
|
elParagraphs.appendChild(card);
|
||||||
});
|
});
|
||||||
|
|
||||||
setupRelevanceNavigation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ───────────────── Floating-arrow navigation ───────────────── */
|
|
||||||
let sortedCards = []; // cards sorted by relevance
|
|
||||||
let currentIdx = -1; // index of the active card
|
|
||||||
let previousIdx = -1;
|
|
||||||
let arrowPrev, arrowNext; // will be assigned in setup
|
|
||||||
|
|
||||||
function setupRelevanceNavigation(){
|
|
||||||
const cards = Array.from(document.querySelectorAll('.paragraph-card'));
|
|
||||||
if(!cards.length) return;
|
|
||||||
|
|
||||||
sortedCards = cards.sort(
|
|
||||||
(a,b) => parseFloat(b.dataset.summaryRating) - parseFloat(a.dataset.summaryRating)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* grab the arrow buttons so helpers can reach them */
|
|
||||||
arrowPrev = document.getElementById('arrowPrev');
|
|
||||||
arrowNext = document.getElementById('arrowNext');
|
|
||||||
|
|
||||||
arrowPrev.addEventListener('click', () => goTo(currentIdx - 1));
|
|
||||||
arrowNext.addEventListener('click', () => goTo(currentIdx + 1));
|
|
||||||
|
|
||||||
/* start on the most-relevant paragraph */
|
|
||||||
// goTo(0, /*smooth*/false);
|
|
||||||
updateArrowState();
|
|
||||||
}
|
|
||||||
|
|
||||||
function goTo(idx, smooth = true, fromScroll = false){
|
|
||||||
if (idx < 0)
|
|
||||||
idx = sortedCards.length - 1;
|
|
||||||
else if (idx >= sortedCards.length)
|
|
||||||
idx = 0;
|
|
||||||
// if(idx < 0 || idx >= sortedCards.length) return;
|
|
||||||
|
|
||||||
currentIdx = idx;
|
|
||||||
|
|
||||||
/* only scroll the viewport when the user clicked an arrow */
|
|
||||||
if(!fromScroll){
|
|
||||||
sortedCards[currentIdx].scrollIntoView({
|
|
||||||
behavior: smooth ? 'smooth' : 'auto',
|
|
||||||
block: 'center'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateArrowState();
|
|
||||||
highlightActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateArrowState(){
|
|
||||||
if (currentIdx < 0) {
|
|
||||||
arrowPrev.disabled = false;
|
|
||||||
arrowNext.disabled = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
arrowPrev.disabled = currentIdx === 0;
|
|
||||||
arrowNext.disabled = currentIdx === sortedCards.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function highlightActive(){
|
|
||||||
if (currentIdx < 0) return;
|
|
||||||
if(previousIdx !== -1){
|
|
||||||
sortedCards[previousIdx].classList.remove('paragraph-card--active');
|
|
||||||
}
|
|
||||||
sortedCards[currentIdx].classList.add('paragraph-card--active');
|
|
||||||
previousIdx = currentIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('keydown', evt => {
|
|
||||||
/* ignore key presses while the user is typing in inputs / textareas */
|
|
||||||
const tag = (evt.target.tagName || '').toLowerCase();
|
|
||||||
if (tag === 'input' || tag === 'textarea' || evt.target.isContentEditable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evt.key === 'ArrowLeft') {
|
|
||||||
/* same as clicking the left arrow */
|
|
||||||
if (typeof arrowPrev !== 'undefined' && !arrowPrev.disabled) {
|
|
||||||
evt.preventDefault();
|
|
||||||
arrowPrev.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (evt.key === 'ArrowRight') {
|
|
||||||
/* same as clicking the right arrow */
|
|
||||||
if (typeof arrowNext !== 'undefined' && !arrowNext.disabled) {
|
|
||||||
evt.preventDefault();
|
|
||||||
arrowNext.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<button id="arrowPrev" class="nav-arrow nav-arrow--left" aria-label="Previous paragraph" disabled>←</button>
|
|
||||||
<button id="arrowNext" class="nav-arrow nav-arrow--right" aria-label="Next paragraph" disabled>→</button>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue