Custom Templates: Topic list template
Here are some examples for the topic list view:

Template:
<div class="pl">
{{#if pinned}}
{{#each pinned}}
<div class="pl-card pl-card--pinned{{#unless this.is_read}} pl-card--unread{{/unless}}">
<span class="pl-avatar">
<a href="{{ this.author.profile_url }}"><img src="{{ this.author.avatar_url }}" alt="{{ this.author.username }}" /></a>
</span>
<div class="pl-main">
<div class="pl-chips">
<span class="pl-pin"><span class="fa-solid fa-thumbtack"></span> Pinned</span>
{{#each this.labels}}
<span class="pl-chip">{{ this.title }}</span>
{{/each}}
{{#if this.is_locked}}<span class="pl-state"><span class="fa-solid fa-lock"></span> Locked</span>{{/if}}
{{#if this.is_solved}}<span class="pl-state pl-state--solved"><span class="fa-solid fa-check"></span> Solved</span>{{/if}}
</div>
<div class="pl-title"><a href="{{ this.url }}">{{ this.title }}</a></div>
<div class="pl-meta">{{ this.author.username }} <span class="pl-sep">·</span> {{ this.created_at }}</div>
<div class="pl-foot">
<span class="pl-stat"><span class="fa-regular fa-comment"></span> {{ this.replies_count }}</span>
<span class="pl-stat"><span class="fa-regular fa-eye"></span> {{ this.views_short }}</span>
{{#if this.last_post.author}}
<span class="pl-activity">
<img src="{{ this.last_post.avatar_url }}" alt="{{ this.last_post.author }}" />
<a href="{{ this.last_post.url }}">{{ this.last_post.author }} <span class="pl-sep">·</span> {{ this.last_post.date }}</a>
</span>
{{/if}}
</div>
</div>
{{{ this.checkbox }}}
</div>
{{/each}}
{{/if}}
{{#each topics}}
<div class="pl-card{{#unless this.is_read}} pl-card--unread{{/unless}}">
<span class="pl-avatar">
<a href="{{ this.author.profile_url }}"><img src="{{ this.author.avatar_url }}" alt="{{ this.author.username }}" /></a>
</span>
<div class="pl-main">
<div class="pl-chips">
{{#each this.labels}}
<span class="pl-chip">{{ this.title }}</span>
{{/each}}
{{#if this.is_hot}}<span class="pl-state pl-state--hot"><span class="fa-solid fa-fire-flame-curved"></span> Hot</span>{{/if}}
{{#if this.is_locked}}<span class="pl-state"><span class="fa-solid fa-lock"></span> Locked</span>{{/if}}
{{#if this.is_solved}}<span class="pl-state pl-state--solved"><span class="fa-solid fa-check"></span> Solved</span>{{/if}}
</div>
<div class="pl-title"><a href="{{ this.url }}">{{ this.title }}</a></div>
<div class="pl-meta">{{ this.author.username }} <span class="pl-sep">·</span> {{ this.created_at }}</div>
<div class="pl-foot">
<span class="pl-stat"><span class="fa-regular fa-comment"></span> {{ this.replies_count }}</span>
<span class="pl-stat"><span class="fa-regular fa-eye"></span> {{ this.views_short }}</span>
{{#if this.participants}}
<span class="pl-people">
{{#each this.participants}}
<img src="{{ this.avatar_url }}" alt="{{ this.username }}" />
{{/each}}
</span>
{{/if}}
{{#if this.last_post.author}}
<span class="pl-activity">
<img src="{{ this.last_post.avatar_url }}" alt="{{ this.last_post.author }}" />
<a href="{{ this.last_post.url }}">{{ this.last_post.author }} <span class="pl-sep">·</span> {{ this.last_post.date }}</a>
</span>
{{/if}}
</div>
</div>
{{{ this.checkbox }}}
</div>
{{/each}}
{{#unless topics}}{{#unless pinned}}
<div class="pl-empty">No topics here yet.</div>
{{/unless}}{{/unless}}
{{#if pagination.has_pages}}
<div class="pl-pages">
Page {{ pagination.current_page }} of {{ pagination.last_page }}
{{#if pagination.prev_url}}<a href="{{ pagination.prev_url }}">Previous</a>{{/if}}
{{#if pagination.next_url}}<a href="{{ pagination.next_url }}">Next</a>{{/if}}
</div>
{{/if}}
</div>CSS:
.pl { display: flex; flex-direction: column; gap: 0.65rem; padding: 0.75rem; }
.pl-card { display: flex; gap: 0.8rem; padding: 0.9rem 1rem; background: var(--fs-topic-bg, rgba(128,128,128,0.04)); border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.18)); border-radius: 0.75rem; transition: border-color 0.14s ease, box-shadow 0.14s ease; }
.pl-card:hover { border-color: var(--fs-panel-footer-accent, rgba(128,128,128,0.4)); box-shadow: 0 4px 14px rgba(0, 0, 0, 0.06); }
.pl-card--unread { box-shadow: inset 3px 0 0 var(--fs-panel-footer-accent, currentColor); }
.pl-card--pinned { background: var(--fs-panel-section-bg, rgba(128,128,128,0.07)); }
.pl-avatar { flex-shrink: 0; }
.pl-avatar img { width: 2.6rem; height: 2.6rem; border-radius: 50%; object-fit: cover; display: block; }
.pl-main { flex: 1; min-width: 0; }
.pl-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; margin-bottom: 0.25rem; }
.pl-pin, .pl-chip, .pl-state { display: inline-flex; align-items: center; gap: 0.28rem; font-size: 0.62rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; padding: 0.14rem 0.5rem; border-radius: 999px; }
.pl-pin { color: #fff; background: var(--fs-panel-footer-accent, #35a377); }
.pl-chip { background: var(--fs-panel-section-bg, rgba(128,128,128,0.12)); opacity: 0.85; }
.pl-state { border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.25)); opacity: 0.8; }
.pl-state--solved { color: var(--fs-panel-footer-accent, inherit); border-color: var(--fs-panel-footer-accent, rgba(128,128,128,0.4)); opacity: 1; }
.pl-state--hot { opacity: 1; }
.pl-title a { font-size: 1rem; font-weight: 700; letter-spacing: -0.01em; color: var(--fs-forum-link-color, inherit); text-decoration: none; }
.pl-title a:hover { color: var(--fs-panel-footer-accent, inherit); }
.pl-card--unread .pl-title a { color: var(--fs-panel-footer-accent, inherit); }
.pl-meta { font-size: 0.73rem; opacity: 0.6; margin-top: 0.1rem; }
.pl-sep { opacity: 0.5; margin: 0 0.1rem; }
.pl-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-top: 0.55rem; font-size: 0.74rem; }
.pl-stat { display: inline-flex; align-items: center; gap: 0.32rem; opacity: 0.75; font-variant-numeric: tabular-nums; }
.pl-people { display: inline-flex; }
.pl-people img { width: 1.4rem; height: 1.4rem; border-radius: 50%; object-fit: cover; border: 2px solid var(--fs-topic-bg, #fff); margin-left: -0.4rem; }
.pl-people img:first-child { margin-left: 0; }
.pl-activity { display: inline-flex; align-items: center; gap: 0.4rem; margin-left: auto; min-width: 0; }
.pl-activity img { width: 1.35rem; height: 1.35rem; border-radius: 50%; object-fit: cover; }
.pl-activity a { font-size: 0.72rem; color: inherit; opacity: 0.7; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-activity a:hover { opacity: 1; }
.pl-card .topic-row__bulk-select { align-self: center; }
.pl-empty { padding: 1.6rem 1rem; text-align: center; opacity: 0.7; }
.pl-pages { padding: 0.4rem 0.3rem; font-size: 0.78rem; opacity: 0.8; display: flex; gap: 0.8rem; }
.pl-pages a { color: var(--fs-link-color, inherit); font-weight: 600; text-decoration: none; }
.pl-pages a:hover { text-decoration: underline; }
@media (max-width: 640px) {
.pl-activity { display: none; }
.pl-people { display: none; }
}
Template:
<div class="tk">
<div class="tk-cols">
<span></span>
<span>Topic</span>
<span class="tk-r">Replies</span>
<span class="tk-r">Views</span>
<span>Activity</span>
</div>
{{#if pinned}}
{{#each pinned}}
<div class="tk-row tk-row--pinned{{#unless this.is_read}} tk-row--unread{{/unless}}">
<span class="tk-glyph"><span class="fa-solid fa-thumbtack"></span></span>
<div class="tk-main">
<div class="tk-title">
<a href="{{ this.url }}">{{ this.title }}</a>
{{#each this.labels}}
<span class="tk-label">{{ this.title }}</span>
{{/each}}
{{#if this.is_locked}}<span class="tk-mini fa-solid fa-lock"></span>{{/if}}
{{#if this.is_solved}}<span class="tk-mini tk-mini--solved fa-solid fa-check"></span>{{/if}}
</div>
<div class="tk-meta">{{ this.author.username }} · {{ this.created_at }}</div>
</div>
<span class="tk-num">{{ this.replies_count }}</span>
<span class="tk-num">{{ this.views_short }}</span>
<div class="tk-act">
{{#if this.last_post.author}}
<a href="{{ this.last_post.url }}">{{ this.last_post.author }}</a>
<span>{{ this.last_post.date }}</span>
{{/if}}
</div>
{{{ this.checkbox }}}
</div>
{{/each}}
{{/if}}
{{#each topics}}
<div class="tk-row{{#unless this.is_read}} tk-row--unread{{/unless}}">
<span class="tk-glyph">
{{#if this.is_locked}}
<span class="fa-solid fa-lock"></span>
{{else}}
{{#if this.is_hot}}
<span class="tk-hot fa-solid fa-fire-flame-curved"></span>
{{else}}
{{#if this.is_solved}}
<span class="tk-ok fa-solid fa-check"></span>
{{else}}
<span class="tk-dot"></span>
{{/if}}
{{/if}}
{{/if}}
</span>
<div class="tk-main">
<div class="tk-title">
<a href="{{ this.url }}">{{ this.title }}</a>
{{#each this.labels}}
<span class="tk-label">{{ this.title }}</span>
{{/each}}
</div>
<div class="tk-meta">{{ this.author.username }} · {{ this.created_at }}</div>
</div>
<span class="tk-num">{{ this.replies_count }}</span>
<span class="tk-num">{{ this.views_short }}</span>
<div class="tk-act">
{{#if this.last_post.author}}
<a href="{{ this.last_post.url }}">{{ this.last_post.author }}</a>
<span>{{ this.last_post.date }}</span>
{{/if}}
</div>
{{{ this.checkbox }}}
</div>
{{/each}}
{{#unless topics}}{{#unless pinned}}
<div class="tk-empty">No topics here yet.</div>
{{/unless}}{{/unless}}
{{#if pagination.has_pages}}
<div class="tk-pages">
Page {{ pagination.current_page }} of {{ pagination.last_page }}
{{#if pagination.prev_url}}<a href="{{ pagination.prev_url }}">Previous</a>{{/if}}
{{#if pagination.next_url}}<a href="{{ pagination.next_url }}">Next</a>{{/if}}
</div>
{{/if}}
</div>CSS:
.tk-cols, .tk-row { display: grid; grid-template-columns: 1.7rem minmax(0, 1fr) 4.5rem 4.5rem 11rem; gap: 0.9rem; align-items: center; padding: 0 0.9rem; }
.tk:has(.topic-row__bulk-select) .tk-cols,
.tk:has(.topic-row__bulk-select) .tk-row { grid-template-columns: 1.7rem minmax(0, 1fr) 4.5rem 4.5rem 11rem 1.6rem; }
.topic-row__bulk-select { display: flex; justify-content: center; }
.tk-cols { padding-top: 0.55rem; padding-bottom: 0.45rem; font-size: 0.58rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.11em; opacity: 0.45; border-bottom: 1px solid var(--fs-panel-border, rgba(128,128,128,0.2)); }
.tk-r { text-align: right; }
.tk-row { padding-top: 0.55rem; padding-bottom: 0.55rem; }
.tk-row + .tk-row { border-top: 1px solid var(--fs-forum-divider, rgba(128,128,128,0.1)); }
.tk-row:hover { background: var(--fs-panel-section-bg, rgba(128,128,128,0.05)); }
.tk-row--pinned { background: var(--fs-panel-section-bg, rgba(128,128,128,0.06)); }
.tk-glyph { display: flex; align-items: center; justify-content: center; font-size: 0.72rem; opacity: 0.65; }
.tk-row--pinned .tk-glyph { color: var(--fs-panel-footer-accent, inherit); opacity: 1; }
.tk-hot { color: var(--fs-panel-footer-accent, inherit); }
.tk-ok { color: var(--fs-panel-footer-accent, inherit); }
.tk-dot { width: 0.42rem; height: 0.42rem; border-radius: 50%; background: currentColor; opacity: 0.28; }
.tk-row--unread .tk-dot { background: var(--fs-panel-footer-accent, currentColor); opacity: 1; }
.tk-main { min-width: 0; }
.tk-title { display: flex; align-items: center; gap: 0.45rem; min-width: 0; flex-wrap: wrap; }
.tk-title a { font-size: 0.86rem; font-weight: 500; color: var(--fs-forum-link-color, inherit); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tk-title a:hover { text-decoration: underline; }
.tk-row--unread .tk-title a { font-weight: 750; }
.tk-label { font-size: 0.58rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.1rem 0.42rem; border-radius: 0.28rem; background: var(--fs-panel-section-bg, rgba(128,128,128,0.12)); opacity: 0.85; }
.tk-mini { font-size: 0.62rem; opacity: 0.6; }
.tk-mini--solved { color: var(--fs-panel-footer-accent, inherit); opacity: 1; }
.tk-meta { font-size: 0.67rem; opacity: 0.52; margin-top: 0.05rem; }
.tk-num { text-align: right; font-size: 0.8rem; font-weight: 600; font-variant-numeric: tabular-nums; opacity: 0.8; }
.tk-act { display: flex; flex-direction: column; min-width: 0; line-height: 1.35; }
.tk-act a { font-size: 0.72rem; font-weight: 600; color: inherit; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tk-act a:hover { text-decoration: underline; }
.tk-act span { font-size: 0.64rem; opacity: 0.5; }
.tk-empty { padding: 1.6rem 1rem; text-align: center; opacity: 0.7; }
.tk-pages { padding: 0.6rem 0.9rem; font-size: 0.76rem; opacity: 0.8; display: flex; gap: 0.8rem; border-top: 1px solid var(--fs-panel-border, rgba(128,128,128,0.2)); }
.tk-pages a { color: var(--fs-link-color, inherit); font-weight: 600; text-decoration: none; }
.tk-pages a:hover { text-decoration: underline; }
@media (max-width: 760px) {
.tk-cols { display: none; }
.tk-row { grid-template-columns: 1.4rem minmax(0, 1fr) 3rem; gap: 0.6rem; }
.tk:has(.topic-row__bulk-select) .tk-row { grid-template-columns: 1.4rem minmax(0, 1fr) 3rem 1.6rem; }
.tk-num + .tk-num { display: none; }
.tk-act { display: none; }
}
Template:
<div class="hd">
{{#if pinned}}
<div class="hd-eyebrow">Featured</div>
<div class="hd-features">
{{#each pinned}}
<div class="hd-hero{{#unless this.is_read}} hd-hero--unread{{/unless}}">
<div class="hd-hero-chips">
<span class="hd-pin"><span class="fa-solid fa-thumbtack"></span></span>
{{#each this.labels}}
<span class="hd-chip">{{ this.title }}</span>
{{/each}}
{{#if this.is_locked}}<span class="hd-chip"><span class="fa-solid fa-lock"></span> Locked</span>{{/if}}
</div>
<div class="hd-hero-title"><a href="{{ this.url }}">{{ this.title }}</a></div>
<div class="hd-hero-meta">
<img src="{{ this.author.avatar_url }}" alt="{{ this.author.username }}" />
<span>{{ this.author.username }} <span class="hd-sep">·</span> {{ this.created_at }}</span>
</div>
<div class="hd-hero-stats">
<b>{{ this.replies_count }}</b> replies <span class="hd-sep">·</span> <b>{{ this.views_short }}</b> views
{{#if this.last_post.author}}
<span class="hd-sep">·</span> last {{ this.last_post.author }}, {{ this.last_post.date }}
{{/if}}
</div>
</div>
{{/each}}
</div>
{{/if}}
<div class="hd-eyebrow">Latest</div>
<div class="hd-list">
{{#each topics}}
<div class="hd-row{{#unless this.is_read}} hd-row--unread{{/unless}}">
<div class="hd-main">
<div class="hd-title">
<a href="{{ this.url }}">{{ this.title }}</a>
{{#if this.is_hot}}<span class="hd-flame fa-solid fa-fire-flame-curved"></span>{{/if}}
{{#if this.is_solved}}<span class="hd-check fa-solid fa-check"></span>{{/if}}
{{#if this.is_locked}}<span class="hd-lock fa-solid fa-lock"></span>{{/if}}
</div>
<div class="hd-meta">
{{#each this.labels}}
<span class="hd-tag">{{ this.title }}</span>
{{/each}}
{{ this.author.username }} <span class="hd-sep">·</span> {{ this.created_at }}
</div>
</div>
<div class="hd-side">
<span class="hd-count"><b>{{ this.replies_count }}</b> replies</span>
<span class="hd-count hd-count--dim"><b>{{ this.views_short }}</b> views</span>
{{#if this.last_post.author}}
<a href="{{ this.last_post.url }}" class="hd-when">{{ this.last_post.date }}</a>
{{/if}}
</div>
{{{ this.checkbox }}}
</div>
{{/each}}
</div>
{{#unless topics}}{{#unless pinned}}
<div class="hd-empty">No topics here yet.</div>
{{/unless}}{{/unless}}
{{#if pagination.has_pages}}
<div class="hd-pages">
Page {{ pagination.current_page }} of {{ pagination.last_page }}
{{#if pagination.prev_url}}<a href="{{ pagination.prev_url }}">Previous</a>{{/if}}
{{#if pagination.next_url}}<a href="{{ pagination.next_url }}">Next</a>{{/if}}
</div>
{{/if}}
</div>CSS:
.hd { padding: 0.9rem; }
.hd-eyebrow { font-size: 0.62rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.18em; opacity: 0.5; margin: 0 0 0.6rem; }
.hd-list + .hd-eyebrow, .hd-features + .hd-eyebrow { margin-top: 1.4rem; }
.hd-features { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.8rem; margin-bottom: 1.4rem; }
.hd-hero { padding: 1rem 1.1rem; background: var(--fs-panel-section-bg, rgba(128,128,128,0.06)); border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.18)); border-top: 3px solid var(--fs-panel-footer-accent, rgba(128,128,128,0.4)); border-radius: 0.6rem; }
.hd-hero--unread { background: var(--fs-topic-bg, rgba(128,128,128,0.08)); }
.hd-hero-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; margin-bottom: 0.4rem; }
.hd-pin { display: inline-flex; align-items: center; justify-content: center; width: 1.4rem; height: 1.4rem; border-radius: 50%; color: #fff; background: var(--fs-panel-footer-accent, #35a377); font-size: 0.6rem; }
.hd-chip { display: inline-flex; align-items: center; gap: 0.25rem; font-size: 0.6rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; padding: 0.13rem 0.5rem; border-radius: 999px; background: var(--fs-panel-bg, rgba(255,255,255,0.6)); border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.2)); opacity: 0.85; }
.hd-hero-title a { font-size: 1.22rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.25; color: var(--fs-forum-link-color, inherit); text-decoration: none; }
.hd-hero-title a:hover { color: var(--fs-panel-footer-accent, inherit); }
.hd-hero--unread .hd-hero-title a { color: var(--fs-panel-footer-accent, inherit); }
.hd-hero-meta { display: flex; align-items: center; gap: 0.45rem; margin-top: 0.5rem; font-size: 0.73rem; opacity: 0.7; }
.hd-hero-meta img { width: 1.5rem; height: 1.5rem; border-radius: 50%; object-fit: cover; }
.hd-hero-stats { margin-top: 0.55rem; font-size: 0.73rem; opacity: 0.75; font-variant-numeric: tabular-nums; }
.hd-hero-stats b { font-weight: 800; }
.hd-sep { opacity: 0.45; margin: 0 0.12rem; }
.hd-row { display: flex; align-items: center; gap: 1.2rem; padding: 0.75rem 0.2rem; }
.hd-row + .hd-row { border-top: 1px solid var(--fs-forum-divider, rgba(128,128,128,0.12)); }
.hd-row:hover { background: var(--fs-panel-section-bg, rgba(128,128,128,0.04)); }
.hd-main { flex: 1; min-width: 0; }
.hd-title { display: flex; align-items: center; gap: 0.45rem; min-width: 0; }
.hd-title a { font-size: 0.97rem; font-weight: 650; letter-spacing: -0.01em; color: var(--fs-forum-link-color, inherit); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hd-title a:hover { color: var(--fs-panel-footer-accent, inherit); }
.hd-row--unread .hd-title a { font-weight: 850; color: var(--fs-panel-footer-accent, inherit); }
.hd-flame, .hd-check { font-size: 0.7rem; color: var(--fs-panel-footer-accent, inherit); }
.hd-lock { font-size: 0.68rem; opacity: 0.55; }
.hd-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.45rem; font-size: 0.7rem; opacity: 0.6; margin-top: 0.12rem; }
.hd-tag { font-size: 0.58rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.08rem 0.4rem; border-radius: 0.26rem; background: var(--fs-panel-section-bg, rgba(128,128,128,0.12)); }
.hd-side { flex-shrink: 0; display: flex; align-items: baseline; gap: 1.1rem; }
.hd-count { font-size: 0.72rem; opacity: 0.8; font-variant-numeric: tabular-nums; }
.hd-count b { font-size: 0.88rem; font-weight: 800; }
.hd-count--dim { opacity: 0.55; }
.hd-when { font-size: 0.7rem; opacity: 0.6; color: inherit; text-decoration: none; }
.hd-when:hover { opacity: 1; text-decoration: underline; }
.hd-empty { padding: 1.6rem 1rem; text-align: center; opacity: 0.7; }
.hd-pages { margin-top: 0.8rem; font-size: 0.76rem; opacity: 0.8; display: flex; gap: 0.8rem; }
.hd-pages a { color: var(--fs-link-color, inherit); font-weight: 600; text-decoration: none; }
.hd-pages a:hover { text-decoration: underline; }
@media (max-width: 760px) {
.hd-features { grid-template-columns: 1fr; }
.hd-side { flex-direction: column; align-items: flex-end; gap: 0.15rem; }
.hd-count--dim { display: none; }
}
ForumSpark Support