Q&A: pinned questions are featured on the home page, home cards link to the full answer, newest answer first; v2.22.1
Publish Container / build (push) Successful in 16m39s
Publish Container / build (push) Successful in 16m39s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
960ee41375
commit
4a7c3cc967
6 files changed
+21
-7
No files matched your search
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "siteforge",
|
"name": "siteforge",
|
||||||
"version": "2.22.0",
|
"version": "2.22.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "siteforge",
|
"name": "siteforge",
|
||||||
"version": "2.22.0",
|
"version": "2.22.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.1135.0",
|
"@aws-sdk/client-s3": "^3.1135.0",
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "siteforge",
|
"name": "siteforge",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.22.0",
|
"version": "2.22.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -76,10 +76,12 @@ export function register(app) {
|
|||||||
const publicQuestions = sourceQuestions
|
const publicQuestions = sourceQuestions
|
||||||
.filter(q => q.isApproved === true && q.answer && q.answer.trim().length > 0)
|
.filter(q => q.isApproved === true && q.answer && q.answer.trim().length > 0)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
// Pinned questions always float to top
|
// Pinned first (they are also the ones featured on the home page), then newest answer first
|
||||||
if (a.pinned && !b.pinned) return -1
|
if (a.pinned && !b.pinned) return -1
|
||||||
if (!a.pinned && b.pinned) return 1
|
if (!a.pinned && b.pinned) return 1
|
||||||
return 0
|
const at = new Date(a.answeredAt ?? a.submittedAt ?? 0).getTime() || 0
|
||||||
|
const bt = new Date(b.answeredAt ?? b.submittedAt ?? 0).getTime() || 0
|
||||||
|
return bt - at
|
||||||
})
|
})
|
||||||
res.json({ questions: publicQuestions.map(toPublicQuestion) })
|
res.json({ questions: publicQuestions.map(toPublicQuestion) })
|
||||||
})
|
})
|
||||||
|
|||||||
+11
@@ -1349,6 +1349,17 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.qa-callout-more {
|
||||||
|
margin-top: auto;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--brand-gold);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-callout-more:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Home Jump Section ── */
|
/* ── Home Jump Section ── */
|
||||||
/* ── Truth For Life Widget ── */
|
/* ── Truth For Life Widget ── */
|
||||||
.section-tfl {
|
.section-tfl {
|
||||||
|
|||||||
@@ -1260,6 +1260,7 @@ function HomepageQACallout() {
|
|||||||
<p className="qa-callout-question">"{q.question}"</p>
|
<p className="qa-callout-question">"{q.question}"</p>
|
||||||
<p className="qa-callout-answer">{q.answer.length > 220 ? q.answer.slice(0, 220).trimEnd() + '…' : q.answer}</p>
|
<p className="qa-callout-answer">{q.answer.length > 220 ? q.answer.slice(0, 220).trimEnd() + '…' : q.answer}</p>
|
||||||
{q.firstName && <p className="qa-callout-from">— {q.firstName}</p>}
|
{q.firstName && <p className="qa-callout-from">— {q.firstName}</p>}
|
||||||
|
<Link to={`/questions#qa-${q.id}`} className="qa-callout-more">Read the full answer →</Link>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ export function QuestionsAdmin({ questions, onChange }: Props) {
|
|||||||
<section className="admin-panel-section" aria-label="Questions and answers">
|
<section className="admin-panel-section" aria-label="Questions and answers">
|
||||||
<div className="admin-panel-head">
|
<div className="admin-panel-head">
|
||||||
<h2>Bible Questions & Answers</h2>
|
<h2>Bible Questions & Answers</h2>
|
||||||
<p>Work through questions from the top: write an answer, set a topic, and publish. Published answers appear on the public Q&A page right away.</p>
|
<p>Work through questions from the top: write an answer, set a topic, and publish. Published answers appear on the public Q&A page right away. Pinned questions show first there and are featured on the home page.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12, alignItems: 'center' }}>
|
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12, alignItems: 'center' }}>
|
||||||
@@ -350,7 +350,7 @@ export function QuestionsAdmin({ questions, onChange }: Props) {
|
|||||||
<button type="button" className="btn-admin-ghost" onClick={saveFields} disabled={busy || !dirty}>Save draft</button>
|
<button type="button" className="btn-admin-ghost" onClick={saveFields} disabled={busy || !dirty}>Save draft</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<button type="button" className="btn-admin-ghost" onClick={togglePin} disabled={busy}>{selected.pinned ? 'Unpin' : 'Pin to top'}</button>
|
<button type="button" className="btn-admin-ghost" onClick={togglePin} disabled={busy} title="Pinned questions show first on the Q&A page and are featured on the home page">{selected.pinned ? 'Unpin' : 'Pin & feature'}</button>
|
||||||
<button type="button" className="btn-admin-remove" onClick={() => remove([selected.id])} disabled={busy}>Delete</button>
|
<button type="button" className="btn-admin-remove" onClick={() => remove([selected.id])} disabled={busy}>Delete</button>
|
||||||
{dirty && <span className="admin-stats-note">Unsaved changes</span>}
|
{dirty && <span className="admin-stats-note">Unsaved changes</span>}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user