mirror of
https://github.com/discourse/discourse.git
synced 2026-08-15 17:24:47 +08:00
The Horizon theme's topic card system relied on inspecting
`router.currentRouteName` to decide when to apply card styling. This
was fragile — the theme was coupled to internal routing details — and
made it impossible to scope card behavior per-list (e.g. showing simple
cards for suggested topics but high-context cards on discovery).
This PR introduces a `listContext` string prop that flows through the
topic list component tree, replacing all route-name checks with explicit
context values.
## What changed
### Core: `listContext` prop threading
Every topic list call site now passes an explicit context string
(`"discovery"`, `"suggested"`, `"related"`, `"group-activity"`,
`"user-activity"`, `"messages"`, `"assigned"`). The prop flows from
the call site through `BasicTopicList` → `TopicList` → `Item` and into
all value transformers (`topic-list-class`, `topic-list-columns`,
`topic-list-item-class`, `topic-list-item-style`,
`topic-list-item-mobile-layout`) and the `topic-list-item-click`
behavior transformer.
This lets the theme decide card behavior based on semantic context
rather than route names, and means the theme no longer needs to
`container.lookup("service:router")`.
### Horizon initializer rewrite
- Replace `isHighContextRoute(router.currentRouteName)` with
`isTopicCardContext(listContext)` checks using two declarative arrays:
`TOPIC_CARD_CONTEXTS` and `SIMPLE_CARD_CONTEXTS`.
- Register a `topic-list-class` transformer that adds `--d-topic-cards`
to topic lists in card contexts.
- Suggested/related lists always get the simple card layout, even when
high-context mode is enabled.
- Preserve the `bulk-select` column in high-context layout (its item
cell is hidden by existing CSS) so the header toggle icon renders.
- Set `header: HeaderTopicCell` on the high-context-card column so the
bulk action buttons ("Select All" / "Clear All") appear in the header.
### CSS scoping and cleanup
- **Topic card styles** scoped to `.topic-list.--d-topic-cards` instead
of applying globally to `.topic-list-body`, preventing style leakage
into messages and other non-card lists.
- **Badge category colors** consolidated into CSS custom properties
(`--badge-category-bg`, `--badge-category-text`) on
`.badge-category__wrapper`, replacing 6 repeated
`light-dark(oklch(...))` expressions across 3 files.
- **Messages page**: removed the 72-line `body.user-messages-page`
override block. Messages get `listContext="messages"` which is not a
card context, so they use default rendering. Desktop bulk-select and
header overrides scoped with `body:not(.user-messages-page)`.
- **Bulk select in high-context cards**: fixed checkbox centering,
selected-state background (removed override that reset it to
`--secondary`), sticky header `z-index`, and `max-width: unset` on
header cells at small viewports.
- **Removed** `color-exploration.scss` (unused sidebar color vars),
`excerpt-expanded` grid area styles, hardcoded `#e45735` (now
`var(--danger)`).
- **Renamed** `has-replies` → `--has-replies` for BEM consistency.
### Other fixes
- Extract `getTopicStatusBadge()` into shared utility, fixing
inconsistency where `topic-status-column` only checked `topic.pinned`
but the high-context card checked both `pinned` and `pinned_globally`.
- Fix `topic-list-item-mobile-layout` transformer to properly return
`value` for non-card contexts (was returning `undefined`).
- Fix `hasReplies` to use `replyCount > 0` instead of `posts_count > 1`.
- Typo fix in `chat.scss`.
---------
Co-authored-by: chapoi <101828855+chapoi@users.noreply.github.com>
222 lines
4.7 KiB
SCSS
Vendored
222 lines
4.7 KiB
SCSS
Vendored
@use "lib/viewport";
|
|
|
|
// temp separate file to avoid merge hell… to be distributed later
|
|
@include viewport.until(lg) {
|
|
html,
|
|
.d-header {
|
|
background-color: var(--d-content-background);
|
|
}
|
|
}
|
|
|
|
#main-outlet-wrapper {
|
|
*[class*="navigation-"] & {
|
|
@include viewport.until(sm) {
|
|
padding: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#main-outlet {
|
|
@include viewport.until(sm) {
|
|
padding-top: var(--space-2);
|
|
}
|
|
|
|
.list-controls {
|
|
@include viewport.until(sm) {
|
|
padding-inline: var(
|
|
--space-4
|
|
) !important; // override will be fixed when the whole chat page shenanigans is resolved
|
|
padding-block: var(--space-2);
|
|
border-bottom: 1px solid var(--primary-200);
|
|
}
|
|
|
|
.navigation-container {
|
|
@include viewport.until(sm) {
|
|
gap: var(--space-2);
|
|
|
|
.category-breadcrumb.hidden,
|
|
.category-breadcrumb {
|
|
display: flex !important;
|
|
column-gap: var(--space-4);
|
|
row-gap: var(--space-1);
|
|
flex-basis: 100%;
|
|
|
|
li {
|
|
margin-right: 0;
|
|
margin-left: calc(
|
|
(var(--space-2) - 2px) * -1
|
|
); // 2px is width of the outline
|
|
}
|
|
|
|
.select-kit-header-wrapper {
|
|
gap: 0.25em;
|
|
}
|
|
|
|
.select-kit-header {
|
|
background: var(--d-content-background);
|
|
}
|
|
}
|
|
|
|
.btn-default {
|
|
border: 0;
|
|
margin-right: 0;
|
|
|
|
.d-icon {
|
|
font-size: var(--font-up-1);
|
|
}
|
|
}
|
|
|
|
.fk-d-button-tooltip {
|
|
margin-right: 0;
|
|
margin-left: var(
|
|
--space-1
|
|
); // pure visual correction for horizontal alignment
|
|
|
|
&:has(#create-topic) {
|
|
order: 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#navigation-bar,
|
|
.navigation-controls,
|
|
.category-breadcrumb {
|
|
@include viewport.until(sm) {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.list-container {
|
|
@include viewport.until(sm) {
|
|
padding-inline: 0 !important;
|
|
}
|
|
|
|
.topic-list-body {
|
|
@include viewport.until(sm) {
|
|
border-top: 0;
|
|
padding-top: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#topic-title {
|
|
@include viewport.until(sm) {
|
|
.title-wrapper {
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.topic-category {
|
|
order: -1;
|
|
}
|
|
|
|
.badge-category__wrapper {
|
|
font-size: var(--font-down-2-rem);
|
|
border-radius: var(--d-border-radius);
|
|
padding: var(--space-1) var(--space-2);
|
|
background-color: var(--badge-category-bg);
|
|
border: 1px solid var(--badge-category-bg);
|
|
}
|
|
|
|
.badge-category__name {
|
|
color: var(--badge-category-text);
|
|
}
|
|
|
|
.discourse-tags {
|
|
gap: var(--space-1);
|
|
|
|
&__tag-separator {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.discourse-tag {
|
|
font-size: var(--font-down-2-rem);
|
|
padding: var(--space-1) var(--space-2);
|
|
gap: var(--space-1);
|
|
border-radius: var(--d-border-radius-large);
|
|
border: 1px solid var(--primary-low-mid);
|
|
background: var(--secondary);
|
|
}
|
|
}
|
|
}
|
|
|
|
.container.posts {
|
|
@include viewport.until(sm) {
|
|
.main-avatar .avatar {
|
|
width: 40px;
|
|
height: 40px;
|
|
}
|
|
|
|
.topic-body {
|
|
.topic-meta-data {
|
|
.username {
|
|
font-size: var(--font-0-rem);
|
|
}
|
|
}
|
|
|
|
.contents {
|
|
padding-top: var(--space-4);
|
|
}
|
|
}
|
|
|
|
.small-action {
|
|
&-desc {
|
|
padding: var(--space-1) 0;
|
|
}
|
|
|
|
// for core eventually, better way imo
|
|
.topic-avatar {
|
|
padding-top: 0;
|
|
align-items: center;
|
|
|
|
.d-icon {
|
|
font-size: var(--font-up-1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#topic-footer-buttons {
|
|
@include viewport.until(sm) {
|
|
padding-inline: var(--space-1) !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
// should be changed in core, should not be a primary btn
|
|
// changing this into straight buttons to match the progress one, which doesn't work well with rounded corners
|
|
#topic-progress-wrapper {
|
|
.progress-back-container {
|
|
margin-right: 0;
|
|
margin-bottom: var(--space-1);
|
|
|
|
.btn-primary.progress-back {
|
|
border-radius: 0;
|
|
background: var(--secondary);
|
|
border: 1px solid var(--tertiary-low);
|
|
color: var(--accent-color);
|
|
padding: var(--space-2) var(--space-4);
|
|
|
|
.d-icon {
|
|
color: var(--accent-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
.topic-admin-menu-trigger {
|
|
border-radius: 0;
|
|
background: var(--secondary);
|
|
border: 1px solid var(--tertiary-low);
|
|
}
|
|
}
|
|
|
|
.mobile-device #reply-control.show-preview .submit-panel {
|
|
background-color: var(--background-color);
|
|
}
|
|
|
|
.d-editor-preview-wrapper {
|
|
outline: 2px solid var(--background-color);
|
|
}
|