0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-15 17:24:47 +08:00
discourse/themes/horizon/scss/mobile-stuff.scss
Régis Hanol f068c56c1b
DEV: Refactor Horizon topic cards to use listContext instead of route checks (#37355)
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>
2026-02-11 16:13:58 +01:00

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);
}