Compare commits

...

210 Commits

Author SHA1 Message Date
shiran d1ce649fb2 feat(cursor): 添加多种自定义光标样式支持
Discourse Theme / ci (push) Failing after 0s
- 将原有的 custom_cursor 重命名为 default_cursor,并实现默认光标功能
- 新增 hover_cursor 配置,为链接和按钮元素提供悬停光标效果
- 新增 pointer_cursor 配置,为链接元素提供专用指针光标
- 新增 text_cursor 配置,为输入框和文本域提供文本编辑光标
- 在 settings.yml 中添加对应的配置项和描述信息
- 实现多层级光标样式的 SCSS 逻辑处理
2026-02-26 15:48:21 +08:00
shiran b6e54e3cbd feat(theme): 添加自定义光标功能
Discourse Theme / ci (push) Failing after 1s
- 在 SCSS 中实现条件编译以支持自定义光标
- 添加 $custom_cursor 变量控制光标样式
- 在 settings.yml 中增加 custom_cursor 配置项
- 支持上传 SVG 文件作为自定义光标
- 默认值设为空字符串以保持向后兼容性
2026-02-26 15:37:57 +08:00
shiran eb3f4efe2c feat(style): 添加自定义鼠标指针样式
Discourse Theme / ci (push) Failing after 0s
- 在全局范围内应用自定义 SVG 指针
- 设置指针热点位置为 1,1 坐标
- 保留默认指针作为备选方案
- 隐藏 Discourse 功能标识元素
2026-02-26 15:32:48 +08:00
shiran 2f5c4b2989 style(scss): 移除按钮悬停背景色过渡效果
Discourse Theme / ci (push) Failing after 0s
- 移除了按钮元素的 hover 状态背景色变化
- 删除了 transition 属性相关的悬停动画效果
- 简化了按钮样式代码结构
2026-02-26 15:26:05 +08:00
shiran 15ec4e326a style(css): 更新样式选择器以匹配管理员容器布局
Discourse Theme / ci (push) Failing after 2s
- 添加 .admin-container>.container.groups-index 选择器到现有的背景样式规则
- 保持与现有 .ember-view.group-box 样式的一致性
- 确保管理员组索引页面的视觉统一性
2026-02-26 15:22:04 +08:00
shiran 0c85709857 fix(style): 修复群组页面容器背景样式
Discourse Theme / ci (push) Failing after 1s
- 修正了群组索引页面的选择器以正确应用背景样式
- 确保群组页面容器具有正确的背景颜色和圆角效果
2026-02-26 15:19:58 +08:00
shiran 7f87145998 style(css): 添加群组容器样式支持
Discourse Theme / ci (push) Failing after 0s
- 为 .container.group 添加背景色、圆角和模糊效果样式
- 扩展 backdrop-filter 应用范围到群组相关容器
- 保持一致的视觉风格和透明度效果
2026-02-26 14:49:20 +08:00
shiran 2f7bd50a36 style(css): 更新SCSS样式以添加新组件背景样式
Discourse Theme / ci (push) Failing after 0s
- 为 .ember-view.group-box 添加背景、圆角和阴影样式
- 统一主题帖子、搜索头部、管理员插件配置页面背景样式
- 应用变量 --d-chat-input-bg-color 和 --d-border-radius
- 添加黑色半透明阴影效果 box-shadow: #00000024 0 0 7px 2px
2026-02-26 14:47:44 +08:00
shiran d5f84bc7fc style(scss): 更新背景样式配置
Discourse Theme / ci (push) Failing after 2s
- 为 .container.groups-index 添加背景色、圆角和模糊效果
- 统一多个选择器的视觉样式表现
2026-02-26 14:46:29 +08:00
shiran 1e2fc63ed1 feat(style): 添加用户卡片悬停效果
Discourse Theme / ci (push) Failing after 1s
- 为用户卡片添加背景色过渡动画
- 实现悬停时背景色变化效果
- 使用 CSS 变量保持主题一致性
- 优化用户体验的视觉反馈
2026-02-26 14:44:18 +08:00
shiran 241f251c3a refactor(style): 重构CSS类选择器以优化样式应用
Discourse Theme / ci (push) Failing after 0s
- 移除 .user-main .about.collapsed-info .details 从背景色透明样式规则中
- 将 .user-main .about.collapsed-info .details 添加到背景变量样式规则中
- 优化了CSS选择器的分组和结构
- 统一了相关组件的视觉样式表现
2026-02-26 14:40:55 +08:00
shiran 9154d84663 style(css): 格式化CSS选择器以符合团队样式指南
Discourse Theme / ci (push) Failing after 0s
- 将长的选择器列表按行分割以提高可读性
- 在每个选择器后添加适当的换行和缩进
- 遵循团队的代码格式化规范
- 保持CSS代码的一致性和整洁性
- 便于后续维护和审查
2026-02-26 14:37:52 +08:00
shiran 7d30ebd133 fix(style): 更新CSS选择器以正确应用背景样式
Discourse Theme / ci (push) Failing after 0s
- 修改了.edit-category类的选择器定位方式
- 从直接类选择器改为ID选择器配合后代选择器
- 确保编辑分类页面的背景色和圆角样式正确应用
- 保持原有的毛玻璃效果和透明度设置不变
2026-02-26 14:33:10 +08:00
shiran 3330d0056b docs(theme): 更新主题描述为中文
Discourse Theme / ci (push) Failing after 0s
- 将主题描述从英文更改为中文描述
- 移除已弃用的提示信息
- 简化描述内容为自制二次元主题说明
2026-02-26 14:30:56 +08:00
shiran 4f5ff0fb73 style(theme): 更新CSS样式以包含新类别编辑组件
Discourse Theme / ci (push) Failing after 0s
- 为.edit-category类添加白色半透明背景
- 应用相同的边框圆角和背景模糊效果
- 确保新组件与其他页面元素保持一致的视觉风格
2026-02-26 14:25:06 +08:00
shiran 45baef8a01 style(scss): 隐藏 Discourse 标识显示
Discourse Theme / ci (push) Failing after 2s
- 在 self.scss 中新增 .powered-by-discourse 类
- 设置 display: none 属性隐藏相关元素
- 保持原有的用户内容背景样式设置
- 添加空行优化代码结构可读性
2026-02-24 09:45:30 +08:00
shiran 3e2d5f455c style(theme): 更新CSS样式以支持用户目录页面
Discourse Theme / ci (push) Failing after 0s
- 为.users-directory类添加背景色、圆角和模糊效果样式
- 保持与其他页面组件一致的视觉风格
2026-02-24 09:38:43 +08:00
shiran 97d33974c9 style(theme): 更新CSS样式以包含新类名
Discourse Theme / ci (push) Failing after 1s
- 为.show-badge类添加背景色和圆角样式
- 统一应用半透明白色背景和模糊效果
- 保持与其他容器元素一致的视觉风格
- 确保新类名在主题系统中的兼容性
2026-02-24 09:37:07 +08:00
shiran 14b8fd2048 style(scss): 添加溢出隐藏样式
Discourse Theme / ci (push) Failing after 2s
- 在用户内容区域添加 overflow: hidden 样式
- 防止内容超出容器边界显示
2026-02-24 09:23:39 +08:00
shiran f6cbd5eccf style(css): 更新样式表中的选择器以增强主题一致性
Discourse Theme / ci (push) Failing after 0s
- 为 .admin-detail 添加背景颜色重置规则
- 将 .admin-detail 替换为 .admin-plugin-config-page__content 以改进插件配置页面样式
- 确保主题背景和边框半径在整个管理界面中保持一致
2026-02-24 09:16:24 +08:00
shiran d11c87a060 style(css): 更新CSS选择器样式
Discourse Theme / ci (push) Failing after 1s
- 将.admin-plugin-config-page__content选择器替换为.admin-detail
- 保持相同的背景色、圆角和阴影样式定义
2026-02-24 09:13:39 +08:00
shiran f876f44c84 style(scss): 更新样式表以支持管理员插件配置页面内容区域
Discourse Theme / ci (push) Failing after 0s
- 为 .admin-plugin-config-page__content 类添加背景、边框半径和阴影样式
- 统一管理插件配置页面内容区域的视觉外观
- 保持与其他内容区域样式的一致性
2026-02-24 09:11:48 +08:00
shiran b1d9fdd058 style(css): 更新样式文件中的选择器定义
Discourse Theme / ci (push) Failing after 1s
- 为 .search-header 添加与 .topic-post 和 .post-list-item 相同的背景、圆角和阴影样式
- 统一搜索头部与其他帖子项目的视觉外观
- 保持一致的设计风格和用户体验
2026-02-24 09:05:18 +08:00
shiran cddf2f9f84 style(theme): 更新搜索容器样式并调整背景模糊效果
Discourse Theme / ci (push) Failing after 2s
- 为搜索容器添加白色半透明背景
- 将背景模糊效果从 16px 增加到 32px
- 保持现有的边框圆角和阴影效果
- 确保所有相关页面元素具有一致的视觉样式
2026-02-24 09:03:55 +08:00
shiran 57cfd7eaae style(layout): 更新CSS选择器以改进页面背景样式
Discourse Theme / ci (push) Failing after 0s
- 添加.contents.clearfix.body-page选择器到现有样式规则
- 保持背景颜色透明度和边框半径一致性
- 维持毛玻璃效果以确保视觉统一性
2026-02-24 09:00:46 +08:00
shiran c12464bc7d style(layout): 更新盒子样式和添加用户内容背景
Discourse Theme / ci (push) Failing after 0s
- 调整盒子内边距从 0 12px 到 16px 12px
- 添加 .user-content 类设置背景颜色为无样式
2026-02-24 08:43:20 +08:00
shiran 1d94f2ed88 style(css): 更新主题帖子样式选择器
Discourse Theme / ci (push) Failing after 0s
- 扩展 .topic-post.clearfix.regular 选择器以包含 .post-list-item.user-stream-item
- 保持相同的背景、圆角和阴影样式属性
- 确保用户流项目具有与主题帖子相同的视觉外观
2026-02-23 09:09:23 +08:00
shiran a8f730a1f6 style(topic-cards): 移除悬停状态下的触摸设备样式
Discourse Theme / ci (push) Failing after 1s
- 移除了 .discourse-no-touch 类的选择器包装
- 简化了悬停时的背景和阴影样式应用逻辑
- 保持了选中状态样式的完整性
2026-02-23 09:02:49 +08:00
shiran a45b6c0cbc style(topic-post): 添加主题帖子样式定义
Discourse Theme / ci (push) Failing after 0s
- 为 .topic-post.clearfix.regular 类添加背景色样式
- 设置圆角边框样式
- 添加阴影效果
- 定义外边距和内边距
- 设置相对定位样式
2026-02-23 08:57:23 +08:00
shiran 808d195332 style(scss): 更新样式选择器以支持主题列表头部
Discourse Theme / ci (push) Failing after 0s
- 将 #list-area 选择器扩展为同时包含 .topic-list-header 类
- 移除背景颜色的强制设置以支持主题定制
- 保持现有的阴影效果和其他样式属性不变
2026-02-22 11:42:58 +08:00
shiran 8b0584a87e style(scss): 更新样式表以改进用户界面元素的边框半径和背景色
Discourse Theme / ci (push) Failing after 1s
- 为 .user-content 和 .details 类添加边框半径变量
- 将 .regular.ember-view, .user-main, .reviewable, .admin-content
  的背景色设置为带透明度的白色
- 为多个用户界面组件统一应用边框半径和背景模糊效果
- 调整 CSS 选择器顺序以优化样式覆盖逻辑
2026-02-21 11:12:36 +08:00
shiran b3f2686970 style(theme): 更新CSS选择器以改进页面样式
Discourse Theme / ci (push) Failing after 0s
- 为.regular.ember-view, .user-main, .user-content, .details, .reviewable, .admin-content添加背景色
- 为相关元素添加圆角样式
- 为页面内容添加毛玻璃效果
2026-02-21 10:19:20 +08:00
shiran 09e5f27aaa style(scss): 更新CSS选择器以适配更多页面元素
Discourse Theme / ci (push) Failing after 0s
- 为.regular.ember-view, .user-main, .reviewable, .admin-content类添加背景样式
- 统一应用白色半透明背景、圆角和模糊效果
- 替换原有的.container选择器为更通用的页面容器类名
2026-02-21 10:16:07 +08:00
shiran ba0a46820a style(css): 更新样式类选择器以包含容器元素
Discourse Theme / ci (push) Failing after 0s
- 将 .container 类添加到 .regular.ember-view 选择器中
- 保持相同的背景颜色、边框半径和背景模糊效果
- 确保容器元素具有与现有视图组件相同的视觉样式
2026-02-21 10:13:39 +08:00
shiran c472e537a3 style(topic-cards): 更新主题卡片样式以使用新的颜色变量和阴影效果
Discourse Theme / ci (push) Failing after 1s
- 将背景渐变从 --d-sidebar-active-background 替换为 --active-color
- 更新悬停状态的背景色为 --active-color
- 修改盒阴影语法以提高兼容性
- 调整悬停状态的边框颜色透明度
- 简化了阴影效果的数值表示方式
2026-02-21 10:11:28 +08:00
shiran ac2bb8084b style(topic-cards): 更新主题卡片边框颜色样式
Discourse Theme / ci (push) Failing after 0s
- 将主题卡片左侧边框颜色从变量 --d-button-danger-icon-color 改为 #0008
2026-02-21 10:07:22 +08:00
shiran b83d1c4de9 style(css): 移除梦幻效果并优化主题样式
Discourse Theme / ci (push) Failing after 0s
- 删除了全局的梦幻光晕效果和相关动画
- 移除了话题卡片的渐变背景和发光效果
- 简化了列表容器的背景样式和阴影效果
- 调整了话题卡片悬停状态的视觉效果
- 优化了分类标签的颜色配置方式
- 更新了选中状态的边框颜色和透明度设置
2026-02-21 10:03:46 +08:00
shiran 1fb6a7b5a1 Merge remote-tracking branch 'origin/main'
Discourse Theme / ci (push) Failing after 0s
2026-02-21 09:59:32 +08:00
shiran d87e9a30d5 style(scss): 添加主出口包装器的z-index样式
- 在self.scss中添加#main-outlet-wrapper的z-index: 0样式
- 保持其他样式定义不变
2026-02-21 09:59:21 +08:00
shiran baf01610e4 style(theme): 更新主题样式和视觉效果
Discourse Theme / ci (push) Failing after 1s
- 替换梦幻光效变量为基于三级颜色的新配色方案
- 调整模糊滤镜强度从48px增加到56px
- 修改径向渐变透明度值以优化视觉层次
- 在列表容器中添加隔离层以改善渲染性能
- 更新话题卡片背景渐变使用RGB颜色变量
- 调整阴影效果和透明度以增强深度感
- 优化选中状态边框颜色使用三级颜色变量
- 添加悬停状态变换效果提升交互体验
2026-02-20 21:54:43 +08:00
shiran 10639d6ddf style(topic-cards): 更新话题卡片悬停样式
Discourse Theme / ci (push) Failing after 1s
- 移除旧的背景渐变效果,改用 --active_color 变量
- 简化阴影效果,从双层阴影改为单层阴影
- 添加左侧边框以增强视觉效果
- 移除悬停时的垂直位移变换效果
2026-02-20 21:48:19 +08:00
shiran ff29cd0652 style(ui): 添加梦幻视觉效果和优化话题卡片样式
Discourse Theme / ci (push) Failing after 1s
- 新增梦幻发光效果变量和动画实现
- 为主题背景添加浮动光晕装饰元素
- 重构话题卡片渐变背景和交互效果
- 实现卡片悬停时的平滑变换动画
- 添加响应式设计和可访问性支持
- 优化主题样式层级和渲染性能
2026-02-20 21:39:22 +08:00
shiran 48c4a39647 style(css): 统一搜索容器样式并移除话题卡片变换效果
Discourse Theme / ci (push) Failing after 0s
- 为搜索容器添加与列表控件相同的圆角样式
- 移除话题卡片的 translateY 变换效果以简化视觉表现
2026-02-20 21:34:22 +08:00
shiran aafa92430a style(scss): 更新样式规则以改进背景和阴影属性
Discourse Theme / ci (push) Failing after 1s
- 为 regular.ember-view 添加 !important 修饰符以确保背景色优先级
- 移除 box-shadow 属性上的 !important 修饰符以优化样式继承
- 保持模糊效果和内边距设置不变
2026-02-20 21:32:11 +08:00
shiran 0ca608ab91 style(scss): 添加重要样式覆盖规则
Discourse Theme / ci (push) Failing after 0s
- 在box-shadow属性上添加!important标记以确保样式覆盖
- 保持原有的背景色、圆角和模糊效果设置不变
- 确保元素具有24px的内边距设置
2026-02-20 21:30:57 +08:00
shiran bee984881e refactor(styles): 更新选择器以提高样式一致性
Discourse Theme / ci (push) Failing after 1s
- 将 ID 选择器 #ember155 替换为类选择器 .regular.ember-view
- 保持相同的背景颜色、边框圆角和背景模糊效果
- 提高样式的可重用性和维护性
2026-02-20 21:28:33 +08:00
shiran ea810552db style(homepage): 更新背景和组件样式
Discourse Theme / ci (push) Failing after 1s
- 添加固定背景附件属性
- 为列表控件添加阴影效果
- 移除话题列表头部背景色
- 更新欢迎横幅内边距和阴影
- 为 ember155 元素添加背景、圆角、模糊滤镜和阴影
2026-02-20 21:26:03 +08:00
shiran 275945ce1a feat(common): 添加自定义样式模块
Discourse Theme / ci (push) Failing after 1s
- 在 common.scss 中导入新的 self 样式模块
- 扩展公共样式体系以支持个性化定制需求
2026-02-20 21:07:47 +08:00
shiran 6119211ff4 style(ui): 优化话题列表界面样式
Discourse Theme / ci (push) Failing after 1s
- 为话题列表头部添加 z-index 层级控制
- 调整话题列表头部间距和内边距
- 设置话题列表数据项颜色、字体大小和粗细
- 将话题列表数据项设为大写字母并添加背景透明效果
- 为默认话题列表项添加圆角边框
- 重新定位批量选择控件位置并更新样式
- 更新批量选择按钮的圆角样式
- 新增自定义背景图片和容器样式
- 为主题卡片渐变背景替换为线性渐变效果
- 调整主题卡片悬停状态下的背景色和阴影效果
- 为主题卡片添加左侧边框高亮效果
- 移除废弃的主题卡片相关样式代码
2026-02-20 21:04:14 +08:00
shiran 2e967617af style(topic-cards): 更新卡片样式添加圆角和模糊效果
Discourse Theme / ci (push) Failing after 1s
- 为话题卡片添加 border-radius 样式
- 实现 backdrop-filter 模糊背景效果
- 提升卡片视觉层次和美观度
2026-02-20 13:21:14 +08:00
shiran 3efe032ebf style(topic-cards): 移除卡片背景遮罩层并重置列表区域背景色
Discourse Theme / ci (push) Failing after 1s
- 移除了卡片元素的负z-index背景遮罩层
- 为列表区域添加了背景色重置样式
- 解决了背景颜色覆盖问题
- 优化了卡片显示效果
2026-02-20 13:19:24 +08:00
shiran 7cdbcb539e feat(theme): 添加首页背景图片功能
Discourse Theme / ci (push) Failing after 0s
- 在设置中新增 home_bg_image 配置选项
- 实现主题 SCSS 中的背景图片样式逻辑
- 添加对首页背景图片的条件渲染支持
- 集成上传功能以支持自定义背景图片
- 设置默认值为空字符串以避免初始加载问题
- 添加中文描述文档以便用户理解功能用途
2026-02-20 13:16:48 +08:00
shiran ddf40963aa style(topic-cards): 优化卡片样式和过渡效果
Discourse Theme / ci (push) Failing after 1s
- 将过渡属性从特定属性改为 all 以简化动画效果
- 移除复杂的径向渐变背景和遮罩组合效果
- 添加列表容器的基础样式定义
- 为列表容器添加半透明白色背景层
2026-02-20 13:11:43 +08:00
shiran d3bb44d636 refactor(horizon): 移除管理员通知并简化主题初始化逻辑
Discourse Theme / ci (push) Failing after 1s
- 删除了管理员使用Horizon主题时的全局通知功能
- 移除了主题ID获取和URL构建相关代码
- 简化了API初始化器中的条件判断逻辑
- 保留了实验性屏幕组件和用户颜色选择器的渲染功能
2026-02-20 09:41:57 +08:00
shiran a1bdaa8052 chore(theme): 更新主题配置信息
Discourse Theme / ci (push) Failing after 0s
- 修改主题名称为 Horizon-shiran
- 更新作者信息为 shiran
- 移除 about_url 链接
- 更新 license_url 指向新的代码仓库地址
- 移除 learn_more 链接
- 保持主题版本号为 0.0.1
- 保留 svg 图标配置
2026-02-20 09:40:08 +08:00
shiran 9e9ec24d56 style(topic-cards): 更新话题卡片样式以增强视觉效果
Discourse Theme / ci (push) Failing after 1s
- 移除话题列表项的底部边框
- 替换原有的阴影效果为更现代的多层阴影设计
- 移除卡片边框并添加渐变背景遮罩层
- 添加悬停时的变换动画和阴影过渡效果
- 优化选中状态的阴影和高亮显示
- 调整悬停和选中状态的颜色与透明度参数
2026-02-20 09:36:53 +08:00
shiran f9130b87b5 docs(readme): 更新 README 文档以详细说明 Horizon 主题源码结构
Discourse Theme / ci (push) Failing after 1s
- 添加项目作用说明,包括视觉改造、交互增强、页面体验调整等功能描述
- 新增目录结构详解,涵盖 .github、assets、common、desktop、javascripts 等目录作用
- 添加 locales、scss、screenshots、spec、test 等目录的详细功能说明
- 新增根目录文件作用介绍,包括 about.json、settings.yml、package.json 等配置文件
- 添加关键功能对应关系表格,便于快速定位配色切换、侧边栏按钮、卡片化等功能实现
- 保留原 DEPRECATED 说明,并补充当前仓库的学习参考价值说明
2026-02-20 09:32:21 +08:00
Martin Brennan c01e0da0ea DEV: Deprecate theme, add admin notice (#190)
The Horizon theme will soon be installed by default in Discourse, and
all development will be done there. This commit shows a warning for
admins telling them to switch to the new theme.
2025-06-30 09:22:29 +10:00
chapoi 35d4103757 UX: hide category image on categories page (#192) 2025-06-27 18:25:48 +02:00
Martin Brennan abf22a6668 UX: Only hide welcome banner on mobile devices (#189) 2025-06-23 12:02:35 +02:00
chapoi c6000c996f UX: show replies in shortened form (#187)
![CleanShot 2025-06-20 at 09 52
13@2x](https://github.com/user-attachments/assets/213416c6-24a6-41e1-84d2-04d157f11999)
![CleanShot 2025-06-20 at 09 52
25@2x](https://github.com/user-attachments/assets/34384e2c-6f4e-4933-ae35-d47102982db1)
2025-06-20 11:39:31 +02:00
chapoi ffa86a0c46 UX: hide welcome banner (#188)
Until we move forward with the search-banner on mobile, the
welcome-message feels out of place. Hiding it for now.
2025-06-20 11:39:20 +02:00
Martin Brennan bb512645d1 UX: Unhide topics footer-message (#180)
This needs to be unhidden so the changes in the following core PR are
visible in horizon:

https://github.com/discourse/discourse/pull/32669
2025-06-19 12:56:37 +02:00
chapoi dac23d544c UX: Categories restyling (#184)
Some CSS sprinkling for our most used category list formats:
### Desktop: Categories and Latest Topics 
| Default | Horizon |
|--------|--------|
| ![CleanShot 2025-06-17 at 17 28
45@2x](https://github.com/user-attachments/assets/4babf4d4-9c25-4780-bb72-c37b13d6f843)|
![CleanShot 2025-06-17 at 17 28
08@2x](https://github.com/user-attachments/assets/741a24fe-fca4-4eb8-97c9-96f5eb30b575)
|

### Desktop: Boxes with Subcategories
| Default | Horizon |
|--------|--------|
| ![CleanShot 2025-06-17 at 15 09
07@2x](https://github.com/user-attachments/assets/21e71f3b-b795-44d8-b56c-7edbe8fc465c)
| ![CleanShot 2025-06-17 at 17 29
46@2x](https://github.com/user-attachments/assets/41707610-cd09-4ebd-8fee-0f637e154fbf)
|

### Mobile: Categories with Featured Topics
| Default | Horizon |
|--------|--------|
| ![CleanShot 2025-06-17 at 17 30
53@2x](https://github.com/user-attachments/assets/665b6f19-c3d3-4438-8960-2170d0c69af3)
| ![CleanShot 2025-06-17 at 17 30
27@2x](https://github.com/user-attachments/assets/ca0fd595-1b0d-4ee9-b805-c538e4cdbc90)
|
2025-06-18 15:23:24 +02:00
chapoi 1e5f71473a UX: remove default select state for keyboard nav on topic cards (#186)
The left-border select state when using keyboard navigation is already
overruled in Horizon, but when bulk-select is enabled, this still showed
up:

![CleanShot 2025-06-18 at 12 28
16@2x](https://github.com/user-attachments/assets/e1b9bfbc-aceb-429a-8890-fb56f7e12048)

Fixed:
![CleanShot 2025-06-18 at 12 29
09@2x](https://github.com/user-attachments/assets/40572de6-a316-4f7b-8786-9040f513b6c8)
2025-06-18 15:22:31 +02:00
chapoi 6d8415579e UX: fix topic cards layout for messages with has-replies class (#183)
The `grid-template-areas` were not correct on the messages page

---------

Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Martin Brennan <martin@discourse.org>
2025-06-18 13:34:26 +10:00
chapoi 2bcd04d4f4 UX: topic cards v3 (#182)
* Bringing back the OP
* Removed reason why topic appears (again) in topic list (="activity")
* Removed likes
* New layout with indention + moved all elements left (on desktop)

| Mobile | Desktop |
|--------|--------|
| ![CleanShot 2025-06-13 at 11 00
19@2x](https://github.com/user-attachments/assets/f43a773d-c8ba-4573-b16a-940e9fc3d901)
| ![CleanShot 2025-06-13 at 11 05
10@2x](https://github.com/user-attachments/assets/6bb152df-9ed3-4866-8c0a-95ddf94cd773)
|
| ![CleanShot 2025-06-13 at 11 02
25@2x](https://github.com/user-attachments/assets/3d9fb41c-a894-4b07-8737-6bd03e513f2f)
| ![CleanShot 2025-06-13 at 11 06
59@2x](https://github.com/user-attachments/assets/c54b9efe-fd1d-40aa-b8ad-2e4eab54eb90)
|
| ![CleanShot 2025-06-13 at 11 03
28@2x](https://github.com/user-attachments/assets/cdad49e8-ae6d-4f2c-9ef5-f6fa42705764)
| ![CleanShot 2025-06-13 at 11 07
10@2x](https://github.com/user-attachments/assets/91fee5ad-71b7-400c-a2c7-80339438b8de)
|
| ![CleanShot 2025-06-13 at 11 04
09@2x](https://github.com/user-attachments/assets/85296a16-f052-4787-a260-81fa54cd6191)
| ![CleanShot 2025-06-13 at 11 07
24@2x](https://github.com/user-attachments/assets/ffcaecb0-767a-4a72-8244-a3baa56d3cc2)
|
| ![CleanShot 2025-06-13 at 11 04
26@2x](https://github.com/user-attachments/assets/48a05ef5-366f-4543-bf0e-441ecae39877)
| ![CleanShot 2025-06-13 at 11 04
48@2x](https://github.com/user-attachments/assets/50499b4d-60bf-4b41-8a42-6fba8e0a41d8)
|

---------

Co-authored-by: Jordan Vidrine <jordan@jordanvidrine.com>
2025-06-13 11:08:57 +02:00
Jordan Vidrine 05416abe70 DEV: Topic creator fix (#181) 2025-06-11 14:03:52 -05:00
chapoi 14aa72ad99 UX: Mini fixes and tweaks (#179)
* Changing the category & tag dropdown back into their original form.
The breadcrumb idea isn't working well.

| BC | AC |
|--------|--------|
| ![CleanShot 2025-06-09 at 18 59
37@2x](https://github.com/user-attachments/assets/cbeb3aaf-ad0e-4085-8548-58ea0a521c95)
| ![CleanShot 2025-06-09 at 18 57
33@2x](https://github.com/user-attachments/assets/15db752b-4983-4b7f-b6f8-9a8ded9e6f9f)
|

* Alignment fix in chat navbar drawer

| BC | AC |
|--------|--------|
| ![CleanShot 2025-06-09 at 18 59
18@2x](https://github.com/user-attachments/assets/38c7dcee-dc77-4a44-ae8d-5ecb7910536b)
| ![CleanShot 2025-06-09 at 18 58
36@2x](https://github.com/user-attachments/assets/be699f88-4e5e-4d8c-ab4d-f6d1eca93037)
|
2025-06-09 19:41:18 +02:00
Jarek Radosz bf9fe07f67 DEV: Update linting config and run gjs-codemod (#177) 2025-06-06 12:15:57 +01:00
Jordan Vidrine 31249c4f27 UX: Remove unused line & fix ipad safari browser (#176) 2025-06-04 14:55:25 -05:00
Kris 581332c001 UX: fix mobile timeline in PWA (#174) 2025-06-04 14:55:02 -04:00
chapoi f5c4403423 UX: increase spacing of topic cards (#175)
Slightly bigger spacing to match the bigger avatars (bigger elements =>
more spacing to balance it out)
2025-06-04 16:04:11 +02:00
chapoi b72a3c1e95 UX: Topic cards v2 (#173)
This is the second iteration on the topic card design, in which we bring
back the OP and change the layout.

**Changes**:
* Show OP avatar
* Remove activity avatar and replace by reply icon
* Remove activity icon background
* Move category tag to top left
* Replace long activity copy ("…replied at…") with dot separator
* Change date formatting to `tiny`
* Adjust bulk select styling to new layout + align checkbox to top on
mobile VS keep centred on desktop

* Why: On desktop, the avatar is taking 2 lines (usually) and aligning
the checkbox vertically looks nice. Exception for excerpts, but since
that's only available for pinned topics atm that's a low occurrence. On
mobile, the topic card is 3 lines, with a smaller avatar, which makes
the checkbox "float" around a bit when centred. Hence aligning it to the
top, which for solid avatars aligns nicely too.

* CSS refactor: grid, breakpoints

Messages/bookmarks have not been changed.

| Description | Visual |
|--------|--------|
| Large topic list | ![CleanShot 2025-06-02 at 17 37
35@2x](https://github.com/user-attachments/assets/f232058e-dbf6-4689-abe3-65970464a3e3)|
| Large bulk edit | ![CleanShot 2025-06-02 at 17 37
17@2x](https://github.com/user-attachments/assets/03d86b5f-d62b-4449-9c0b-452ceb8be60c)
|
| Medium topic list | ![CleanShot 2025-06-02 at 17 39
01@2x](https://github.com/user-attachments/assets/80739641-cf8f-4095-938f-9781cac57a7d)
|
| Medium bulk edit | ![CleanShot 2025-06-02 at 17 39
24@2x](https://github.com/user-attachments/assets/6e9045af-734a-4f3f-830a-e03a2f06fdd8)
|
| Small topic list | ![CleanShot 2025-06-02 at 17 39
44@2x](https://github.com/user-attachments/assets/eeca80bc-6863-4026-8f19-b1b5cf6848f3)
|
| Small bulk edit | ![CleanShot 2025-06-02 at 17 40
00@2x](https://github.com/user-attachments/assets/cde7be08-cde2-4ff2-b81b-328d3d7be848)
|
| Messages page (remains unchanged) | ![CleanShot 2025-06-02 at 17 20
37@2x](https://github.com/user-attachments/assets/6512bfe9-a699-4c67-b709-166540ee6fde)
|
| Bookmark page (remains unchanged) | ![CleanShot 2025-06-02 at 17 21
01@2x](https://github.com/user-attachments/assets/f8f43638-e911-49cb-a0d5-ebcb51ccfba4)
|
2025-06-04 14:50:41 +02:00
Jordan Vidrine 0ed3912d63 UX: Fix topic card messages (#172) 2025-05-30 08:39:39 -05:00
Jordan Vidrine fc6d1b5b9d UX: RTL positioning of boxed view (#170) 2025-05-28 15:42:57 -05:00
Ella E. bd93d46ef4 DEV: Add screenshots (#169) 2025-05-23 21:33:01 -06:00
Kris 04d8684b59 UX: fix new topic badge in topic list (#167)
The theme implements this in a centralized way, so we need to remove the
core implementation.

before:


![image](https://github.com/user-attachments/assets/a9b37f79-d464-43e9-9298-3607180162ec)


after:


![image](https://github.com/user-attachments/assets/bd3c79b5-6371-4439-86a2-5f91e44f04ca)
2025-05-21 10:54:24 -04:00
Kris 79be7731b7 UX: adjust event date alignment with topic titles (#165)
this regressed slightly with core changes 

before:

![image](https://github.com/user-attachments/assets/550df0f8-fb8d-4af3-b4ec-5a61834d8a45)


after:

![image](https://github.com/user-attachments/assets/5c06f32d-ee31-444e-90f7-c31f9c44f642)
2025-05-21 09:59:21 -04:00
David Taylor fe1cb262dc UX: Allow clicking anywhere on the topic-list card (#166) 2025-05-21 13:37:21 +01:00
chapoi 25cc070a5b UX: fix low z-index for popup after changes to composer-drawer interaction (#164)
Fixing:
![CleanShot 2025-05-20 at 11 58
11@2x](https://github.com/user-attachments/assets/68611ead-71bf-42bf-bd87-183f589f4b82)

Consequence of #161
2025-05-20 14:22:21 +02:00
Kris 7982d60967 UX: add compatibility with the top contributors sidebar (#162)
Improves compatibility with
https://meta.discourse.org/t/top-contributors-sidebar/215110

Before:

![image](https://github.com/user-attachments/assets/08994458-0322-4725-a66b-0c91712e3a2a)


After: 

![image](https://github.com/user-attachments/assets/de231b57-d6da-42c0-852e-2bf915ee929e)

---------

Co-authored-by: Jarek Radosz <jarek@cvx.dev>
2025-05-19 11:26:11 -04:00
chapoi 90eae2d3f1 Chat drawer and peakmode (#161)
To avoid very strange positioning and sizing, I'm opting to keep the
chat in front of the composer, when in peak-mode.
Still not ideal, but better than before.

![CleanShot 2025-05-14 at 13 11
16@2x](https://github.com/user-attachments/assets/9b28f097-a63b-4bbb-a016-68cbcd04ee3c)
⬇️ 
![CleanShot 2025-05-14 at 13 10
57@2x](https://github.com/user-attachments/assets/10b9c17e-1207-4775-8933-0f6aca8c3ab6)

Due to the way peakmode positions itself, it's impossible to place the
chat flush next to it. And due to the way resizing works (frop the top
left, anchored right), it also can't be placed on any left-handed
alignment.
2025-05-16 12:24:05 +02:00
Joffrey JAFFEUX 948c60d656 FIX: do not error when no palettes are available (#160)
To repro this you had to unchecked all the "Color palette can be
selected by users" from the colors tab.
2025-05-12 19:18:15 -03:00
Kris 86d0c03b03 UX: handle opening composer from slide-in hamburger menu (#159) 2025-05-12 12:04:38 -04:00
Kris d749920db7 UX: improve mobile event badge positioning (#156) 2025-05-10 13:46:15 -04:00
Keegan George eda0db294d UX: Improve styles for add translation composer view (#158)
## 🔍 Overview
This update ensures styles in composer look appropriate for the new
composer add translation view (recently added here:
https://github.com/discourse/discourse/pull/32564)


## 📷 Screenshots

### ← Before
<img width="1473" alt="Screenshot 2025-05-08 at 11 58 54"
src="https://github.com/user-attachments/assets/76fec3f6-1cbf-4b57-a765-c2cf003ba177"
/>

### → After
<img width="1476" alt="Screenshot 2025-05-08 at 11 58 42"
src="https://github.com/user-attachments/assets/f17e8dc5-3230-4a1f-9072-28a3c7415958"
/>
2025-05-08 12:17:42 -07:00
Jarek Radosz c2b71c04a8 DEV: Update linting (#153) 2025-05-06 16:53:12 +01:00
Kris ec532d356e UX: exclude wizard from #main-outlet background styling (#155)
Only a tiny sliver of the background shows currently, which seems
accidental

Before:

![image](https://github.com/user-attachments/assets/815b9dec-7708-44a1-b360-7394e42cc4f6)


After:

![image](https://github.com/user-attachments/assets/b2eaf893-3e41-4321-b836-873b691589c5)
2025-05-05 12:35:14 -04:00
Kris 755a666dae UX: hide bootstrap mode from header (#154)
There are multiple header elements that get in the way, and we can't
really manage the position of this button well without a better
full-width solution... so I think it makes sense to hide it for now


Before:

![image](https://github.com/user-attachments/assets/07009232-d188-4a5f-9381-0e1d4479512b)

After: 

![image](https://github.com/user-attachments/assets/91a0f01a-3d12-4f89-9d7f-0050abdd47e9)
2025-05-05 12:35:00 -04:00
Keegan George 4b159e9296 UX: New topic button shouldn't appear in AI conversations page (#152)
## 🔍 Overview
This update ensures that the sidebar new topic button isn't shown on the
AI conversations sidebar. It also styles the new conversation button to
make use of Horizon's accent color

## 📸 Screenshots

### ← Before
<img width="1228" alt="Screenshot 2025-05-02 at 14 16 41"
src="https://github.com/user-attachments/assets/b187d31e-881a-4c34-b663-f4b55b8bc565"
/>

### → After
<img width="1232" alt="Screenshot 2025-05-02 at 14 15 34"
src="https://github.com/user-attachments/assets/987cfba3-ad7c-49a9-80d8-14c3e52dd5c0"
/>
2025-05-05 09:27:28 -07:00
Kris e53184ac28 UX: fix experimental new new positioning (#151)
These styles were added for bulk select positioning, but turns out they
weren't needed anyway

before:

![image](https://github.com/user-attachments/assets/bf752846-cb51-4872-9cb7-2d98ab7f5c8f)

after:

![image](https://github.com/user-attachments/assets/4a25c776-b88c-4be6-b186-31973c6b5e05)
2025-04-25 11:35:00 -04:00
Kris a6293aa24b UX: text logo line-height fix (#150)
Minor adjustment to avoid clipping descenders 


before:

![image](https://github.com/user-attachments/assets/bc68416b-ab04-4a62-8bff-ec8164284380)


after: 

![image](https://github.com/user-attachments/assets/30296e9c-4e8d-446f-8ee4-f0583e6c3e68)
2025-04-24 14:22:07 -04:00
Kris 45cc99a2e0 UX: better full-width support for wide logos (#149)
Helps avoid situations like this:


![image](https://github.com/user-attachments/assets/78adec74-8fb7-457f-b592-da1b56a98b1a)


Some examples...


text-logos

![image](https://github.com/user-attachments/assets/c87333cb-727a-4167-af76-a5db0b3cd20c)

![image](https://github.com/user-attachments/assets/8cc62ab9-4f3e-4697-a763-851dc21aa2ec)

![image](https://github.com/user-attachments/assets/e36ffa7e-a3a9-463a-b448-833da2b3bc69)

image-logos

![image](https://github.com/user-attachments/assets/962f33c1-d83c-4d74-a707-ec1fb867d557)

![image](https://github.com/user-attachments/assets/0014505a-bfab-4616-962a-c1a5fa30938e)

![image](https://github.com/user-attachments/assets/32d9730a-1a43-49ac-b160-b6dd610f4482)
2025-04-24 14:04:06 -04:00
Jordan Vidrine 806b800f1f UX: adjust styles to meet core changes (#148) 2025-04-23 14:44:00 -05:00
Jordan Vidrine 70af5fc68a UX: Adjust spacing for more room (#146) 2025-04-21 16:36:03 -05:00
Kris b1a9389a04 UX: minor breakpoint gap fix (#147)
Reported here:
https://meta.discourse.org/t/help-us-test-horizon-our-newest-theme/360484/55?u=awesomerobot

We have a 1px gap here where we get kind of a half-container 

Before:

![image](https://github.com/user-attachments/assets/0d355156-c579-418d-a1d1-9d624c61bc12)



After:

![image](https://github.com/user-attachments/assets/ce96bf6b-c8a8-4fd2-b5b0-56d37382284d)
2025-04-18 14:08:34 -04:00
Martin Brennan f9603a24ea DEV: Rename search -> welcome banner (#144)
Horizon is targeting the welcome banner not the search component
anymore, update CSS class names and rename the file to make this clearer
2025-04-18 12:23:44 +10:00
Jordan Vidrine bf2fb463ae UX: Modernize spacing a bit (#145) 2025-04-17 21:16:43 -05:00
Martin Brennan 07113ca324 DEV: Slight refactor and add specs for composer peek (#142)
Followup cf9fd864dd
2025-04-18 09:12:43 +10:00
Kris d67ec3ac5f FIX: remove SCSS mixed declarations (#143)
This fixes the SCSS mixed declaration errors (most noticeable while
running rspec)
2025-04-17 17:27:13 -04:00
Kris cf9fd864dd DEV: implement composer peek mode directly in theme (#141)
This implements the [composer
peek](https://github.com/discourse/composer-peek) component directly
into the theme, and makes some minor adjustments to match theme styles:


![image](https://github.com/user-attachments/assets/e4272a11-6570-4392-945f-c509cf4debd6)
2025-04-16 17:10:23 -04:00
Kris 36899bbbaa UX: make theme compatible with AI gists (#140)
Before (only pinned topic excerpts, no gist toggle):

![image](https://github.com/user-attachments/assets/7a1b78b8-e115-4c96-9ebf-52d2c1237eea)


After (gists can be toggled on): 

![image](https://github.com/user-attachments/assets/9e6786be-3817-4420-8142-1c5f7cad54ea)


This puts the gists in the same place as the theme places excerpts and
uses the same styles. It also follows the theme pattern of hiding
excerpts/gists on mobile.
2025-04-16 15:34:52 -04:00
Jordan Vidrine 651cf2794c UX: remove square avatar from topic posts (#139) 2025-04-16 12:04:41 -05:00
Jordan Vidrine e9e166ca3a FIX: Search header index (#138) 2025-04-15 20:46:27 -05:00
Kris 81141cc66f UX: update about.json, readme (#137)
Just a little bit of metadata cleanup
2025-04-15 09:19:14 -04:00
Martin Brennan b23c4764a2 DEV: Put full width styles into their own file (#132)
Followup f1d5b69293

We want to make it super clear that this is to be removed when we merge
full width into core, keeping it in desktop.scss together with other
styles will make that harder.
2025-04-15 13:46:20 +10:00
Jordan Vidrine 7ab29303dd UX: Mobile composer fixes (#136) 2025-04-14 16:33:30 -05:00
Kris 776071fdb0 UX: adjust disabled create button tooltip styles (#135) 2025-04-14 16:22:17 -05:00
Jordan Vidrine 2d193b4d7a UX: Quick fixes (#134) 2025-04-14 15:52:12 -05:00
Jordan Vidrine 24165a53a6 UX: Login layout fixes (#133) 2025-04-14 13:59:24 -05:00
Kris 3a9917862d UX: main-outlet needs dynamic bottom padding when composer open (#119)
When the composer is open the `#main-outlet`'s bottom padding needs to
match the composer height, so the content behind the composer can be
scrolled into view.

Reported here:
https://meta.discourse.org/t/help-us-test-horizon-our-newest-theme/360484/26?u=awesomerobot
2025-04-14 09:06:42 -04:00
Kris 0cd52c07fe UX: fix topic progress height (#118)
Before: 

![image](https://github.com/user-attachments/assets/b41d9c5f-6a7a-4cae-aa87-375e54b94bf9)


After:

![image](https://github.com/user-attachments/assets/e6969dcd-83b3-4e3c-a868-1dbd70ecf195)
2025-04-14 08:59:33 -04:00
Kris 1e6a4a8a57 DEV: port sidebar new topic component into theme (#129)
This moves the [sidebar new topic button
component](https://github.com/discourse/discourse-sidebar-new-topic-button)
into the theme directly

If you have installed this theme previously, you should manually remove
the component.
2025-04-14 08:58:46 -04:00
Jordan Vidrine b40a5a6e9a UX: Adjust avatar spacing (#131) 2025-04-12 09:03:55 -05:00
Jordan Vidrine 3a0a5b0f30 UX: Fix chat backgrounds (#130) 2025-04-11 17:06:41 -05:00
Jordan Vidrine e3aed16e2b UX: remove gap on avatars in PM list (#128) 2025-04-11 15:47:12 -05:00
Jordan Vidrine 23f4362f7e UX: Visual fixes (#127) 2025-04-11 15:33:58 -05:00
Kris f1d5b69293 DEV: port full-width component to be included directly (#126)
Removes the [full-width
component](https://github.com/discourse/discourse-full-width-component)
dependency by adding most of the code directly to the theme. There was
one grid definition in the CSS I ended up removing because it was
conflicting with an existing override in the theme.

Anyone who has previously installed the theme should manually remove the
full-width component from it.
2025-04-11 15:46:25 -04:00
Jordan Vidrine 18ffe04242 UX: New PM design (#125) 2025-04-11 13:43:17 -05:00
David Taylor b220d87a0d DEV: Trigger basic-html view for unsupported browsers (#124) 2025-04-10 20:39:30 +01:00
Kris 8e5cef819d UX: fix account activation layout (#123)
fixes this too-wide layout issue


![image](https://github.com/user-attachments/assets/9b2c8a1a-e395-44b5-acdb-cb289f69dcfb)
2025-04-10 13:19:52 -04:00
chapoi 2653732bc3 UX: post notice styling (#122)
![CleanShot 2025-04-10 at 11 14
07@2x](https://github.com/user-attachments/assets/c5c8f918-fbf4-4a39-b65d-09ddf045fe74)
⬇️ 
![CleanShot 2025-04-10 at 11 13
28@2x](https://github.com/user-attachments/assets/449d824a-15e3-49fb-9acb-25cee76e8acb)
2025-04-10 13:56:17 +02:00
Jordan Vidrine 2a0f5ec599 UX: font set experimental screen styles (#121) 2025-04-09 12:12:10 -05:00
Loïc Guitaut 3c7ccc97a7 DEV: Add system spec to check core features are working fine (#117) 2025-04-09 15:41:21 +02:00
Kris 2674364309 DEV: use wildcard selector for common container behavior (#120) 2025-04-08 16:01:08 -05:00
chapoi 5299986ed1 UX: iteration for the timeline scroll design (#116)
Attempt to make the timeline less eye-drawing, while still enhancing the
feel of "this is a draggable area" by emphasising the handle. Also added
a slight decrease of width.

| Before | After |
|--------|--------|
| ![CleanShot 2025-04-07 at 20 17
29@2x](https://github.com/user-attachments/assets/7997a797-1ffa-43b7-94fa-010974aeae51)
| ![CleanShot 2025-04-07 at 20 17
02@2x](https://github.com/user-attachments/assets/7372e1e2-8530-4045-bcdf-0ef73aa6698e)
|
2025-04-08 18:31:10 +02:00
Jordan Vidrine 34b26abb6e UX: fix width (#114) 2025-04-04 14:04:58 -05:00
Jordan Vidrine c735718f1b DEV: Add more user logic (#113) 2025-04-04 11:47:00 -05:00
Jordan Vidrine cdcbffc483 UX: More color fixes (#111) 2025-04-03 16:13:23 -05:00
Jordan Vidrine d8c44934f4 UX: Theme name change (#112) 2025-04-03 16:13:02 -05:00
Martin Brennan 00b2402cbb DEV: Core feature spec refinement (#106)
Followup e4b99976eb

This allows us to skip core feature specs more granularly,
since the topic ones work fine except create for example.

Also adds a topic create spec, since this theme uses the sidebar
new topic button component. We can rely on the /new-topic route
instead.
2025-04-03 13:40:27 +10:00
Kris c9c468c677 UX: fix PM user input spacing (#110)
Before:


![image](https://github.com/user-attachments/assets/3327adce-b26e-4644-82fe-d4f9611ad8e0)

After:


![image](https://github.com/user-attachments/assets/33f6a819-fa34-40f1-98de-469ab0f161f0)
2025-04-02 15:07:51 -04:00
Kris 85d94e9eca UX: fix cakeday & user directory containers (#109)
Before:


![image](https://github.com/user-attachments/assets/dbc14156-2def-42c1-bbc4-b2366a9b89fa)


![image](https://github.com/user-attachments/assets/92554725-ce2d-4756-9f9e-e49b91f0c227)


After:


![image](https://github.com/user-attachments/assets/a2c90617-6efa-4bdb-8149-cd7d5cea6e95)


![image](https://github.com/user-attachments/assets/2188f0be-58ef-4996-8628-57705cc6d52c)
2025-04-02 15:07:35 -04:00
Jordan Vidrine d0078cdd3e UX: Adjust icon colors (#108) 2025-04-02 10:50:37 -05:00
Jordan Vidrine 759fd0b218 UX: Header outline (#107) 2025-04-02 08:28:08 -05:00
Jordan Vidrine 1c85ae4626 UX: More accessible colors (#105) 2025-04-01 20:01:29 -05:00
Jordan Vidrine f4c6876923 UX: Topic excerpt fix (#104) 2025-04-01 15:09:04 -05:00
Martin Brennan e4b99976eb DEV: Add core feature spec (#100) 2025-04-01 12:49:37 -05:00
chapoi def09bcca5 UX: adapt topic card layout for bookmarks & assigned list (#97) 2025-04-01 12:48:52 -05:00
Jordan Vidrine 05d4b79fc9 UX: Add hover colors (#103) 2025-04-01 12:25:52 -05:00
Kris 5570fb9feb UX: fix group page container, round border (#102)
Fixes the spacing on the group container and rounds the header 

Before:


![image](https://github.com/user-attachments/assets/3384841a-82b0-4f17-a0be-a32bd405bd29)


After:


![image](https://github.com/user-attachments/assets/1450cb2d-bd7a-4fb4-b7a8-b800b8b40d0d)
2025-04-01 12:50:19 -04:00
Jordan Vidrine 5bbba7cacc UX: Define header colors (#101) 2025-04-01 09:52:12 -05:00
Martin Brennan 96da1d3439 FIX: Issues with FOUC and dark mode when switching palettes (#99)
Followup 6a4b979514

In this commit I changed how we load the selected palette
stylesheet so the system specs would know when the CSS is actually
loaded, however this introduced an issue where the user would see
a FOUC when switching palettes. I also introduced a bug where
if you chose to force dark mode then switched the palette, you would
see light mode instead.

This commit fixes both issues, by swapping the CSS link with a preloaded
one then waiting for the preload before switching the href of the
existing link, and removes `mode` shenanigans causing the light mode
issue.
2025-04-01 13:07:26 +10:00
Kris 878da19552 UX: fix category nav padding on small screens (#98)
This adjusts the active state of the dropdown by employing negative
margin to compensate for the padding

before:

![image](https://github.com/user-attachments/assets/e8c8a544-3527-4d6c-a513-0291a6a15ab5)


after:

![image](https://github.com/user-attachments/assets/4a53a0ee-a07d-43b0-9ab6-3542d86bbe8c)
2025-03-31 17:02:30 -04:00
chapoi 17bd1c2346 UX: fix chat border (#96) 2025-03-31 10:50:44 +02:00
Martin Brennan 6a4b979514 FIX: Color palette switching when Horizon is not default (#95)
When Horizon is not the default theme, and the color palette
switcher is used, we were ending up in a broken CSS state because
the color definitions were not loaded correctly when calling
`/color-scheme-stylesheet/` to get the new stylesheet URLs.

The problem was that we were not giving the theme ID to this URL,
we were only doing `/color-scheme-stylesheet/:palette_id`, not
`/color-scheme-stylesheet/:palette_id/:theme_id`, so the theme
color definitions like the ones that define the background color
were not loaded.

This commit fixes the issue and also changes to recreating the
`<link>` tags for the CSS in the head so we can check if they
are loaded correctly for easier testing in system specs.
2025-03-31 18:23:07 +10:00
Jordan Vidrine b4e451e64b DEV: Experimenting with using built in core color palettes for the color picking component (#71)
This PR is the beginning of converting the color picker to use built in
core color palettes.
The `color_schemes` defined in `about.json` are created in core when the
theme is imported,
and we then show all user-selectable color palettes in this sidebar
footer menu.

An important caveat here is that all of the Horizon themes must be
changed to `user_selectable`
otherwise they will not show up in the color palette selector in the
sidebar.

When choosing a color palette that also has a corresponding dark color
palette,
*both* light mode and dark mode are correctly saved with the color
palette(s) chosen,
using the color palette cookie we already have in core.

Anon users can also set a palette, which will be saved in a cookie.

---------

Co-authored-by: Sérgio Saquetim <saquetim@discourse.org>
Co-authored-by: Martin Brennan <martin@discourse.org>
Co-authored-by: Osama Sayegh <asooomaasoooma90@gmail.com>
2025-03-31 13:28:28 +10:00
chapoi 0473f90cd9 Lower z-index of powered-by-discourse badge (#93) 2025-03-30 20:33:59 -05:00
Jordan Vidrine 3e3f410839 UX: More card fixes (#94) 2025-03-28 16:43:52 -05:00
Jordan Vidrine 2046f525d4 UX: More logic for title columns (#87) 2025-03-28 10:49:28 -05:00
chapoi 9945f1d899 FIX: remove overflow prop (#91) 2025-03-28 08:27:36 -05:00
chapoi f70524a44b UX: fix minimised draft bg colour for composer (#89)
Followup fix for #84
2025-03-28 14:17:45 +01:00
Martin Brennan 0a416d317e FIX: Messed up CSS grid on messages list (#88)
This needs a better follow-up, but the messages topic list
is currently busted. Removing the overridden topic-list-item
grid for messages helps.
2025-03-28 12:39:49 +10:00
chapoi 910bc855c1 Composer styling on desktop (#84) 2025-03-27 16:41:20 -05:00
chapoi e20b83b79d Misc mobile fixes (#83) 2025-03-27 16:35:08 -05:00
Jordan Vidrine e7de006a23 UX: Topic list layout changes (#85) 2025-03-27 16:31:46 -05:00
Jordan Vidrine eff8628223 DEV: Fix spec (#86) 2025-03-27 16:31:28 -05:00
Jordan Vidrine a84682c0d0 FIX: Bulk select fix (#81)
This PR fixes bulk select on the new topic cards.
2025-03-27 10:03:40 +10:00
Jordan Vidrine adb1e4dcf2 UX: Change title fonts, etc (#80) 2025-03-26 14:08:42 -05:00
Jordan Vidrine d300cf9d0f UX: New topic card layout (#79) 2025-03-26 10:47:52 -05:00
Kris 6766b94232 UX: add tags-index container (#78) 2025-03-25 16:18:17 -04:00
Jordan Vidrine af82802548 UX: Topic list card fixes for assignments & bookmarks (#76) 2025-03-25 15:11:49 -05:00
Kris 943dd4e2d2 UX: change category nav background on mobile (#77) 2025-03-25 15:54:03 -04:00
Jordan Vidrine 1a372b7edc fix z index for input menu (#75) 2025-03-25 10:08:16 -05:00
Kris f786eae910 UX: set border radius on PMs (#74) 2025-03-24 15:22:25 -04:00
Jordan Vidrine dabd9a159a DEV: Use new is_hot_topic serializer (#73) 2025-03-24 12:05:10 -05:00
Jordan Vidrine 969e2b7969 begin migration of colors (#72) 2025-03-21 09:44:09 -05:00
chapoi ade14d7f54 Welcome banner: slight zindex increase (#70) 2025-03-21 11:55:29 +01:00
chapoi 30cb6bbf59 UX: Z-index welcome banner (#68)
* UX: increase z-index of welcome banner

* UX: lower z-index of sticky list-controls
2025-03-20 19:13:52 +01:00
Jordan Vidrine bee6e4e3c5 init (#69) 2025-03-20 09:43:40 -05:00
Kris 7f6b0df5bf UX: move and restyle bulk select on desktop (#65) 2025-03-20 08:42:11 -04:00
Martin Brennan 274e5f7a1f UX: Add theme settings and value transformers (#67)
This commit adds the above for these core site
settings:

* search_experience
* enable_welcome_banner

Since for horizon we want better control of
the default experience of these settings OOTB.

See also https://github.com/discourse/discourse/pull/31917
2025-03-20 15:38:46 +10:00
chapoi d062468f93 Undo sticky topic header (#64) 2025-03-19 10:19:25 -05:00
chapoi b6db617017 Mobile: New alert info width fix (#63) 2025-03-19 10:01:43 +01:00
Jordan Vidrine efc3dd5475 cleanup dropdown button (#62) 2025-03-18 19:29:42 -05:00
Jordan Vidrine d79313436d fix (#61) 2025-03-18 19:18:32 -05:00
Jordan Vidrine 19c957aecc apply anti-aliased font to topics as well (#60) 2025-03-18 18:43:27 -05:00
chapoi 3816c49bbf Tiny misc fixes (#59) 2025-03-18 17:02:45 +01:00
chapoi f64d0cc6dc UX: update styling of overlapping alert new/updated topics (#56) 2025-03-18 17:01:49 +01:00
chapoi 71f246c8a3 Button hover style reapply (#58) 2025-03-18 09:28:25 -05:00
Jordan Vidrine 970ee33771 cleanup (#55) 2025-03-17 19:49:30 -05:00
Jordan Vidrine 2c41c2ffab fix user page (#54) 2025-03-17 15:13:39 -05:00
Martin Brennan 185651b10d DEV: Remove search banner dependency (#53)
Followup dfa22d21b6,
the search banner has been replaced in core
with the welcome banner, this is no longer needed,
c.f. https://github.com/discourse/discourse/pull/31516
2025-03-17 11:45:14 +08:00
Jordan Vidrine dfa22d21b6 UX: Welcome banner merge prep (#49)
This PR preps the Horizon theme for the merger of the search banner into core. This PR should only be merged once this PR in core has been merged.
2025-03-17 12:18:54 +10:00
Jordan Vidrine 598f4fce65 fix (#52) 2025-03-14 17:13:38 -05:00
Jordan Vidrine 144c3dff8f DEV: main container sizing & border radius cleanup (#51) 2025-03-14 16:12:54 -05:00
Jordan Vidrine 8b09523510 DEV: Button stylesheet cleanup (#50) 2025-03-14 15:30:00 -05:00
Jordan Vidrine f70c452f26 selected (#48) 2025-03-12 13:52:05 -05:00
Jordan Vidrine 3911572b29 UX: More fixes (#47) 2025-03-12 13:39:27 -05:00
Jordan Vidrine 7fe1b87f82 small tweaks (#46) 2025-03-12 12:27:56 -05:00
Martin Brennan d85097774f DEV: Add high level system spec and clean up JS (#34) 2025-03-12 10:18:36 -05:00
chapoi 9a5759ae86 Tweak to color shadows, sidebar font-size, general small fixes (#36) 2025-03-12 10:02:45 -05:00
Jordan Vidrine 7023cc0f97 add margin to select menu (#45) 2025-03-11 17:21:46 -05:00
Jordan Vidrine feae5a0214 hide topic list trigger (#44) 2025-03-11 17:21:28 -05:00
Jordan Vidrine 81b7466224 fix sidebar group chat icon (#43) 2025-03-11 17:20:26 -05:00
Jordan Vidrine 97b379eb08 UX: font smoothing (#42) 2025-03-11 17:20:14 -05:00
Jordan Vidrine 1f55a9d9a2 fixes (#41) 2025-03-11 17:19:41 -05:00
Jordan Vidrine f4d5b3b97e UX: Color fixes (#40) 2025-03-11 16:29:35 -05:00
Jordan Vidrine 09ef1d2a14 paintbrush (#39) 2025-03-11 14:48:10 -05:00
Jordan Vidrine d1800ffd98 PR: Custom Color Choice (#38) 2025-03-11 14:45:04 -05:00
Jordan Vidrine 664e3a5910 UX: Small tweaks to colors (#37) 2025-03-11 14:01:34 -05:00
chapoi cdf49bd516 Button styling and states (#35) 2025-03-11 12:01:18 -05:00
Jordan Vidrine a90b691505 UX: Color exploration & base (#33) 2025-03-11 11:24:20 -05:00
Jordan Vidrine eca05948c3 UX:Breakpoint padding (#32) 2025-03-10 15:56:17 -05:00
Jordan Vidrine cef5ad279c fix target (#31) 2025-03-10 13:15:44 -05:00
chapoi fc97ab99fe Mobile: topic list, topic view, sidebar tweaks 2025-03-10 16:50:13 +01:00
Jordan Vidrine 9e96704c24 UX: Mobile fix (#29) 2025-03-08 09:45:06 +00:00
Jordan Vidrine 536b58feba small-mobile-fix (#28) 2025-03-07 14:54:20 -06:00
Jordan Vidrine 35a4642042 UX: Width & calculation adjustments for main container (#27) 2025-03-07 12:01:26 -06:00
67 changed files with 5330 additions and 2774 deletions
+2
View File
@@ -0,0 +1,2 @@
< 3.5.0.beta5-dev: 31249c4f27d93e83c6b83d42d93974522a9a612e
+60 -44
View File
@@ -1,8 +1,9 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (7.2.1.1)
activesupport (8.0.2)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
@@ -12,68 +13,83 @@ GEM
minitest (>= 5.1)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
ast (2.4.2)
base64 (0.2.0)
bigdecimal (3.1.8)
concurrent-ruby (1.3.4)
connection_pool (2.4.1)
drb (2.2.1)
i18n (1.14.6)
uri (>= 0.13.1)
ast (2.4.3)
base64 (0.3.0)
benchmark (0.4.1)
bigdecimal (3.2.2)
concurrent-ruby (1.3.5)
connection_pool (2.5.3)
drb (2.2.3)
i18n (1.14.7)
concurrent-ruby (~> 1.0)
json (2.7.2)
language_server-protocol (3.17.0.3)
logger (1.6.1)
minitest (5.25.1)
parallel (1.26.3)
parser (3.3.5.0)
json (2.12.2)
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
logger (1.7.0)
minitest (5.25.5)
parallel (1.27.0)
parser (3.3.8.0)
ast (~> 2.4.1)
racc
prettier_print (1.2.1)
prism (1.4.0)
racc (1.8.1)
rack (3.1.10)
rack (3.1.15)
rainbow (3.1.1)
regexp_parser (2.9.2)
rubocop (1.67.0)
regexp_parser (2.10.0)
rubocop (1.76.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0)
rubocop-ast (>= 1.32.2, < 2.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.45.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.32.3)
parser (>= 3.3.1.0)
rubocop-capybara (2.21.0)
rubocop (~> 1.41)
rubocop-discourse (3.8.2)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.45.0)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-capybara (2.22.1)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-discourse (3.12.1)
activesupport (>= 6.1)
rubocop (>= 1.59.0)
rubocop-capybara (>= 2.0.0)
rubocop-factory_bot (>= 2.0.0)
rubocop-rails (>= 2.25.0)
lint_roller (>= 1.1.0)
rubocop (>= 1.73.2)
rubocop-capybara (>= 2.22.0)
rubocop-factory_bot (>= 2.27.0)
rubocop-rails (>= 2.30.3)
rubocop-rspec (>= 3.0.1)
rubocop-rspec_rails (>= 2.30.0)
rubocop-factory_bot (2.26.1)
rubocop (~> 1.61)
rubocop-rails (2.26.2)
rubocop-rspec_rails (>= 2.31.0)
rubocop-factory_bot (2.27.1)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rails (2.32.0)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
rubocop (>= 1.52.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (3.1.0)
rubocop (~> 1.61)
rubocop-rspec_rails (2.30.0)
rubocop (~> 1.61)
rubocop-rspec (~> 3, >= 3.0.1)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.44.0, < 2.0)
rubocop-rspec (3.6.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec_rails (2.31.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec (~> 3.5)
ruby-progressbar (1.13.0)
securerandom (0.3.1)
securerandom (0.4.1)
syntax_tree (6.2.0)
prettier_print (>= 1.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.6.0)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
PLATFORMS
ruby
@@ -83,4 +99,4 @@ DEPENDENCIES
syntax_tree
BUNDLED WITH
2.5.21
2.6.9
+149 -3
View File
@@ -1,5 +1,151 @@
# next-gen
# discourse_theme_ranHorizon 主题源码)
**Theme Summary**
> 该仓库是 Discourse `Horizon (beta)` 主题的源码副本。仓库内原 README 已标注该主题已并入 Discourse Core。
For more information, please see: **url to meta topic**
## 1. 项目作用
这是一个 Discourse 主题项目,核心目标是:
- 改造论坛整体视觉(卡片化主题列表、圆角、配色系统、侧边栏样式)
- 增强交互(侧边栏新建主题按钮、颜色方案切换、Composer Peek 模式)
- 调整不同页面体验(分类页、主题页、聊天页、登录页、移动端)
- 提供系统测试,验证主题关键行为
---
## 2. 目录结构与作用
### `.github/`
- `workflows/discourse-theme.yml`CI 配置,复用 Discourse 官方主题工作流。
### `assets/`
- `.gitkeep`:占位目录,预留静态资源(当前无实际资源文件)。
### `common/`
- `common.scss`:公共样式入口,按模块聚合 `scss/` 下样式。
- `color_definitions.scss`:主题色变量定义(基于 tertiary 推导背景、链接、侧边栏等)。
- `head_tag.html`:注入浏览器兼容检测脚本,不支持 `hsl(from ...)` 时提示升级浏览器。
### `desktop/`
- `desktop.scss`:桌面端样式入口。
- `desktop-full-width.scss`:全宽布局与头部网格布局规则。
- `desktop-horizon-fixes.scss`:桌面端修复(如 bulk select 样式/布局修正)。
### `javascripts/`
- `.gitkeep`:占位。
- `discourse/api-initializers/`:通过 Discourse API 注入主题行为。
- `horizon.gjs`:主题主初始化器;注册实验装饰层、配色选择器、站点设置覆盖、管理员弃用提示。
- `sidebar-new-topic-button-connector.js`:把自定义“新建主题”按钮渲染到侧边栏。
- `composer-peek-toggle-connector.js`:把 Peek 模式切换按钮挂到 composer 工具区。
- `full-width-logo-behavior.js`:侧边栏展开时控制 Logo 最小化行为。
- `reposition-bulk-select.js`:将批量选择入口放到导航控制区。
- `hamburger-click-outside-transformer.js`:扩展汉堡菜单“点击外部关闭”例外元素。
- `discourse/components/`Glimmer 组件。
- `experimental-screen.gjs`:主内容四角/底部装饰层组件(根据容器位置实时计算)。
- `sidebar-new-topic-button.gjs`:侧边栏新建主题按钮逻辑(权限、分类只读、草稿、关闭汉堡菜单)。
- `composer-peek-mode-toggle.gjs`Composer Peek 模式开关,偏好写入 `keyValueStore`
- `user-color-palette-selector.gjs`:用户配色切换主组件(支持匿名/登录、明暗配套、CSS 热替换)。
- `user-color-palette-menu-item.gjs`:配色菜单项。
- `discourse/components/card/`:主题列表卡片列组件。
- `topic-status-column.gjs`Pinned/Hot 状态徽章。
- `topic-category-column.gjs`:分类列。
- `topic-creator-column.gjs`:主题创建者头像列。
- `topic-replies-column.gjs`:回复数列。
- `topic-likes-column.gjs`:点赞数列(当前主题列表布局中未启用展示)。
- `topic-activity-column.gjs`:最近活动信息(回复/创建/更新与时间)。
- `discourse/initializers/topic-list-columns.gjs`:重排主题列表列、注入卡片列、改写点击行为与移动布局策略。
### `locales/`
- `en.yml`:主题文案与元数据(如 `topic_hot``topic_pinned`、描述文本)。
### `scss/`
按功能拆分的样式模块(由 `common/common.scss``desktop/desktop.scss` 聚合):
- `variables.scss`:全局尺寸/圆角/间距变量。
- `main.scss`:页面主体容器网格与背景结构。
- `topic-cards.scss`:主题列表卡片化布局核心样式。
- `topic.scss`:主题阅读页、时间线、帖子流样式。
- `categories-view.scss`:分类页与分类+最新混合页样式。
- `sidebar.scss`:侧边栏容器/section/链接样式。
- `sidebar-new-topic-button.scss`:侧边栏新建主题按钮视觉与状态。
- `header.scss`:顶部栏、通知菜单、图标交互样式。
- `nav-pills.scss`:列表导航区(sticky、tab/下拉)样式。
- `buttons.scss`:按钮体系(默认/主按钮 hover、focus、active)。
- `composer.scss`:编辑器外观与工具条、翻译 composer 相关样式。
- `composer-peek-mode.scss`Peek 模式下 composer 与主布局联动。
- `chat.scss`:聊天页/聊天抽屉适配。
- `welcome-banner.scss`:欢迎横幅和搜索区域样式。
- `mobile-stuff.scss`:移动端/小屏布局调整。
- `login.scss`:登录类页面布局样式。
- `misc.scss`:分散组件兼容/补丁样式。
- `hiddenstuff.scss`:隐藏部分原生 UI 元素。
- `color-choice.scss`:配色切换菜单样式。
- `color-exploration.scss`:侧边栏等颜色变量实验定义。
- `box-view.scss`:实验装饰层(四角遮罩)与聊天相关视觉细节。
- `desktop-full-width.scss``desktop-horizon-fixes.scss`:虽然在 `scss/` 目录下存在同名文件,实际桌面入口使用 `desktop/` 目录版本。
### `screenshots/`
- `light.png``dark.png`:主题明/暗模式截图,供主题元信息展示。
### `spec/`
系统测试(RSpec + Capybara):
- `system/core_features_spec.rb`:主题与核心能力兼容性基础测试。
- `system/horizon_high_level_spec.rb`:高层端到端流程(主题列表、导航、配色切换)。
- `system/sidebar_topic_button_spec.rb`:侧边栏新建主题按钮行为测试。
- `system/composer_peek_spec.rb`Peek 模式可见性与持久化测试。
- `system/user_color_palette_selector_spec.rb`:配色切换在匿名/登录/深色模式下的行为测试。
- `system/page_objects/components/user_color_palette_selector.rb`:配色选择器的 PageObject 封装。
- `.gitkeep`:占位。
### `test/`
- `acceptance/.gitkeep`:预留前端测试目录(当前无具体测试文件)。
---
## 3. 根目录文件作用
- `about.json`:主题元数据(名称、作者、链接、版本、颜色方案、截图、modifiers)。
- `settings.yml`:主题设置项(欢迎横幅开关、搜索体验模式)。
- `README.md`:项目说明文档(本文件)。
- `LICENSE`MIT 许可证。
- `package.json`:前端开发依赖与 Node/pnpm 版本约束。
- `pnpm-lock.yaml`:前端依赖锁定文件。
- `Gemfile` / `Gemfile.lock`Ruby 工具链依赖(rubocop-discourse、syntax_tree 等)。
- `.discourse-compatibility`:与 Discourse 版本兼容映射。
- `eslint.config.mjs`ESLint 配置(继承 `@discourse/lint-configs`)。
- `stylelint.config.mjs`Stylelint 配置。
- `.template-lintrc.cjs`Ember Template Lint 配置。
- `.prettierrc.cjs`Prettier 配置。
- `.rubocop.yml`Rubocop 配置(Discourse 规则)。
- `.streerc`Syntax Tree 格式化配置。
- `.npmrc`:npm 行为约束(严格引擎、禁自动 peer 安装)。
- `.gitignore`Git 忽略规则。
---
## 4. 关键功能对应关系(便于快速定位)
- 主题配色切换:
- 逻辑:`javascripts/discourse/components/user-color-palette-selector.gjs`
- 菜单样式:`scss/color-choice.scss`
- 颜色定义:`about.json` + `common/color_definitions.scss`
- 侧边栏新建主题按钮:
- 逻辑:`javascripts/discourse/components/sidebar-new-topic-button.gjs`
- 挂载:`javascripts/discourse/api-initializers/sidebar-new-topic-button-connector.js`
- 样式:`scss/sidebar-new-topic-button.scss`
- 主题列表卡片化:
- 列注册:`javascripts/discourse/initializers/topic-list-columns.gjs`
- 各列组件:`javascripts/discourse/components/card/*.gjs`
- 主样式:`scss/topic-cards.scss`
- Composer Peek 模式:
- 逻辑:`javascripts/discourse/components/composer-peek-mode-toggle.gjs`
- 挂载:`javascripts/discourse/api-initializers/composer-peek-toggle-connector.js`
- 样式:`scss/composer-peek-mode.scss`
---
## 5. 说明
- 此仓库 README 原文已声明:该主题已并入 Discourse Core,生产环境优先使用 Core 内置 Horizon 主题。
- 当前仓库更适合作为学习/二次开发参考,用于理解 Discourse 主题的样式组织方式与前端扩展点。
+123 -31
View File
@@ -1,43 +1,135 @@
{
"name": "Horizon Theme",
"authors": "Design Team",
"about_url": "TODO: Put your theme's public repo or Meta topic URL here",
"license_url": "TODO: Put your theme's LICENSE URL here",
"learn_more": "TODO",
"name": "Horizon-shiran",
"authors": "shiran",
"about_url": "",
"license_url": "https://gitea.s1f.ren/shiran/discourse_theme_ran/horizon/blob/main/LICENSE",
"learn_more": "",
"theme_version": "0.0.1",
"minimum_discourse_version": null,
"maximum_discourse_version": null,
"assets": {},
"modifiers": {
"svg_icons": ["fire"]
"svg_icons": ["fire"],
"serialize_topic_is_hot": true
},
"components": [
"https://github.com/discourse/discourse-sidebar-new-topic-button.git",
"https://github.com/discourse/discourse-search-banner.git",
"https://github.com/discourse/discourse-full-width-component.git"
],
"color_schemes": {
"Horizon": {
"primary": "1A1A1A",
"primary-low": "ebecf9",
"primary-500": "8591ad",
"secondary": "ffffff",
"header_background": "f5f8ff",
"tertiary": "313270",
"tertiary-low": "d8d9f3",
"tertiary-50": "f5f8ff",
"selected": "d8d9f3",
"hover": "ebebf9"
"tertiary": "595bca",
"tertiary-med-or-tertiary": "595bca",
"selected": "d7dfff",
"header_background": "ffffff",
"header_primary": "1A1A1A",
"hover": "E1E8FF"
},
"Horizon Dark": {
"primary": "F1EFF9",
"secondary": "1e1a36",
"header_background": "00091d",
"header_primary": "F5F8FF",
"tertiary": "6465ab",
"tertiary-50": "131124",
"selected": "1e1a36",
"hover": "131124"
"primary": "ffffff",
"secondary": "1A1A1A",
"tertiary": "595bca",
"tertiary-med-or-tertiary": "595bca",
"selected": "3b3e56",
"header_background": "1A1A1A",
"header_primary": "ffffff",
"hover": "333548"
},
"Royal": {
"primary": "1A1A1A",
"secondary": "ffffff",
"tertiary": "1F7BC1",
"tertiary-med-or-tertiary": "1F7BC1",
"selected": "c7e3ff",
"header_background": "ffffff",
"header_primary": "1A1A1A",
"hover": "D6EBFF"
},
"Royal Dark": {
"primary": "ffffff",
"secondary": "1A1A1A",
"tertiary": "1F7BC1",
"tertiary-med-or-tertiary": "1F7BC1",
"selected": "3a455f",
"header_background": "1A1A1A",
"header_primary": "ffffff",
"hover": "323B4E"
},
"Clover": {
"primary": "1A1A1A",
"secondary": "ffffff",
"tertiary": "39845B",
"tertiary-med-or-tertiary": "39845B",
"selected": "c6f1d5",
"header_background": "ffffff",
"header_primary": "1A1A1A",
"hover": "D5F5E0"
},
"Clover Dark": {
"primary": "ffffff",
"secondary": "1A1A1A",
"tertiary": "39845B",
"tertiary-med-or-tertiary": "39845B",
"selected": "47594e",
"header_background": "1A1A1A",
"header_primary": "ffffff",
"hover": "3C4A40"
},
"Lily": {
"primary": "1A1A1A",
"secondary": "ffffff",
"tertiary": "cc338c",
"tertiary-med-or-tertiary": "cc338c",
"selected": "ffc8ee",
"header_background": "ffffff",
"header_primary": "1A1A1A",
"hover": "FFD7F3"
},
"Lily Dark": {
"primary": "ffffff",
"secondary": "1A1A1A",
"tertiary": "cc338c",
"tertiary-med-or-tertiary": "cc338c",
"selected": "5f3e4e",
"header_background": "1A1A1A",
"header_primary": "ffffff",
"hover": "4E3640"
},
"Violet": {
"primary": "1A1A1A",
"secondary": "ffffff",
"tertiary": "9b15de",
"tertiary-med-or-tertiary": "9b15de",
"selected": "feccff",
"header_background": "ffffff",
"header_primary": "1A1A1A",
"hover": "FFD9FF"
},
"Violet Dark": {
"primary": "ffffff",
"secondary": "1A1A1A",
"tertiary": "9b15de",
"tertiary-med-or-tertiary": "9b15de",
"selected": "4c385c",
"header_background": "1A1A1A",
"header_primary": "ffffff",
"hover": "40314C"
},
"Marigold": {
"primary": "1A1A1A",
"secondary": "ffffff",
"tertiary": "d3881f",
"tertiary-med-or-tertiary": "d3881f",
"selected": "ffdcb2",
"header_background": "ffffff",
"header_primary": "1A1A1A",
"hover": "FFE6C6"
},
"Marigold Dark": {
"primary": "ffffff",
"secondary": "1A1A1A",
"tertiary": "d3881f",
"tertiary-med-or-tertiary": "d3881f",
"selected": "6c5b49",
"header_background": "1A1A1A",
"header_primary": "ffffff",
"hover": "584B3E"
}
}
},
"screenshots": ["screenshots/light.png", "screenshots/dark.png"]
}
+105
View File
@@ -0,0 +1,105 @@
html {
--accent-color: #{$tertiary} !important;
--accent-text-color: #fff;
// Background Colors
--background-color: light-dark(
oklch(from #{$tertiary} 96% calc(c * 0.125) h),
oklch(from #{$tertiary} 10% 0.025 h)
) !important;
--d-content-background: light-dark(
oklch(from #{$secondary} calc(2 * l) c h),
oklch(from #{$secondary} l c h)
) !important;
// HeaderColors
--header_primary-low-mid: light-dark(
oklch(from #{$tertiary} 73.5% calc(c * 0.5) h),
oklch(from #{$tertiary} l calc(c * 0.25) h)
) !important;
--header_primary-medium: light-dark(
oklch(from #{$tertiary} 54% calc(c * 0.5) h),
oklch(from #{$tertiary} calc(l * 1.35) calc(c * 0.25) h)
) !important;
// Sidebar Colors
--d-sidebar-border-color: light-dark(
oklch(from #{$tertiary} 88% calc(c * 0.25) h),
oklch(from #{$tertiary} calc(l * 0.7) calc(c * 0.25) h)
) !important;
--d-sidebar-link-color: light-dark(
oklch(from #{$tertiary} calc(l * 0.8) calc(c * 0.25) h),
oklch(from #{$tertiary} calc(l * 1.5) calc(c * 0.25) h)
) !important;
--d-sidebar-active-color: #{$primary} !important;
--d-sidebar-suffix-color: light-dark(
oklch(from #{$tertiary} l calc(c * 0.9) h),
oklch(from #{$tertiary} l calc(c * 0.9) h)
) !important;
// Other Colors
--d-selected: light-dark(
oklch(from #{$tertiary} 92% calc(c * 0.5) h),
oklch(from #{$tertiary} calc(l * 0.7) calc(c * 0.25) h)
) !important;
--d-nav-color--active: light-dark(
oklch(from #{$tertiary} l c h),
oklch(from #{$tertiary} calc(l * 1.2) c h)
) !important;
--d-nav-color--hover: light-dark(
oklch(from #{$tertiary} l c h),
oklch(from #{$tertiary} calc(l * 1.2) c h)
) !important;
--link-color: light-dark(
oklch(from #{$tertiary} l c h),
oklch(from #{$tertiary} calc(l * 0.95) c h)
) !important;
--link-color-hover: light-dark(
oklch(from #{$tertiary} l c h),
oklch(from #{$tertiary} calc(l * 1.5) calc(c * 2.25) h)
) !important;
--tertiary-hover: #{$tertiary} !important;
// Search Colors
--search-color: light-dark(
oklch(from #{$tertiary} l c h),
oklch(from #{$tertiary} calc(l * 1.5) calc(c * 0.25) h)
) !important;
// Topic Card Colors
--topic-card-shadow: light-dark(
oklch(from #{$tertiary} calc(l * 1.85) calc(c * 0.5) h),
oklch(from #{$tertiary} calc(l * 0.2) calc(c * 0.01) h / 0.25)
) !important;
// Button Colors
--button-box-shadow: light-dark(
oklch(from #{$tertiary} calc(l * 1.5) calc(c * 0.35) h),
oklch(from #{$tertiary} calc(l * 0.75) calc(c * 0.5) h)
) !important;
--d-sidebar-highlight-hover-icon: var(--d-sidebar-link-color) !important;
--d-sidebar-highlight-hover-background: var(--d-selected) !important;
--d-sidebar-link-icon-color: var(--d-sidebar-link-color) !important;
--d-sidebar-header-color: var(--d-sidebar-link-color) !important;
--d-sidebar-header-icon-color: var(--d-sidebar-link-color) !important;
--d-sidebar-active-suffix-color: var(--d-sidebar-suffix-color) !important;
--d-sidebar-background: var(--background-color) !important;
--d-sidebar-footer-fade: var(--background-color) !important;
--d-sidebar-prefix-background: var(--d-selected) !important;
--d-sidebar-active-prefix-background: light-dark(
oklch(from var(--d-selected) calc(l * 0.85) c h),
oklch(from var(--d-selected) calc(l * 0.7) c h)
) !important;
--d-sidebar-highlight-prefix-background: light-dark(
oklch(from var(--d-selected) calc(l * 0.85) c h),
oklch(from var(--d-selected) calc(l * 0.7) c h)
) !important;
--d-sidebar-highlight-suffix-color: var(
--d-sidebar-active-suffix-color
) !important;
--d-sidebar-highlight-color: var(--primary) !important;
--d-sidebar-highlight-background: var(--d-selected) !important;
--d-sidebar-section-link-icon-size: 1em !important;
--d-hover: oklch(from var(--d-selected) l c h / 0.75) !important;
--d-input-bg-color: var(--d-content-background) !important;
}
+12 -5
View File
@@ -1,14 +1,21 @@
@import "box-view";
@import "buttons";
@import "chat";
@import "categories-view";
@import "color-choice";
@import "composer";
@import "composer-peek-mode";
@import "header";
@import "hiddenstuff";
@import "login";
@import "main";
@import "misc";
@import "mobile-stuff";
@import "nav-pills";
@import "search-banner";
@import "welcome-banner";
@import "sidebar";
@import "sidebar-new-topic-button";
@import "topic";
@import "topic-cards";
@import "variables";
@import "box-view";
@import "chat";
@import "misc";
@import "mobile-stuff";
@import "self";
+7
View File
@@ -0,0 +1,7 @@
<script>
if (!CSS.supports("(color: hsl(from white h s l))")) {
window.unsupportedBrowser = true;
window.I18n.translations[I18n.locale].js.browser_update =
'The Horizon theme does not support your browser. Please update your browser, or <a href="?safe_mode=no_themes">switch to safe mode</a>.';
}
</script>
+2
View File
@@ -0,0 +1,2 @@
@import "desktop-horizon-fixes";
@import "desktop-full-width";
@@ -0,0 +1,6 @@
import { apiInitializer } from "discourse/lib/api";
import ComposerPeekModeToggle from "../components/composer-peek-mode-toggle";
export default apiInitializer("1.8.0", (api) => {
api.renderInOutlet("before-composer-toggles", ComposerPeekModeToggle);
});
@@ -0,0 +1,16 @@
import { apiInitializer } from "discourse/lib/api";
export default apiInitializer("0.8", (api) => {
document.body.classList.add("full-width-enabled");
// When the sidebar is visible, force the HomeLogo to be in an 'un-minimized' state.
api.registerValueTransformer?.(
"home-logo-minimized",
({ value, context }) => {
if (value && context.showSidebar) {
return false;
}
return value;
}
);
});
@@ -0,0 +1,10 @@
import { apiInitializer } from "discourse/lib/api";
export default apiInitializer("0.8", (api) => {
api.registerValueTransformer(
"hamburger-dropdown-click-outside-exceptions",
({ value }) => {
return [...value, ".topic-drafts-menu-content"];
}
);
});
@@ -0,0 +1,16 @@
import { apiInitializer } from "discourse/lib/api";
import ExperimentalScreen from "../components/experimental-screen";
import UserColorPaletteSelector from "../components/user-color-palette-selector";
export default apiInitializer("1.8.0", (api) => {
api.renderInOutlet("above-main-container", ExperimentalScreen);
api.renderInOutlet("sidebar-footer-actions", UserColorPaletteSelector);
api.registerValueTransformer("site-setting-enable-welcome-banner", () => {
return settings.enable_welcome_banner;
});
api.registerValueTransformer("site-setting-search-experience", () => {
return settings.search_experience;
});
});
@@ -1,6 +0,0 @@
import { apiInitializer } from "discourse/lib/api";
import ExperimentalScreen from "../components/experimental-screen";
export default apiInitializer("1.8.0", (api) => {
api.renderInOutlet("above-main-container", ExperimentalScreen);
});
@@ -0,0 +1,7 @@
import { apiInitializer } from "discourse/lib/api";
export default apiInitializer("0.8.0", (api) => {
api.registerValueTransformer("bulk-select-in-nav-controls", () => {
return true;
});
});
@@ -0,0 +1,6 @@
import { apiInitializer } from "discourse/lib/api";
import SidebarNewTopicButton from "../components/sidebar-new-topic-button";
export default apiInitializer("1.8.0", (api) => {
api.renderInOutlet("before-sidebar-sections", SidebarNewTopicButton);
});
@@ -0,0 +1,49 @@
import Component from "@glimmer/component";
import concatClass from "discourse/helpers/concat-class";
import formatDate from "discourse/helpers/format-date";
export default class TopicActivityColumn extends Component {
get topicUser() {
if (
moment(this.args.topic.bumped_at).isAfter(this.args.topic.last_posted_at)
) {
return {
user: undefined,
username: undefined,
activityText: "user_updated",
class: "--updated",
};
}
if (this.args.topic.posts_count > 1) {
return {
user: this.args.topic.lastPosterUser,
username: this.args.topic.last_poster_username,
activityText: "user_replied",
class: "--replied",
};
} else if (this.args.topic.posts_count === 1) {
return {
user: this.args.topic.firstPosterUser,
username: this.args.topic.last_poster_username,
class: "--created",
};
} else {
return;
}
}
<template>
<span class={{concatClass "topic-activity" this.topicUser.class}}>
{{#if this.topicUser.username}}
<span
class="topic-activity__username"
>{{this.topicUser.username}}</span>
<span class="dot-separator"></span>
{{/if}}
<div class="topic-activity__time">
{{formatDate @topic.bumpedAt leaveAgo="true" format="tiny"}}
</div>
</span>
</template>
}
@@ -1,9 +0,0 @@
import avatar from "discourse/helpers/avatar";
const TopicAuthorAvatarColumn = <template>
<span class="topic-author-avatar">
{{avatar @topic.creator imageSize="large"}}
</span>
</template>;
export default TopicAuthorAvatarColumn;
@@ -1,5 +0,0 @@
const TopicAuthorColumn = <template>
<span class="topic-author">@{{@topic.creator.username}}</span>
</template>;
export default TopicAuthorColumn;
@@ -0,0 +1,17 @@
import Component from "@glimmer/component";
import avatar from "discourse/helpers/avatar";
export default class TopicCreatorColumn extends Component {
get topicCreator() {
return {
user: this.args.topic.creator,
class: "--topic-creator",
};
}
<template>
<div class={{this.topicCreator.class}}>
{{avatar this.topicCreator.user}}
</div>
</template>
}
@@ -1,8 +1,12 @@
import { gt } from "truth-helpers";
import icon from "discourse/helpers/d-icon";
import number from "discourse/helpers/number";
const TopicRepliesColumn = <template>
{{#if @topic.posts_count}}
<span class="topic-replies">{{icon "reply"}}{{@topic.posts_count}}</span>
{{#if (gt @topic.replyCount 1)}}
<span class="topic-replies">{{icon "reply"}}{{number
@topic.posts_count
}}</span>
{{/if}}
</template>;
@@ -1,115 +1,38 @@
import Component from "@glimmer/component";
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { and } from "truth-helpers";
import icon from "discourse/helpers/d-icon";
import { i18n } from "discourse-i18n";
export default class TopicStatusColumn extends Component {
@service currentUser;
@service siteSettings;
get canAct() {
return this.currentUser && !this.args.disableActions;
}
get statusClass() {
let classes = ["topic-status-card"];
if (this.args.topic.bookmarked) {
classes.push("--bookmark");
} else if (this.args.topic.closed && this.args.topic.archived) {
classes.push("--locked --archived");
} else if (this.args.topic.closed) {
classes.push("--locked");
} else if (this.args.topic.archived) {
classes.push("--archived");
} else if (this.args.topic.is_warning) {
classes.push("--warning");
} else if (
this.args.showPrivateMessageIcon &&
this.args.topic.isPrivateMessage
) {
classes.push("--private-message");
} else if (this.args.topic.pinned) {
classes.push("--pinned");
} else if (this.args.topic.unpinned) {
classes.push("--unpinned");
get badge() {
if (this.args.topic.is_hot) {
return {
icon: "fire",
text: "topic_hot",
className: "--hot",
};
}
return classes.join(" ");
}
get heatMap() {
return this.args.topic.views > this.siteSettings.topic_views_heat_medium;
}
if (this.args.topic.pinned) {
return {
icon: "thumbtack",
text: "topic_pinned",
className: "--pinned",
};
}
@action
togglePinned(event) {
event.preventDefault();
this.args.topic.togglePinnedForUser();
return null;
}
<template>
{{#if @topic.bookmarked}}
<span class={{this.statusClass}}>{{icon "bookmark"}}{{i18n
(themePrefix "topic_bookmarked")
}}</span>
{{/if}}
{{#if (and @topic.closed @topic.archived)~}}
<span class={{this.statusClass}}>{{i18n
(themePrefix "topic_closed_and_archived")
}}</span>
{{else if @topic.closed}}
<span class={{this.statusClass}}>{{i18n
(themePrefix "topic_closed")
}}</span>
{{else if @topic.archived}}
<span class={{this.statusClass}}>{{i18n
(themePrefix "topic_archived")
}}</span>
{{/if}}
{{#if @topic.is_warning}}
<span class={{this.statusClass}}>{{i18n
(themePrefix "topic_warning")
}}</span>
{{else if (and @showPrivateMessageIcon @topic.isPrivateMessage)}}
<span class={{this.statusClass}}>{{i18n
(themePrefix "topic_personal_message")
}}</span>
{{/if}}
{{#if @topic.pinned}}
{{#if this.canAct}}
<button
type="button"
{{on "click" this.togglePinned}}
class={{this.statusClass}}
>{{icon "thumbtack"}}{{i18n (themePrefix "topic_pinned")}}</button>
{{else}}
<span class={{this.statusClass}}>{{icon "thumbtack"}}{{i18n
(themePrefix "topic_pinned")
}}</span>
{{/if}}
{{else if @topic.unpinned}}
{{#if this.canAct}}
<button
type="button"
{{on "click" this.togglePinned}}
class={{this.statusClass}}
>{{icon "thumbtack" class="unpinned"}}{{i18n
(themePrefix "topic_unpinned")
}}</button>
{{else}}
<span class={{this.statusClass}}>{{icon
"thumbtack"
class="unpinned"
}}{{i18n (themePrefix "topic_unpinned")}}</span>
{{/if}}
{{/if}}
{{#if this.heatMap}}
<span class="topic-status-card --hot">{{icon "fire"}}{{i18n
(themePrefix "topic_hot")
}}</span>
{{#if this.badge}}
<span class="topic-status-card {{this.badge.className}}">{{icon
this.badge.icon
}}<p class="topic-status-card__name">{{i18n
(themePrefix this.badge.text)
}}</p></span>
{{/if}}
</template>
}
@@ -0,0 +1,37 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import bodyClass from "discourse/helpers/body-class";
export default class ComposerPeekModeToggle extends Component {
@service composer;
@service keyValueStore;
@tracked
peekModeActive = this.keyValueStore.getItem("peekModeActive") === "true";
get bodyCssClass() {
return this.peekModeActive ? "peek-mode-active" : "";
}
@action
togglePeekMode() {
this.peekModeActive = !this.peekModeActive;
this.keyValueStore.setItem("peekModeActive", this.peekModeActive);
if (this.composer.showPreview) {
this.composer.togglePreview();
}
}
<template>
{{bodyClass this.bodyCssClass}}
<DButton
@action={{this.togglePeekMode}}
@preventFocus={{true}}
@icon="discourse-sidebar"
class="btn-mini-toggle no-text peek-mode-toggle btn-transparent"
/>
</template>
}
@@ -2,10 +2,15 @@ import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { service } from "@ember/service";
import { htmlSafe } from "@ember/template";
import { bind } from "discourse/lib/decorators";
const DO_NOT_RENDER_LIST = ["login"];
export default class ExperimentalScreen extends Component {
@service router;
@tracked left = 0;
@tracked right = 0;
resizeObserver;
@@ -28,6 +33,10 @@ export default class ExperimentalScreen extends Component {
);
}
get shouldRender() {
return !DO_NOT_RENDER_LIST.includes(this.router.currentRouteName);
}
@action
onInsert(element) {
this.calculateDistance(element);
@@ -42,16 +51,18 @@ export default class ExperimentalScreen extends Component {
}
<template>
<ul
class="experimental-screen"
{{didInsert this.onInsert}}
style={{this.distanceStyles}}
>
<li class="experimental-screen__top-left"></li>
<li class="experimental-screen__top-right"></li>
<li class="experimental-screen__bottom-left"></li>
<li class="experimental-screen__bottom-right"></li>
<li class="experimental-screen__bottom-bar"></li>
</ul>
{{#if this.shouldRender}}
<ul
class="experimental-screen"
{{didInsert this.onInsert}}
style={{this.distanceStyles}}
>
<li class="experimental-screen__top-left"></li>
<li class="experimental-screen__top-right"></li>
<li class="experimental-screen__bottom-left"></li>
<li class="experimental-screen__bottom-right"></li>
<li class="experimental-screen__bottom-bar"></li>
</ul>
{{/if}}
</template>
}
@@ -0,0 +1,116 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
import willDestroy from "@ember/render-modifiers/modifiers/will-destroy";
import { service } from "@ember/service";
import { gt, not } from "truth-helpers";
import CreateTopicButton from "discourse/components/create-topic-button";
export default class SidebarNewTopicButton extends Component {
@service composer;
@service currentUser;
@service siteSettings;
@service router;
@service header;
@service appEvents;
@tracked category;
@tracked tag;
get shouldRender() {
return this.currentUser && !this.router.currentRouteName.includes("admin");
}
get canCreateTopic() {
return this.currentUser?.can_create_topic;
}
get draftCount() {
return this.currentUser?.get("draft_count");
}
get createTopicTargetCategory() {
if (this.category?.canCreateTopic) {
return this.category;
}
if (this.siteSettings.default_subcategory_on_read_only_category) {
return this.category?.subcategoryWithCreateTopicPermission;
}
}
get tagRestricted() {
return this.tag?.staff;
}
get createTopicDisabled() {
return (
(this.category && !this.createTopicTargetCategory) ||
(this.tagRestricted && !this.currentUser.staff)
);
}
get categoryReadOnlyBanner() {
if (this.category && this.currentUser && this.createTopicDisabled) {
return this.category.read_only_banner;
}
}
get createTopicClass() {
const baseClasses = "btn-default sidebar-new-topic-button";
return this.categoryReadOnlyBanner
? `${baseClasses} disabled`
: baseClasses;
}
@action
createNewTopic() {
this.composer.openNewTopic({ category: this.category, tags: this.tag?.id });
}
@action
getCategoryandTag() {
this.category = this.router.currentRoute.attributes?.category || null;
this.tag = this.router.currentRoute.attributes?.tag || null;
}
@action
watchForComposer() {
// this covers opening drafts from the hamburger menu
this.appEvents.on("composer:will-open", this, this.closeHamburger);
}
@action
stopWatchingForComposer() {
this.appEvents.off("composer:will-open", this, this.closeHamburger);
}
@action
closeHamburger() {
this.header.hamburgerVisible = false;
}
<template>
{{#if this.shouldRender}}
<div
class="sidebar-new-topic-button__wrapper"
{{didInsert this.getCategoryandTag}}
{{didUpdate this.getCategoryandTag this.router.currentRoute}}
{{didInsert this.watchForComposer}}
{{willDestroy this.stopWatchingForComposer}}
>
<CreateTopicButton
@canCreateTopic={{this.canCreateTopic}}
@action={{this.createNewTopic}}
@disabled={{this.createTopicDisabled}}
@label="topic.create"
@btnClass={{this.createTopicClass}}
@canCreateTopicOnTag={{not this.tagRestricted}}
@showDrafts={{gt this.draftCount 0}}
/>
</div>
{{/if}}
</template>
}
@@ -0,0 +1,44 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { htmlSafe } from "@ember/template";
import DButton from "discourse/components/d-button";
import concatClass from "discourse/helpers/concat-class";
export default class UserColorPaletteMenuItem extends Component {
@service site;
@service session;
get siteStyle() {
return `--icon-color: ${this.args.colorPalette.accent}`;
}
get activeClass() {
if (this.args.selectedColorPaletteId === this.args.colorPalette.id) {
return "active";
}
}
@action
paletteSelected() {
this.args.paletteSelected(this.args.colorPalette);
}
<template>
<div
class="user-color-palette-menu__item"
data-color-palette={{@colorPalette.name}}
>
<DButton
class={{concatClass
"btn-flat user-color-palette-menu__item-choice"
this.activeClass
}}
style={{htmlSafe this.siteStyle}}
@icon="circle"
@translatedLabel={{@colorPalette.name}}
@action={{this.paletteSelected}}
/>
</div>
</template>
}
@@ -0,0 +1,210 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import { Promise } from "rsvp";
import concatClass from "discourse/helpers/concat-class";
import icon from "discourse/helpers/d-icon";
import { reload } from "discourse/helpers/page-reloader";
import { ajax } from "discourse/lib/ajax";
import {
listColorSchemes,
updateColorSchemeCookie,
} from "discourse/lib/color-scheme-picker";
import cookie from "discourse/lib/cookie";
import DMenu from "float-kit/components/d-menu";
import UserColorPaletteMenuItem from "./user-color-palette-menu-item";
const HORIZON_PALETTES = [
"Horizon",
"Marigold",
"Violet",
"Lily",
"Clover",
"Royal",
];
export default class UserColorPaletteSelector extends Component {
@service currentUser;
@service keyValueStore;
@service site;
@service session;
@service interfaceColor;
@tracked anonColorPaletteId = this.#loadAnonColorPalette();
@tracked userColorPaletteId = this.session.userColorSchemeId;
@tracked cssLoaded = true;
get userColorPalettes() {
const availablePalettes = listColorSchemes(this.site)
?.map((userPalette) => {
return {
...userPalette,
accent: `#${
userPalette.colors.find((color) => color.name === "tertiary").hex
}`,
};
})
.filter((userPalette) => {
return HORIZON_PALETTES.some((palette) => {
return userPalette.name.toLowerCase().includes(palette.toLowerCase());
});
})
.sort();
// Match the light scheme with the corresponding dark id based in the name
return (
availablePalettes
?.map((palette) => {
if (palette.is_dark) {
return palette;
}
const normalizedLightName = palette.name.toLowerCase();
const correspondingDarkModeId = availablePalettes.find(
(item) =>
item.is_dark &&
normalizedLightName ===
item.name.toLowerCase().replace(/\s+dark$/, "")
)?.id;
return {
...palette,
correspondingDarkModeId,
};
})
// Only want to show palettes that have corresponding light/dark modes
.filter((palette) => !palette.is_dark)
);
}
get selectedColorPaletteId() {
if (this.currentUser) {
return this.userColorPaletteId;
}
return this.anonColorPaletteId;
}
@action
onRegisterMenu(api) {
this.dMenu = api;
}
@action
paletteSelected(selectedPalette) {
if (selectedPalette.id === this.selectedColorPaletteId) {
return;
}
this.#updatePreference(selectedPalette);
this.#changeSiteColorPalette(selectedPalette);
this.dMenu.close();
}
#updatePreference(selectedPalette) {
updateColorSchemeCookie(selectedPalette.id);
updateColorSchemeCookie(selectedPalette.correspondingDarkModeId, {
dark: true,
});
if (!this.currentUser) {
this.anonColorPaletteId = selectedPalette.id;
} else {
this.userColorPaletteId = selectedPalette.id;
}
}
#loadAnonColorPalette() {
const storedAnonPaletteId = cookie("color_scheme_id");
if (storedAnonPaletteId) {
return parseInt(storedAnonPaletteId, 10);
}
}
async #changeSiteColorPalette(colorPalette) {
this.cssLoaded = false;
const lightPaletteId = colorPalette.id;
const darkPaletteId = colorPalette.correspondingDarkModeId;
const darkTag = document.querySelector("link.dark-scheme");
// TODO(osama) once we have built-in light/dark modes for each palette, we
// can stop making the 2nd ajax call for the dark palette and replace it
// with a include_dark_scheme param on the ajax call for the light
// palette which will include the href for the dark palette in the response
if (!darkTag) {
reload();
return;
}
const lightPaletteInfo = await ajax(
`/color-scheme-stylesheet/${lightPaletteId}/${colorPalette.theme_id}.json`
);
const darkPaletteInfo = await ajax(
`/color-scheme-stylesheet/${darkPaletteId}/${colorPalette.theme_id}.json`
);
Promise.all([
this.#preloadAndSwapCSS(lightPaletteInfo.new_href, "light-scheme"),
this.#preloadAndSwapCSS(darkPaletteInfo.new_href, "dark-scheme"),
]).then(() => {
this.cssLoaded = true;
});
}
#preloadAndSwapCSS(newHref, existingLinkClass) {
return new Promise((resolve) => {
const existingLink = document.querySelector(
`link[rel='stylesheet'].${existingLinkClass}`
);
const newTag = document.createElement("link");
newTag.rel = "preload";
newTag.href = newHref;
newTag.as = "style";
newTag.onload = () => {
existingLink.href = newHref;
newTag.remove();
resolve();
};
document.head.appendChild(newTag);
});
}
<template>
{{#unless (isEmpty this.userColorPalettes)}}
<DMenu
@identifier="user-color-palette-selector"
@placementStrategy="fixed"
@onRegisterApi={{this.onRegisterMenu}}
class={{concatClass
"btn-flat user-color-palette-selector sidebar-footer-actions-button"
(if this.cssLoaded "user-color-palette-css-loaded")
}}
data-selected-color-palette-id={{this.selectedColorPaletteId}}
@inline={{true}}
>
<:trigger>
{{icon "paintbrush"}}
</:trigger>
<:content>
<div class="user-color-palette-menu">
<div class="user-color-palette-menu__content">
{{#each this.userColorPalettes as |colorPalette|}}
<UserColorPaletteMenuItem
@selectedColorPaletteId={{this.selectedColorPaletteId}}
@colorPalette={{colorPalette}}
@paletteSelected={{this.paletteSelected}}
/>
{{/each}}
</div>
</div>
</:content>
</DMenu>
{{/unless}}
</template>
}
@@ -1,64 +1,76 @@
import { withPluginApi } from "discourse/lib/plugin-api";
import TopicAuthorAvatarColumn from "../components/card/topic-author-avatar-column";
import TopicAuthorColumn from "../components/card/topic-author-column";
import TopicActivityColumn from "../components/card/topic-activity-column";
import TopicCategoryColumn from "../components/card/topic-category-column";
import TopicLikesColumn from "../components/card/topic-likes-column";
import TopicCreatorColumn from "../components/card/topic-creator-column";
import TopicRepliesColumn from "../components/card/topic-replies-column";
import TopicStatusColumn from "../components/card/topic-status-column";
const TopicAuthor = <template>
<td class="topic-author-data">
<TopicAuthorColumn @topic={{@topic}} />
const TopicActivity = <template>
<td class="topic-activity-data">
<TopicActivityColumn @topic={{@topic}} />
</td>
</template>;
const TopicAuthorAvatar = <template>
<td class="topic-author-avatar-data">
<TopicAuthorAvatarColumn @topic={{@topic}} />
</td>
</template>;
const TopicCategoryStatus = <template>
<td class="topic-category-status-data">
<TopicCategoryColumn @topic={{@topic}} />
const TopicStatus = <template>
<td class="topic-status-data">
<TopicStatusColumn @topic={{@topic}} />
</td>
</template>;
const TopicLikesReplies = <template>
const TopicCategory = <template>
<td class="topic-category-data">
<TopicCategoryColumn @topic={{@topic}} />
</td>
</template>;
const TopicReplies = <template>
<td class="topic-likes-replies-data">
<TopicLikesColumn @topic={{@topic}} />
<TopicRepliesColumn @topic={{@topic}} />
</td>
</template>;
const TopicCreator = <template>
<td class="topic-creator-data">
<TopicCreatorColumn @topic={{@topic}} />
</td>
</template>;
export default {
name: "topic-list-customizations",
initialize() {
initialize(container) {
const router = container.lookup("service:router");
withPluginApi("1.39.0", (api) => {
api.registerValueTransformer(
"topic-list-columns",
({ value: columns }) => {
columns.add("topic-author", {
item: TopicAuthor,
after: "activity",
});
columns.add("topic-category-status", {
item: TopicCategoryStatus,
columns.add("topic-status", {
item: TopicStatus,
after: "topic-author",
});
columns.add("topic-author-avatar", {
item: TopicAuthorAvatar,
after: "topic-category-status",
columns.add("topic-category", {
item: TopicCategory,
after: "topic-status",
});
columns.add("topic-likes-replies", {
item: TopicLikesReplies,
item: TopicReplies,
after: "topic-author-avatar",
});
columns.add("topic-creator", {
item: TopicCreator,
after: "topic-author-avatar",
});
columns.delete("posters");
columns.delete("views");
columns.delete("replies");
if (!router.currentRouteName.includes("userPrivateMessages")) {
columns.add("topic-activity", {
item: TopicActivity,
after: "title",
});
columns.delete("posters");
columns.delete("activity");
}
return columns;
}
);
@@ -66,8 +78,15 @@ export default {
api.registerValueTransformer(
"topic-list-item-class",
({ value: classes, context }) => {
if (context.topic.pinned || context.topic.pinned_globally) {
classes.push("--pinned");
if (
context.topic.is_hot ||
context.topic.pinned ||
context.topic.pinned_globally
) {
classes.push("--has-status-card");
}
if (context.topic.replyCount > 1) {
classes.push("has-replies");
}
return classes;
}
@@ -76,6 +95,34 @@ export default {
api.registerValueTransformer("topic-list-item-mobile-layout", () => {
return false;
});
api.registerBehaviorTransformer(
"topic-list-item-click",
({ context: { event }, next }) => {
if (event.target.closest("a, button, input")) {
return next();
}
event.preventDefault();
event.stopPropagation();
const topicLink = event.target
.closest("tr")
.querySelector("a.raw-topic-link");
// Redespatch the click on the topic link, so that all key-handing is sorted
topicLink.dispatchEvent(
new MouseEvent("click", {
ctrlKey: event.ctrlKey,
metaKey: event.metaKey,
shiftKey: event.shiftKey,
button: event.button,
bubbles: true,
cancelable: true,
})
);
}
);
});
},
};
+4 -8
View File
@@ -1,12 +1,8 @@
en:
theme_metadata:
description: "A simple, beautiful theme for the future of Discourse that improves the out of the box experience for sites."
topic_bookmarked: "Bookmarked"
topic_closed_archived: "Closed and archived"
topic_closed: "Closed"
topic_archived: "Archived"
topic_warning: "Warning"
topic_personal_message: "Personal message"
description: "自制二次元的半透明主题"
topic_pinned: "Pinned"
topic_unpinned: "Unpinned"
topic_hot: "Hot"
user_replied: "replied"
user_posted: "posted"
user_updated: "updated"
-3
View File
@@ -1,3 +0,0 @@
#main-outlet-wrapper {
padding: 0;
}
+6 -5
View File
@@ -1,13 +1,14 @@
{
"private": true,
"devDependencies": {
"@discourse/lint-configs": "2.4.0",
"ember-template-lint": "6.1.0",
"eslint": "9.19.0",
"prettier": "2.8.8"
"@discourse/lint-configs": "2.25.0",
"ember-template-lint": "7.8.1",
"eslint": "9.28.0",
"prettier": "3.5.3",
"stylelint": "16.20.0"
},
"engines": {
"node": ">= 18",
"node": ">= 22",
"npm": "please-use-pnpm",
"yarn": "please-use-pnpm",
"pnpm": "9.x"
+1089 -1770
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View File
+80 -23
View File
@@ -1,4 +1,6 @@
@media screen and (min-width: 1300px) {
@use "lib/viewport";
@media screen and (width >= 1300px) {
#main-outlet {
border-top-right-radius: var(--d-border-radius-large);
border-top-left-radius: var(--d-border-radius-large);
@@ -17,32 +19,48 @@
}
}
.has-full-page-chat .experimental-screen {
display: none;
.has-full-page-chat .chat-replying-indicator-container {
margin-bottom: var(--main-grid-gap);
@include viewport.until(lg) {
margin-bottom: 0;
}
}
.has-full-page-chat .chat-selection-management {
margin-bottom: var(--main-grid-gap);
@include viewport.until(lg) {
margin-bottom: 0;
}
}
.experimental-screen {
@include breakpoint(medium) {
display: none;
}
max-width: unset !important;
.has-full-page-chat & {
display: none;
}
@media screen and (max-width: 488px) {
display: none;
}
width: 100%;
display: block;
margin: 0;
padding: 0;
position: relative;
container: content-width / inline-size;
@include viewport.until(lg) {
display: none;
}
@media screen and (width <= 488px) {
display: none;
}
@include viewport.until(md) {
display: none;
}
li {
list-style: none;
margin: 0;
padding: 0;
}
&__top-left,
&__top-right,
&__bottom-left,
@@ -52,38 +70,45 @@
height: var(--d-border-radius-large);
background-color: var(--background-color);
z-index: 399;
-webkit-mask: radial-gradient(
mask: radial-gradient(
circle at var(--d-border-radius-large) var(--d-border-radius-large),
transparent var(--d-border-radius-large),
transparent var(--d-border-radius-large),
black var(--d-border-radius-large)
);
}
&__top-left {
top: var(--header-offset);
left: var(--left-distance);
}
&__top-right {
top: var(--header-offset);
transform: rotate(90deg);
left: calc(var(--right-distance) - var(--d-border-radius-large));
}
&__bottom-left {
transform: rotate(-90deg);
bottom: var(--d-border-radius-large);
bottom: var(--main-grid-gap);
left: var(--left-distance);
@media screen and (max-width: 768px) {
@media screen and (width <= 768px) {
bottom: calc(var(--d-border-radius-large) * 2);
}
}
&__bottom-right {
transform: rotate(180deg);
bottom: var(--d-border-radius-large);
bottom: var(--main-grid-gap);
left: calc(var(--right-distance) - var(--d-border-radius-large));
@media screen and (max-width: 768px) {
@media screen and (width <= 768px) {
bottom: calc(var(--d-border-radius-large) * 2);
}
}
&__bottom-bar {
position: fixed;
width: 100%;
@@ -91,17 +116,49 @@
background-color: var(--background-color);
bottom: 0;
left: var(--left-distance);
height: var(--d-border-radius-large);
@media screen and (max-width: 768px) {
height: var(--main-grid-gap);
@media screen and (width <= 768px) {
height: calc(var(--d-border-radius-large) * 2);
}
@container content-width (width > 1px) {
width: 100cqw;
}
}
}
@media screen and (min-width: 768px) {
.rtl .experimental-screen {
&__top-left {
right: var(--left-distance);
left: unset;
}
&__top-right {
transform: rotate(-90deg) !important;
right: calc(var(--right-distance) - var(--d-border-radius-large));
left: unset;
}
&__bottom-left {
transform: rotate(90deg);
right: var(--left-distance);
left: unset;
}
&__bottom-right {
transform: rotate(180deg);
left: unset;
right: calc(var(--right-distance) - var(--d-border-radius-large));
}
&__bottom-bar {
right: var(--left-distance);
left: unset;
}
}
@media screen and (width >= 768px) {
.with-topic-progress {
bottom: calc(
env(safe-area-inset-bottom) + var(--composer-height, 0px) +
@@ -110,7 +167,7 @@
}
}
@media screen and (max-width: 768px) {
@media screen and (width <= 768px) {
.with-topic-progress {
bottom: calc(
env(safe-area-inset-bottom) + var(--composer-height, 0px) +
@@ -119,7 +176,7 @@
}
}
@media screen and (max-width: 400px) {
@media screen and (width <= 400px) {
.with-topic-progress {
bottom: calc(env(safe-area-inset-bottom) + var(--composer-height, 0px));
}
+67 -110
View File
@@ -6,148 +6,105 @@
transition: none;
}
.btn-default,
.btn-primary,
.btn-danger,
.select-kit .select-kit-header {
padding: var(--spacing-block-s) var(--spacing-inline-m);
// font-size: var(--font-up-1-rem);
// border-radius: var(--d-button-border-radius);
&.no-text {
padding-inline: 0.665rem;
}
}
.sidebar-new-topic-button__wrapper .topic-drafts-menu-trigger.btn.no-text {
background: var(--accent-color);
&:hover {
background: radial-gradient(
90% 110% at 50% 50%,
rgba(255, 255, 255, 0.3) 0%,
rgba(255, 255, 255, 0) 100%
),
var(--accent-color);
&:hover,
&:focus-visible {
background: oklch(from var(--accent-color) 40% c h) !important;
box-shadow: none;
}
svg {
.d-icon {
color: var(--accent-text-color);
}
}
.discourse-no-touch .dropdown-menu__item .btn {
background: transparent;
}
.discourse-no-touch .btn-default.sidebar-new-topic-button,
.discourse-no-touch .interface-color-selector-content .btn-default {
border: none;
&:hover {
border: none;
box-shadow: none;
}
}
.discourse-no-touch .btn-default.topic-drafts-menu-trigger {
border: none;
margin-left: 2px;
&:hover {
border: none;
box-shadow: none;
}
}
.btn-default {
border: 1px solid var(--primary-300);
background: var(--secondary);
.discourse-no-touch .btn-default,
.discourse-no-touch .select-kit .select-kit-header.btn-default {
background: var(--primary-100);
.d-icon {
color: var(--accent-color);
}
&:hover {
.discourse-no-touch & {
border: 1px solid var(--accent-color);
box-shadow: 0px 0px 8px 2px var(--button-box-shadow);
background: var(--secondary);
color: var(--primary);
.d-icon {
color: var(--accent-color);
}
}
}
&:focus-visible {
.discourse-no-touch & {
background: var(--secondary);
border-color: transparent;
box-shadow: 0 0 8px 1px var(--button-box-shadow);
background: var(--d-content-background);
color: var(--accent-color);
.d-icon {
color: var(--accent-color);
box-shadow: 0px 0px 0px 2px var(--secondary),
0px 0px 0px 4px var(--button-box-shadow);
.d-icon {
color: var(--accent-color);
}
}
}
}
//not shared with select-kit
.btn-default {
&:active {
.discourse-no-touch & {
color: var(--secondary);
background: oklch(from var(--accent-color) 30% c h) !important;
.d-icon {
color: var(--secondary);
}
}
}
&:focus-visible {
background: var(--d-content-background);
color: var(--accent-color);
box-shadow: 0 0 0 3px var(--button-box-shadow);
.d-icon {
color: var(--accent-color);
}
}
&:active:not(:hover, :focus) {
color: var(--primary);
background: var(--tertiary-300);
background-image: none;
.d-icon {
color: var(--tertiary-high);
}
}
}
.btn-primary,
#create-topic.btn {
#create-topic.btn,
.discourse-no-touch .btn-default.ai-new-question-button {
background-color: var(--accent-color);
color: var(--accent-text-color);
.d-icon {
color: var(--accent-text-color);
}
&:hover {
.discourse-no-touch & {
background: radial-gradient(
90% 110% at 50% 50%,
rgba(255, 255, 255, 0.3) 0%,
rgba(255, 255, 255, 0) 100%
),
var(--accent-color);
box-shadow: 0px 0px 6px 1px var(--button-box-shadow);
background: light-dark(
oklch(from var(--accent-color) 40% c h),
oklch(from var(--accent-color) 50% c h)
);
box-shadow: 0 0 6px 1px var(--button-box-shadow);
color: var(--accent-text-color);
.d-icon {
color: var(--accent-text-color);
}
}
}
&:focus-visible {
.discourse-no-touch & {
background: radial-gradient(
90% 110% at 50% 50%,
rgba(255, 255, 255, 0.3) 0%,
rgba(255, 255, 255, 0) 100%
),
var(--accent-color);
box-shadow: 0px 0px 0px 2px var(--secondary),
0px 0px 0px 4px var(--button-box-shadow);
background: light-dark(
oklch(from var(--accent-color) 40% c h),
oklch(from var(--accent-color) 50% c h)
);
box-shadow: 0 0 0 4px var(--button-box-shadow);
color: var(--accent-text-color);
}
}
&:active {
.discourse-no-touch & {
// background: radial-gradient(
// 65% 95% at 50% 50%,
// rgba(0, 0, 0, 0.4) 0%,
// rgba(0, 0, 0, 0) 100%
// ),
// var(--accent-color) !important;
background: oklch(from var(--accent-color) 30% c h) !important;
}
background: light-dark(
oklch(from var(--accent-color) 40% c h),
oklch(from var(--accent-color) 50% c h)
);
}
}
.post-controls {
svg.d-icon {
color: inherit !important; //something we should honestly implement in core imo, when do we ever NOT want the same colour for icon and text?
}
}
//undoing the outline for select-kit, since Im using a custom visual cue
.select-kit.single-select.is-expanded .select-kit-header:not(.btn),
.select-kit.single-select .select-kit-header:not(.btn):focus,
.select-kit.single-select .select-kit-header:not(.btn):active {
outline: transparent;
border-color: var(--accent-color);
}
+363
View File
@@ -0,0 +1,363 @@
@use "lib/viewport";
.categories-and-latest {
.category-list {
border-collapse: separate;
th.topics,
.category-logo {
display: none;
}
thead tr th {
font-size: var(--font-up-1-rem);
font-weight: bold;
}
tbody {
display: flex;
flex-direction: column;
gap: 1em;
padding-top: 1em;
border: 0;
}
tbody tr {
display: grid;
grid-template-areas:
"title topics"
"category category"
"subcategory subcategory";
row-gap: 1em;
border: 1px solid var(--primary-300);
border-radius: var(--d-border-radius-large);
box-shadow: 0 0 12px 1px var(--topic-card-shadow);
}
td.category {
display: contents;
border-top-left-radius: var(--d-border-radius-large);
border-bottom-left-radius: var(--d-border-radius-large);
border-width: 2px;
padding: 1em 1.5rem;
}
tbody h3 {
grid-area: title;
padding: 1em 0 0 1.5rem;
font-size: var(--font-up-1-rem);
.category-name {
display: flex;
align-self: center;
}
.badge-category {
gap: 0.25em;
align-items: center;
font-size: var(--font-up-1-rem);
.d-icon:first-of-type:not(.d-icon-lock),
&.--style-square::before,
&.--style-emoji .emoji {
width: 1.25em;
height: 1.25em;
margin-right: 0.25em;
}
&.--style-square::before {
border-radius: 6px;
}
}
.d-icon.d-icon-lock {
order: 1;
}
}
.topics {
width: auto;
padding: 1em 1.5rem 0 0;
display: flex;
align-items: center;
justify-content: end;
}
.category-description {
grid-area: category;
padding: 0 1.5rem;
margin: 0;
font-size: var(--font-down-1-rem);
}
.subcategories {
grid-area: subcategory;
gap: 0.25em 0.5em;
padding: 0 1.5rem 1em;
margin: 0;
.badge-category__wrapper {
background-color: light-dark(
oklch(from var(--category-badge-color) 98% calc(c * 0.2) h),
oklch(from var(--category-badge-color) 45% calc(c * 0.5) h)
);
padding: 0.25em 0.5rem;
border-radius: var(--d-border-radius);
}
.badge-category__name {
color: light-dark(
oklch(from var(--category-badge-color) 20% calc(c * 1) h),
oklch(from var(--category-badge-color) 100% calc(c * 0.9) h)
);
}
.badge-category.--style-square::before {
border-radius: 3px;
}
}
}
.latest-topic-list {
.table-heading {
border: 0;
font-size: var(--font-up-1-rem);
font-weight: bold;
}
&-item {
display: grid;
grid-template-columns: min-content min-content auto min-content;
grid-template-areas:
"creator title title status"
". category activity activity";
grid-column-gap: 0.75rem;
grid-row-gap: 0.5rem;
background: var(--d-content-background);
box-shadow: 0 0 12px 1px var(--topic-card-shadow);
text-overflow: ellipsis;
padding: 0.75em 1rem;
border: 1px solid var(--primary-300);
border-radius: var(--d-border-radius-large);
margin-top: 1em;
}
.main-link,
.topic-stats {
display: contents;
}
.top-row {
grid-area: title;
}
.bottom-row {
grid-area: category;
.discourse-tags {
display: none;
}
}
.badge-category__wrapper {
border-radius: var(--d-border-radius);
padding: 0.25em 0.5rem;
background-color: light-dark(
oklch(from var(--category-badge-color) 97% calc(c * 0.3) h),
oklch(from var(--category-badge-color) 45% calc(c * 0.5) h)
);
@include viewport.until(md) {
padding: 0.25em 0.5rem;
font-size: var(--font-down-2);
}
.badge-category__name {
color: light-dark(
oklch(from var(--category-badge-color) 20% calc(c * 1) h),
oklch(from var(--category-badge-color) 100% calc(c * 0.9) h)
);
}
}
.topic-list-data {
grid-area: likes-replies;
}
.num.posts-map {
display: none;
}
.topic-last-activity {
grid-area: activity;
display: flex;
align-items: center;
text-align: left;
font-size: var(--font-down-1-rem);
&::before {
content: "";
display: inline-block;
width: 0.25em;
height: 0.25em;
background-color: var(--primary-500);
border-radius: 100%;
margin-right: 0.5em;
}
}
.topic-poster {
grid-area: creator;
width: auto;
align-self: flex-start;
.avatar {
height: 24px;
width: 24px;
border-radius: var(--d-border-radius-small);
}
}
}
}
@include viewport.until(sm) {
.category-list.with-topics {
margin-inline: 1rem;
.num.posts,
.category-topics-count,
.category-logo {
display: none;
}
.category-list {
&-item {
padding-top: 0;
padding-bottom: 0;
border-top: 0 !important;
border-bottom: 0 !important;
}
}
tbody {
display: flex;
flex-direction: column;
tr:first-of-type {
order: -2;
}
tr.subcategories-list {
order: -1;
}
tr:nth-last-of-type(2) {
border-bottom: 0;
}
}
th.main-link {
padding-top: 0;
}
}
}
.category-boxes.with-subcategories {
.category-logo {
display: none;
}
@include viewport.from(sm) {
margin-top: 0;
}
@include viewport.until(md) {
padding-inline: 1rem;
box-sizing: border-box;
}
.category {
border: 0;
&-box-inner {
border-radius: var(--d-border-radius-large);
border: 1px solid var(--primary-300);
background: var(--d-content-background);
box-shadow: 0 0 12px 1px var(--topic-card-shadow);
&:hover {
.discourse-no-touch & {
border-color: var(--accent-color);
background: var(--d-content-background);
}
}
&.selected {
box-shadow:
0 0 0 2px var(--accent-color),
0 0 12px 1px var(--topic-card-shadow);
}
}
&-details {
display: flex;
flex-direction: column;
gap: 1rem;
height: 100%;
}
&-box-heading {
h3 {
text-align: left;
}
.badge-category {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: 1em;
justify-content: space-between;
width: 100%;
&__wrapper {
display: flex;
}
&.--style-square::before {
aspect-ratio: 1 / 1;
height: auto;
width: 13%;
border-radius: var(--d-border-radius);
}
&__name {
flex-basis: 100%;
font-size: var(--font-up-1-rem);
}
.d-icon:not(.d-icon-lock),
img.emoji {
aspect-ratio: 1 / 1;
height: auto;
width: 13%;
}
}
}
.description {
text-align: left;
margin: 0;
font-size: var(--font-down-1-rem);
}
.subcategories {
margin-top: auto;
row-gap: 0.5em;
.subcategory {
margin-bottom: 0;
font-size: var(--font-down-1);
}
}
}
}
+60 -9
View File
@@ -1,13 +1,13 @@
@use "lib/viewport";
.full-page-chat.full-page-chat-sidebar-enabled {
border-top-left-radius: var(--d-border-radius-large);
border-top-right-radius: var(--d-border-radius-large);
border: none;
}
.c-navbar-container {
border-top-left-radius: var(--d-border-radius-large);
border-top-right-radius: var(--d-border-radius-large);
padding: 0 1.5em;
.full-page-chat & {
padding: 0 1.5em;
}
background-color: var(--d-content-background);
}
@@ -15,16 +15,45 @@ body.has-full-page-chat {
background-color: var(--background-color);
}
.chat-drawer .chat-drawer-container {
box-shadow: 0px 0px 0px 2px var(--d-chat-border);
border: none;
.chat-drawer-container {
.is-expanded & {
box-shadow: 0 0 0 2px var(--tertiary-medium);
}
.chat-drawer.is-expanded & {
border: none;
}
.c-navbar__title {
padding-left: 0.33em; // visual alignment for chat index, which does not havea a backarrow
}
}
.chat-drawer-outlet-container {
z-index: z("composer", "content");
.peek-mode-active & {
padding-bottom: 0;
left: unset;
right: var(--main-grid-gap);
&:has(.is-expanded) {
z-index: calc(z("composer", "dropdown") + 1);
}
}
}
.chat-drawer {
.peek-mode-active & {
max-width: 90vw;
}
}
.chat-drawer .channels-list-container .chat-channel-row {
margin-bottom: var(--spacing-block-xs);
font-size: var(--font-up-1);
border-radius: var(--d-border-radius);
border-bottom: none;
&:hover {
background-color: var(--d-sidebar-active-background);
}
@@ -35,3 +64,25 @@ body.has-full-page-chat {
text-transform: uppercase;
font-size: var(--font-down-1);
}
.chat-composer__wrapper {
background: var(--d-content-background);
}
.chat-message-actions .more-buttons .btn-icon-text {
&:hover {
background-color: var(--d-selected);
box-shadow: none;
color: var(--primary);
}
}
.chat-drawer-active.chat-drawer-expanded .chat-composer-dropdown__menu-content {
z-index: z("modal", "dialog");
}
.chat-replying-indicator-container {
@include viewport.from(sm) {
margin-left: calc(0.65em + 0.2rem);
}
}
+29
View File
@@ -0,0 +1,29 @@
.user-color-palette-menu {
&__item .btn-icon-text.btn-flat {
background-color: var(--d-content-background);
width: 100%;
justify-content: flex-start;
}
&__item .btn-icon-text.btn-flat:hover {
background-color: var(--d-selected);
box-shadow: none;
color: var(--primary);
}
&__item .btn-icon-text.btn-flat:hover svg {
color: var(--icon-color);
}
&__item .btn-icon-text.btn-flat svg {
color: var(--icon-color);
}
&__item-choice.active.btn-icon-text.btn-flat {
background-color: var(--d-selected);
}
}
.user-color-palette-content .fk-d-menu__inner-content {
border: none;
}
+26
View File
@@ -0,0 +1,26 @@
:root {
--d-sidebar-highlight-hover-icon: var(--d-sidebar-link-color);
--d-sidebar-highlight-hover-background: var(--d-selected);
--d-sidebar-link-icon-color: var(--d-sidebar-link-color);
--d-sidebar-header-color: var(--d-sidebar-link-color);
--d-sidebar-header-icon-color: var(--d-sidebar-link-color);
--d-sidebar-active-suffix-color: var(--d-sidebar-suffix-color);
--d-sidebar-background: var(--background-color);
--d-sidebar-footer-fade: rgb(var(--tertiary-50-rgb), 1);
--d-sidebar-prefix-background: var(--d-selected);
--d-sidebar-active-prefix-background: light-dark(
oklch(from var(--d-selected) calc(l * 0.85) c h),
oklch(from var(--d-selected) calc(l * 0.7) c h)
);
--d-sidebar-highlight-prefix-background: light-dark(
oklch(from var(--d-selected) calc(l * 0.85) c h),
oklch(from var(--d-selected) calc(l * 0.7) c h)
);
--d-sidebar-highlight-suffix-color: var(--d-sidebar-active-suffix-color);
--d-sidebar-highlight-color: var(--primary);
--d-sidebar-highlight-background: var(--d-selected);
--d-sidebar-section-link-icon-size: 1em;
--d-hover: oklch(from var(--d-selected) l c h / 0.75);
--d-input-bg-color: var(--d-content-background);
--d-sidebar-active-color: var(--primary) !important;
}
+65
View File
@@ -0,0 +1,65 @@
.peek-mode-toggle {
display: none;
}
@media screen and (width >= 1300px) {
html:not(.fullscreen-composer) {
.peek-mode-toggle svg {
transform: scaleX(-1);
}
&.composer-open {
.full-width-enabled .peek-mode-toggle {
display: flex;
}
.full-width-enabled.peek-mode-active {
#reply-control.hide-preview {
transition: none;
box-shadow: none;
border-radius: var(--d-border-radius-large);
.grippie {
display: none;
}
.reply-area {
padding-inline: 0.67em;
}
}
#reply-control:not(.fullscreen).hide-preview {
width: 100%;
right: var(--main-grid-gap);
top: var(--header-offset);
bottom: var(--main-grid-gap);
left: unset;
height: unset;
max-width: 36.5vw;
}
&.has-sidebar-page {
#main-outlet-wrapper {
grid-template-columns:
var(--d-sidebar-width) calc(100vw - 38vw - var(--d-sidebar-width))
1fr;
}
}
&:not(.has-sidebar-page) {
#main-outlet-wrapper {
grid-template-columns: 0 calc(100vw - 52vw) 1fr;
}
#reply-control:not(.fullscreen).hide-preview {
max-width: 46vw;
}
}
.sidebar-wrapper .sidebar-container {
height: unset;
}
}
}
}
}
+121
View File
@@ -0,0 +1,121 @@
@use "lib/viewport";
#reply-control
.select-kit.dropdown-select-box.composer-actions
.select-kit-header {
border: 1px solid var(--tertiary-700);
background: var(--secondary);
&:hover {
.d-icon {
color: var(--accent-color);
}
}
}
#reply-control.hide-preview:not(.draft) {
@include viewport.from(sm) {
background: var(--d-content-background);
border-top-right-radius: var(--d-border-radius);
border-top-left-radius: var(--d-border-radius);
.grippie {
background: var(--tertiary-low);
border-top-right-radius: var(--d-border-radius);
border-top-left-radius: var(--d-border-radius);
}
.user-selector,
.title-and-category {
padding: 0 var(--spacing-inline-m);
width: calc(100% - var(--spacing-inline-m) * 2);
}
.d-editor-button-bar {
padding: 3px var(--spacing-inline-m);
border: none;
}
.d-editor-input {
padding: var(--spacing-inline-m);
}
&:has(.in-focus) .grippie {
background: var(--tertiary);
}
.reply-area {
padding-inline: 0;
}
.reply-to,
.submit-panel {
padding-inline: var(--spacing-inline-sm);
}
.d-editor-textarea-wrapper {
border: 0;
border-bottom: 1px solid var(--primary-low);
border-radius: 0;
&.in-focus {
outline: 0;
}
}
}
}
.d-editor-button-bar {
.btn:hover,
.toolbar-popup-menu-options.is-expanded {
.discourse-no-touch & {
background: var(--tertiary-very-low);
color: var(--accent-color);
.d-icon {
color: inherit;
}
// to have parity with regular select-kit styling used elsewhere
.select-kit-row {
.d-icon {
color: var(--primary-high);
}
&:hover {
.d-icon {
color: var(--primary);
}
}
}
}
}
.toolbar-popup-menu-options.is-expanded {
border-radius: var(--d-border-radius);
}
}
.discourse-no-touch .translation-selector-dropdown {
.select-kit-header.btn-default {
background: var(--background-color);
}
}
#reply-control.composer-action-add_translation {
.d-editor-preview .d-editor-translation-preview-wrapper {
border-color: var(--d-sidebar-border-color);
}
.d-editor-preview .d-editor-translation-preview-wrapper__header {
top: 6.5rem;
padding: 0.25rem 0.75rem;
background: var(--background-color);
color: var(--accent-color);
border-radius: var(--d-border-radius-large);
}
.topic-title-translator input {
width: 47.25vw;
}
}
+276
View File
@@ -0,0 +1,276 @@
@use "lib/viewport";
// Full width layout. Ported from the Discourse Full Width theme component here
// https://meta.discourse.org/t/discourse-full-width-component/292496, which we
// intend to move into core over time.
//
// We are copying this here so we can continue to iterate on Horizon with full
// width without having to include the theme component as a dependency, we
// need to remove this once full width is in core.
$sidebar-width: 17em;
.wrap {
max-width: unset; // undoing core default
}
.d-header #site-logo {
// this prevents the logo from shifting header content
// when the sidebar is opened
max-height: 100%;
max-width: 100%;
object-fit: contain; // contains logo without squishing/stretching
// allows some flexibility for wide logos
body:not(.has-sidebar-page) & {
max-width: unset;
@include viewport.until(sm) {
max-width: 25vw;
}
}
}
.d-header #site-text-logo {
font-size: clamp(var(--font-0), 2.5vw, var(--font-up-2));
.has-sidebar-page & {
white-space: wrap;
line-height: var(--line-height-medium);
@include line-clamp(2);
}
}
#main-outlet-wrapper {
padding: 0;
body.has-sidebar-page & {
.sidebar-wrapper {
width: var(--d-sidebar-width);
}
}
body.has-full-page-chat & {
gap: 0;
}
.sidebar-wrapper {
width: 100%; // safari has issues without this
}
#main-outlet {
margin: 0 auto;
max-width: var(--d-max-width);
width: 100%;
body.has-full-page-chat & {
max-width: unset;
}
}
}
.has-full-page-chat:not(.discourse-sidebar) .full-page-chat {
border: none;
}
#main-outlet > .regular {
max-width: var(--d-max-width);
margin: 0 auto;
body.has-sidebar-page & {
margin: 0 auto;
}
}
.d-header .title:not(.title--minimized) {
// allowing overflow here isn't always ideal
// but works well enough most of the time
overflow: visible;
}
.d-header {
> .wrap {
.contents {
display: grid;
grid-template-areas: "logo lspace extra-info rspace panel";
grid-template-columns:
minmax(auto, 1fr)
auto
minmax(0, calc(var(--d-max-width)))
auto
minmax(auto, 1fr);
.d-header-mode {
grid-area: extra-info;
white-space: nowrap;
@include viewport.until(md) {
display: none;
}
}
.d-header .title {
min-width: auto;
}
.has-sidebar-page & {
// at wide widths, when 1fr > 0
// we want the panel to be the same width as the sidebar
// this way we can get more accurate centering
grid-template-columns:
calc(var(--d-sidebar-width) - 11px) // 11px is wrap padding
1fr
minmax(0, calc(var(--d-max-width)))
1fr
minmax(0, calc(var(--d-sidebar-width) - 11px));
gap: 1em;
// at narrower widths, when 1fr = 0
// we can center without matching the sidebar's width
// which allows the title to take up the remaining width
@media screen and (width <= 1400px) {
grid-template-columns:
calc(var(--d-sidebar-width) - 11px)
1fr
minmax(0, calc(var(--d-max-width)))
1fr
auto;
}
@media screen and (width <= 1000px) {
gap: 0.5em;
}
.d-header-mode {
grid-area: extra-info;
}
}
}
}
.header-sidebar-toggle {
grid-area: logo;
}
.before-header-panel-outlet {
grid-area: extra-info;
}
.d-header-mode {
.bootstrap-mode {
display: none;
}
}
.home-logo-wrapper-outlet {
grid-area: logo;
margin-left: 3.7em; // 2.7em hamburger width + 1em for margin
margin-right: 0.725em;
display: flex;
overflow: visible;
.title {
flex: 1 1 auto;
}
}
.panel {
grid-area: panel;
}
}
.extra-info-wrapper {
grid-area: extra-info;
max-width: var(--d-max-width);
width: 100%;
box-sizing: border-box;
padding: 0;
}
.header-search--enabled .floating-search-input-wrapper {
grid-area: extra-info;
@include viewport.until(md) {
grid-area: rspace;
}
@include viewport.until(sm) {
display: none;
}
}
body.has-sidebar-page {
.wrap {
max-width: unset; // undoing core default
}
.d-header-mode,
.extra-info-wrapper {
padding: 0;
}
@media screen and (width >= calc($reply-area-max-width + ($sidebar-width * 2))) {
#reply-control.show-preview {
margin-left: auto;
margin-right: auto;
}
.sidebar-container {
height: auto;
}
}
@media screen and (width <= calc($reply-area-max-width + ($sidebar-width * 2))) and (width >= calc($reply-area-max-width + calc($sidebar-width / 2))) {
#reply-control.show-preview:not(.fullscreen) {
margin-left: $sidebar-width;
width: auto;
// overruling new core composer changes
max-width: $reply-area-max-width;
transform: none;
}
.sidebar-container {
height: auto;
}
}
// overruling new core composer changes
@media screen and (min-width: $reply-area-max-width) {
#reply-control.show-preview:not(.fullscreen) {
max-width: $reply-area-max-width;
transform: none;
}
}
}
body.sidebar-animate {
#main-outlet-wrapper {
transition: none;
}
.d-header-wrap .wrap {
transition: none;
}
}
.d-header-icons {
display: flex;
}
.rtl {
.d-header .title {
margin-right: 3.7em; // 2.7em hamburger width + 1em for margin
margin-left: 0.725em;
}
}
// provides some extra space for login buttons
@media screen and (width >= 1400px) {
.anon {
.d-header .panel {
grid-column-start: -4;
}
}
}
+83
View File
@@ -0,0 +1,83 @@
// Fixing bulk select (only needed for desktop)
.bulk-select-enabled {
.topic-list-header {
position: relative;
top: 0;
z-index: 2;
}
.topic-author-avatar-data {
display: none;
}
.bulk-select.topic-list-data {
grid-area: bulk-select;
margin-left: -0.5em;
@media screen and (width <= 576px) {
margin-top: 0;
label {
padding-block: 0.345em;
}
}
input {
transform: scale(1.5);
}
}
}
.topic-list-header {
position: relative;
margin-bottom: 0.35rem;
tr {
border: none;
}
.topic-list-data {
padding: 0.25rem 0;
color: var(--primary-600);
font-size: var(--font-down-2);
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
background: transparent;
&:not(.default) {
display: none;
}
&.default {
border-radius: var(--d-border-radius);
.bulk-select,
span:not(.bulk-select-topics, .d-button-label) {
display: none;
}
}
}
// bulk select
.bulk-select-topics {
position: absolute;
right: 0.25rem;
top: 50%;
transform: translateY(-50%);
background: color-mix(in srgb, var(--d-content-background) 88%, white 12%);
border: 1px solid var(--primary-200);
border-radius: 999px;
box-shadow: 0 6px 18px -12px rgb(10 18 35 / 35%);
display: flex;
gap: 0.5rem;
margin: 0;
padding: 0.25rem;
button {
white-space: nowrap;
margin: 0;
border-radius: 999px;
}
}
}
+64 -6
View File
@@ -1,13 +1,12 @@
@use "lib/viewport";
.d-header {
box-shadow: none;
background: var(--background-color);
@include breakpoint(extra-large, $rule: min-width) {
padding-bottom: 1.5em;
}
}
.has-full-page-chat .d-header {
background-color: transparent;
@include viewport.from(xl) {
padding-bottom: var(--main-grid-gap);
}
}
.user-menu .quick-access-panel,
@@ -30,3 +29,62 @@
.user-menu.revamped .tabs-list .btn.active {
background: var(--d-hover);
}
.discourse-no-touch .d-header-icons .icon:hover,
.discourse-no-touch .d-header-icons .icon:focus,
.header-sidebar-toggle button:focus:hover,
.discourse-no-touch .header-sidebar-toggle button:hover {
background-color: transparent;
}
.discourse-no-touch .d-header-icons .icon:hover > .d-icon,
.drop-down-mode .d-header-icons .active .icon > .d-icon,
.drop-down-mode
.d-header-icons
.header-color-scheme-toggle
.-expanded
> .d-icon,
.discourse-no-touch .header-sidebar-toggle button:hover .d-icon {
color: var(--header_primary-medium);
}
.discourse-no-touch .interface-color-selector-content {
border: none;
border-radius: var(--d-border-radius);
.btn {
border: none;
&:hover {
box-shadow: none;
}
}
}
.drop-down-mode .d-header-icons .active .icon,
.drop-down-mode .d-header-icons .header-color-scheme-toggle .-expanded {
border-color: transparent;
background-color: transparent;
}
.badge-notification {
color: var(--accent-text-color);
}
body.login-page,
body.signup-page,
body.invite-page,
body.password-reset-page,
body.activate-account-page {
.d-header {
background: var(--background-color);
}
}
.header-dropdown-toggle.chat-header-icon .icon .chat-channel-unread-indicator {
border-color: var(--background-color);
}
.d-header-icons .badge-notification {
border-color: var(--background-color);
}
+1 -4
View File
@@ -1,10 +1,7 @@
.sidebar__panel-switch-button,
.sidebar-section[data-section-name="messages"],
.list-controls #create-topic,
.notifications-button-footer .reason .text,
.pinned-button .reason .text,
.more-topics__browse-more,
//footer-message might cause issues, not sure what possible stuff can be in there, but the general idea is to hide it bcs having an ugly H3 (what?) CTA at the bottom is just ugly imo
.footer-message {
.more-topics__browse-more {
display: none;
}
+15
View File
@@ -0,0 +1,15 @@
body.static-login {
#main-outlet-wrapper {
grid-template-areas:
"sidebar blank"
"sidebar content"
"sidebar below-content";
grid-template-rows: auto 1fr auto;
}
.login-welcome {
border-radius: none;
border: none;
box-shadow: none;
}
}
+101 -77
View File
@@ -1,11 +1,23 @@
html:not(:has(.has-full-page-chat)) {
// @include breakpoint(extra-large, $rule: min-width) {
background-color: var(--background-color);
// }
}
@use "lib/viewport";
:root {
--main-grid-gap: 2em;
--main-grid-gap: 0.5em;
}
html:not(:has(.has-full-page-chat)) {
background-color: var(--background-color);
@include viewport.until(sm) {
background-color: var(--d-content-background);
}
}
body {
-webkit-font-smoothing: antialiased;
@include viewport.until(sm) {
background-color: var(--d-content-background);
}
}
#main-outlet-wrapper {
@@ -14,94 +26,99 @@ html:not(:has(.has-full-page-chat)) {
body.has-sidebar-page.has-full-page-chat #main-outlet-wrapper {
grid-column-gap: var(--main-grid-gap);
background-color: var(--background-color);
}
body.has-full-page-chat:not(.has-sidebar-page) {
.d-header {
background-color: var(--background-color);
}
#main-outlet-wrapper {
--main-grid-gap: 0;
.full-page-chat.full-page-chat-sidebar-enabled,
.c-navbar-container {
border-top-right-radius: 0;
border-top-left-radius: 0;
gap: var(--main-grid-gap);
@include viewport.until(lg) {
gap: 0;
}
}
}
body.has-sidebar-page #main-outlet-wrapper {
grid-template-columns: var(--d-sidebar-width) 1fr 0px;
grid-template-columns: var(--d-sidebar-width) minmax(0, 1fr) 0;
#main-outlet {
max-width: unset;
}
}
body:not(.has-full-page-chat) {
@include breakpoint(extra-large, $rule: min-width) {
background-color: var(--background-color);
body:not(.has-sidebar-page) #main-outlet-wrapper {
@include viewport.from(lg) {
grid-template-columns: 0 minmax(0, 1fr) 0;
}
#main-outlet-wrapper {
@include breakpoint(medium) {
--main-grid-gap: 0;
}
@include breakpoint(tablet, $rule: min-width) {
gap: var(--main-grid-gap);
}
// height: calc(100vh - var(--header-offset) - 4rem);
// box-sizing: border-box;
// > * {
// height: inherit;
// box-sizing: border-box;
// }
#main-outlet {
width: 100%;
padding-bottom: var(--spacing-block-l);
// height: inherit;
// overflow: scroll;
// &:has(.list-controls) {
// padding-top: 0;
// }
// &:has(#topic-title) {
// padding-top: 0;
// }
//thanks to random container elements on the page, I can't do a direct child selector here because it targets all the randomness, so I see no other option than MANUALLY adding every possible element that can appear in the main outlet YAY
.list-controls,
.list-container,
#topic-title,
.container.posts,
#topic-footer-buttons,
.more-topics__container,
.search-banner,
.container.viewing-self,
.reviewable,
.admin-content,
.discourse-post-event-upcoming-events,
.container.groups-index,
.body-page,
.container.badges,
.topic-above-footer-buttons-outlet .presence-users,
.global-notice {
max-width: 1000px;
margin-inline: auto;
padding-inline: 1.5em;
}
border-radius: var(--d-border-radius-large);
@include breakpoint(medium) {
border-radius: 0px;
}
border-radius: 1.25rem;
// box-shadow: 0px 0px 1px 2px #e2e8f8, 0px 0px 24px 4px #e2e8f8;
background-color: var(--d-content-background);
}
}
// .global-notice {
// margin-top: var(--spacing-block-m);
// }
}
.list-container {
body:not(.has-full-page-chat, .wizard) {
@include viewport.from(xl) {
background-color: var(--background-color);
}
#main-outlet-wrapper {
@include viewport.until(lg) {
--main-grid-gap: 0;
}
@media screen and (width >= 768px) {
gap: var(--main-grid-gap);
}
#main-outlet {
width: 100%;
max-width: unset;
padding-bottom: var(--spacing-block-l);
border-radius: var(--d-border-radius-large);
background-color: var(--d-content-background);
@include viewport.until(lg) {
border-radius: 0;
}
html.composer-open & {
padding-bottom: var(--composer-height);
}
> *:not(.experimental-screen, .activate-account) {
@include viewport.from(lg) {
box-sizing: border-box;
max-width: 1000px;
margin-inline: auto;
padding-inline: var(--spacing-inline-l);
}
}
}
}
}
@include viewport.until(sm) {
.welcome-banner {
display: none;
}
}
#list-area {
.show-more.has-topics {
@include viewport.from(lg) {
width: auto;
right: 50%;
transform: translateX(50%);
.alert {
padding: var(--spacing-block-sm) var(--spacing-inline-m);
border-radius: var(--d-border-radius-large);
font-size: var(--font-down-1-rem);
}
}
}
.topic-list-body {
padding-top: var(--spacing-block-m);
}
@@ -112,9 +129,16 @@ aside.onebox {
}
.d-editor-preview-wrapper {
box-shadow: 0px 0px 1px 2px var(--tertiary-50),
0px 0px 24px 4px var(--tertiary-50);
border-radius: var(--d-border-radius-large);
border-radius: var(--d-border-radius);
padding: 1em;
background-color: var(--d-content-background);
}
.no-ember {
#main-outlet {
border-radius: var(--d-border-radius-large);
margin: 0 var(--main-grid-gap) var(--main-grid-gap) var(--main-grid-gap);
padding: 2em;
max-height: calc(100vh - 50px - 1em - var(--main-grid-gap));
}
}
+97 -6
View File
@@ -1,3 +1,5 @@
@use "lib/viewport";
.user-main .about.collapsed-info .details {
background: var(--d-content-background);
}
@@ -8,7 +10,7 @@
}
.powered-by-discourse {
z-index: 9999;
z-index: 400;
}
.boxed.white {
@@ -40,11 +42,100 @@
border-radius: 0;
}
.d-editor-button-bar {
padding: 3px;
.open .grippie {
background-color: var(--accent-color);
}
a,
a:visited {
color: var(--accent-color);
.d-editor-textarea-wrapper.in-focus,
input[type="text"]:focus,
input[type="password"]:focus,
input[type="datetime"]:focus,
input[type="datetime-local"]:focus,
input[type="date"]:focus,
input[type="month"]:focus,
input[type="time"]:focus,
input[type="week"]:focus,
input[type="number"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="search"]:focus,
input[type="tel"]:focus,
input[type="color"]:focus,
.select-kit.multi-select.is-expanded .multi-select-header,
.select-kit.multi-select .multi-select-header:focus {
border-color: var(--accent-color);
outline: 2px solid var(--accent-color);
}
#reply-control {
background-color: var(--background-color);
}
@include viewport.until(sm) {
// pinned topic excerpts are hidden on small screens too
.fk-d-menu__trigger.topic-list-layout-trigger {
display: none;
}
}
.search-container .search-header,
.search-container .search-bar,
.search-container .search-filters,
.search-container .search-filters .search-advanced-filters {
background-color: var(--d-content-background);
}
.user-main .about .details {
padding: 1em 1em 0;
border-bottom: 0;
border-radius: var(--d-border-radius);
background-color: var(--primary-50);
}
.alert.alert-info {
background: var(--tertiary-very-low);
}
.discourse-reactions-list .reactions {
gap: 0.15em;
}
.group-details-container {
border-radius: var(--d-border-radius);
}
.period-chooser-header {
border-radius: 0;
}
// compatibility with the top contributors sidebar theme component
// https://meta.discourse.org/t/top-contributors-sidebar/215110
.list-container
#list-area
> .contents
> .topic-list:has(.discourse-top-contributors) {
grid-template-areas: "head head" "body sidebar";
grid-template-rows: auto 1fr;
@include viewport.until(lg) {
grid-template-areas: "head head" "body body";
}
tbody {
display: flex;
}
.discourse-top-contributors {
width: auto;
box-sizing: border-box;
@include viewport.until(lg) {
display: none;
}
.top-contributors-heading {
font-size: var(--font-up-2);
padding-bottom: 0.5em;
}
}
}
+150 -54
View File
@@ -1,132 +1,173 @@
//temp sepeate file to avoid merge hell… to be distributed later
@include breakpoint(medium) {
@use "lib/viewport";
// temp separate file to avoid merge hell… to be distributed later
@include viewport.until(lg) {
html,
.d-header {
background-color: var(--secondary);
background-color: var(--d-content-background);
}
}
#main-outlet-wrapper {
.navigation-topics & {
@include breakpoint(mobile-extra-large) {
*[class*="navigation-"] & {
@include viewport.until(sm) {
padding: 0;
}
}
}
#main-outlet {
@include breakpoint(mobile-extra-large) {
@include viewport.until(sm) {
padding-top: var(--spacing-block-sm);
}
.list-controls {
@include breakpoint(mobile-extra-large) {
@include viewport.until(sm) {
padding-inline: var(
--spacing-inline-m
) !important; //override will be fixed when the whole chat page shenanigans is resolved
) !important; // override will be fixed when the whole chat page shenanigans is resolved
padding-block: var(--spacing-block-s);
border-bottom: 1px solid var(--primary-200);
}
.navigation-container {
@include breakpoint(mobile-extra-large) {
@include viewport.until(sm) {
gap: var(--spacing-inline-s);
//dont know why we even hide this crucial navigation on mobile
.category-breadcrumb.hidden,
.category-breadcrumb {
display: flex !important;
gap: var(--spacing-inline-sm);
column-gap: var(--spacing-inline-m);
row-gap: var(--spacing-block-xs);
flex-basis: 100%;
li {
margin-right: 0;
margin-left: calc(
(var(--spacing-block-s) - 2px) * -1
); // 2px is width of the outline
}
.select-kit-header-wrapper {
gap: 0.25em;
}
.select-kit-header {
padding-block: var(--spacing-block-s);
padding-inline: 0;
border: 0;
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(
--spacing-inline-xs
); //pure visual correction for horitzontal alignment
); // pure visual correction for horizontal alignment
&:has(#create-topic) {
order: 1;
}
}
}
#navigation-bar,
.navigation-controls,
.category-breadcrumb {
@include breakpoint(mobile-extra-large) {
@include viewport.until(sm) {
margin-bottom: 0;
}
}
.navigation-controls {
gap: var(--spacing-inline-s);
@include viewport.until(sm) {
gap: var(--spacing-inline-s);
}
}
}
}
.list-container {
@include breakpoint(mobile-extra-large) {
@include viewport.until(sm) {
padding-inline: 0 !important;
}
.topic-list-body {
@include breakpoint(mobile-extra-large) {
@include viewport.until(sm) {
border-top: 0;
padding-top: 0;
}
}
.topic-list-item {
@include breakpoint(mobile-extra-large) {
box-shadow: none;
border-radius: 0;
//to be moved to topic card segment for general use
// .navigation-category & {
// .badge-category__wrapper {
// display: none;
// }
// }
}
}
}
#topic-title {
@include breakpoint(mobile-extra-large) {
padding-inline: var(--spacing-inline-m) !important;
@include viewport.until(sm) {
padding-inline: var(--spacing-inline-s) !important;
.title-wrapper {
gap: var(--spacing-block-s);
}
.topic-category {
order: -1;
}
//make mixin of this
// .badge-category__wrapper {
// border-radius: var(--d-border-radius);
// padding: var(--spacing-inline-xs) var(--spacing-inline-s);
// background-color: light-dark(
// oklch(from var(--category-badge-color) 97% calc(c * 0.3) h),
// oklch(from var(--category-badge-color) 45% calc(c * 0.5) h)
// );
// }
// .badge-category__name {
// color: light-dark(
// oklch(from var(--category-badge-color) 20% calc(c * 1) h),
// oklch(from var(--category-badge-color) 100% calc(c * 0.9) h)
// );
// }
// make mixin of this
.badge-category__wrapper {
font-size: var(--font-down-2-rem);
border-radius: var(--d-border-radius);
padding: var(--spacing-inline-xs) var(--spacing-inline-s);
background-color: light-dark(
oklch(from var(--category-badge-color) 97% calc(c * 0.3) h),
oklch(from var(--category-badge-color) 45% calc(c * 0.5) h)
);
border: 1px solid
light-dark(
oklch(from var(--category-badge-color) 97% calc(c * 0.3) h),
oklch(from var(--category-badge-color) 45% calc(c * 0.5) h)
);
}
.badge-category__name {
color: light-dark(
oklch(from var(--category-badge-color) 20% calc(c * 1) h),
oklch(from var(--category-badge-color) 100% calc(c * 0.9) h)
);
}
.discourse-tags {
gap: var(--spacing-inline-xs);
&__tag-separator {
display: none;
}
}
.discourse-tag {
font-size: var(--font-down-2-rem);
padding: var(--spacing-inline-xs) var(--spacing-inline-s);
gap: var(--spacing-inline-xs);
border-radius: var(--d-border-radius-large);
border: 1px solid var(--primary-low-mid);
background: var(--secondary);
}
}
}
.container.posts {
@include breakpoint(mobile-extra-large) {
padding-inline: var(--spacing-inline-m) !important;
@include viewport.until(sm) {
padding-inline: var(--spacing-inline-xs) !important;
.main-avatar .avatar {
width: 40px;
height: 40px;
border-radius: var(--d-border-radius);
}
.topic-body {
@@ -135,13 +176,68 @@
font-size: var(--font-0-rem);
}
}
.contents {
padding-top: var(--spacing-block-m);
p {
line-height: 1.65;
}
}
.small-action {
&-desc {
padding: var(--spacing-block-xs) 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(--spacing-inline-xs) !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(--spacing-block-xs);
.btn-primary.progress-back {
border-radius: 0;
background: var(--secondary);
border: 1px solid var(--tertiary-low);
color: var(--accent-color);
padding: var(--spacing-inline-s) var(--spacing-inline-m);
.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);
}
+32 -15
View File
@@ -2,27 +2,41 @@
position: sticky;
top: var(--header-offset);
background: var(--d-content-background);
z-index: 100;
z-index: z("base");
padding: 1.5rem 0 1rem 0;
max-width: unset;
.navigation-container {
gap: 1rem;
.category-breadcrumb {
order: 1;
}
}
.combo-box .combo-box-header {
// needs more specificy than just in the button file
// needs more specificity than just in the button file
background-color: var(--secondary);
border-radius: var(--d-border-radius-large);
border-radius: var(--d-border-radius);
border: 1px solid var(--primary-300);
// font-size: var(--font-up-1-rem);
&:hover {
border: 1px solid var(--accent-color);
box-shadow: 0px 0px 8px 2px var(--button-box-shadow);
}
&:focus-visible {
.discourse-no-touch & {
background: var(--secondary);
color: var(--accent-color);
box-shadow: 0 0 0 3px var(--button-box-shadow);
.d-icon {
color: var(--accent-color);
}
}
}
}
.select-kit.combo-box.category-drop.has-selection
.category-drop-header:hover {
border-color: transparent;
@@ -36,15 +50,18 @@
.nav-pills > li > a:hover,
.nav-pills > li button:hover {
background: transparent;
color: var(--accent-color);
&::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: var(--d-nav-underline-height);
background: var(--accent-color);
.discourse-no-touch & {
background: transparent;
color: var(--d-nav-color--hover);
&::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: var(--d-nav-underline-height);
background: var(--d-nav-color--hover);
}
}
}
-83
View File
@@ -1,83 +0,0 @@
.custom-search-banner-wrap {
display: grid;
grid-template-rows: 0.33fr 0.33fr 0.33fr;
grid-template-columns: 1fr 1fr;
grid-column-gap: 1em;
grid-row-gap: 0.5em;
border-bottom: 1px solid var(--primary-300);
padding: 1.5em 0 2.5em;
margin-bottom: 0;
@media screen and (max-width: 900px) {
padding-bottom: 1em;
}
h1 {
grid-column: 1/2;
grid-row: 1/-1;
padding: 0 1em;
text-align: left;
align-self: center;
margin: 0;
font-weight: 400;
color: var(--search-banner-text-color);
@media screen and (max-width: 1028px) {
font-size: var(--font-up-4);
grid-column: 1/-1;
grid-row: 1;
text-align: center;
margin-bottom: 0.5em;
}
@media screen and (max-width: 768px) {
text-align: left;
grid-column: 1/2;
grid-row: 1/-1;
font-size: var(--font-up-3);
}
@media screen and (max-width: 600px) {
grid-column: 1/-1;
grid-row: 1;
text-align: center;
margin-bottom: 0.5em;
}
}
.search-menu {
grid-column: 2/3;
grid-row: 1/-1;
width: 100%;
align-self: center;
@media screen and (max-width: 1028px) {
grid-row: 2/-1;
grid-column: 1/-1;
}
@media screen and (max-width: 768px) {
grid-column: 2/-1;
grid-row: 1/-1;
}
@media screen and (max-width: 600px) {
grid-row: 2/-1;
grid-column: 1/-1;
}
}
p {
display: none;
}
.search-input {
background: var(--d-content-background);
border: 1px solid var(--search-color);
box-shadow: 0 4px 10px rgba(52, 6, 121, 15%);
}
.search-menu .search-input:focus-within,
.search-menu-container .search-input:focus-within {
border: 1px solid var(--search-color);
outline: 2px solid var(--search-color);
}
.search-menu .d-icon,
.search-menu .searching .d-icon {
color: var(--search-color);
}
.panel-body {
z-index: z("dropdown");
}
.results {
background: var(--d-content-background);
}
}
+127
View File
@@ -0,0 +1,127 @@
@use "lib/viewport";
#main-outlet {
@if $home_bg_image != "" {
background-image: url($home_bg_image);
background-size: cover;
background-position: center;
background-attachment: fixed;
}
}
.container.list-container{
position: relative;
}
.container.list-container::before{
position: absolute;
content: "";
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background-color: #fff9;
border-radius: var(--d-border-radius);
backdrop-filter: blur(10px);
box-shadow: #00000077 0 0 19px 0;
}
.topic-list-header{
background-color: unset;
}
.list-controls, .search-container{
border-radius: var(--d-border-radius);
}
.welcome-banner {
padding: 0 !important;
box-shadow: #00000094 0 0 11px 0;
}
#list-area, .topic-list-header, .admin-detail{
background-color: unset !important;
}
.user-content, .details{
border-radius: var(--d-border-radius);
}
.regular.ember-view, .user-main, .reviewable,
.admin-content, .contents.clearfix.body-page,
.search-container, .show-badge, .users-directory, #main-outlet>.edit-category,
#main-outlet>.container.groups-index,
.container.group{
background-color: #ffffffa8 !important;
border-radius: var(--d-border-radius);
backdrop-filter: blur(32px);
box-shadow: #00000077 0 0 19px 0;
padding: 24px;
}
.topic-post.clearfix.regular, .post-list-item.user-stream-item,
.search-header, .admin-plugin-config-page__content,
.user-main .about.collapsed-info .details,
.ember-view.group-box, .admin-container>.container.groups-index{
background: var(--d-chat-input-bg-color);
border-radius: var(--d-border-radius);
box-shadow: #00000024 0 0 7px 2px;
margin: 10px 0;
position: relative;
padding: 16px 12px;
overflow: hidden;
transition: background-color 0.2s ease-in-out;
}
.user-content{
background-color: unset;
}
.powered-by-discourse{
display: none;
}
// 默认光标
@if $default_cursor != "" {
* {
cursor: url($default_cursor) 1 1, auto;
}
}
// 悬停光标
@if $hover_cursor != "" {
a,
button,
[role="button"],
input[type="button"],
input[type="submit"],
.btn,
.clickable {
cursor: url($hover_cursor) 1 1, auto;
}
}
// 链接光标
@if $pointer_cursor != "" {
a[href],
button,
[role="button"],
label,
input[type="button"],
input[type="submit"],
.pointer {
cursor: url($pointer_cursor) 1 1, pointer;
}
}
// 文本光标
@if $text_cursor != "" {
input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
textarea {
cursor: url($text_cursor) 1 1, text;
}
}
+71
View File
@@ -0,0 +1,71 @@
.navigation-controls {
.topic-drafts-menu-trigger,
.fk-d-button-tooltip {
display: none;
}
}
.has-ai-conversations-sidebar {
.sidebar-new-topic-button__wrapper {
display: none;
}
}
.sidebar-new-topic-button {
flex: 1 1 auto;
&__wrapper {
box-sizing: border-box;
display: flex;
.mobile-view & {
margin: 0 0 1rem;
}
&:has(.topic-drafts-menu-trigger) {
.sidebar-new-topic-button {
border-radius: var(--d-button-border-radius) 0 0
var(--d-button-border-radius);
border-right: 1px solid var(--primary-300);
}
}
.fk-d-button-tooltip {
flex: 1 1 auto;
}
.topic-drafts-menu-trigger {
flex: 0 1 auto;
margin: 0;
border-radius: 0 var(--d-button-border-radius)
var(--d-button-border-radius) 0;
}
.fk-d-button-tooltip:has(button[disabled]) {
+ .topic-drafts-menu-trigger {
display: none;
}
.fk-d-tooltip__trigger {
background: var(--accent-color);
border-radius: 0 var(--d-button-border-radius)
var(--d-button-border-radius) 0;
padding-right: 0.65em;
.d-icon {
color: var(--secondary);
}
}
}
}
}
li.sidebar-section-link-wrapper[data-list-item-name="New Topic"] {
display: none;
}
.has-full-page-chat {
.sidebar-new-topic-button__wrapper {
display: none;
}
}
+49 -18
View File
@@ -1,14 +1,24 @@
.sidebar-wrapper {
@include breakpoint(medium) {
@use "lib/viewport";
.sidebar-wrapper,
.sidebar-hamburger-dropdown {
@include viewport.until(lg) {
background: var(--secondary);
.sidebar-footer-wrapper {
background: var(--secondary);
.sidebar-footer-container::before {
display: none;
}
}
}
.has-full-page-chat &,
.has-full-page-chat & .sidebar-footer-wrapper {
background: transparent;
}
.sidebar-container {
border-right: none;
}
@@ -16,31 +26,48 @@
.sidebar-sections {
padding: 0;
}
.sidebar-section-link {
font-size: var(--font-up-1);
// dont want to change fonts here just yet as font-size can be changed as a user pref.
// charlie: sure but I want it to be bigger by default
// letter-spacing: 0.5px;
transition: none;
border-radius: var(--d-border-radius);
}
.dropdown-menu__item .sidebar-section-link {
border-radius: 0px;
border-radius: 0;
}
}
.sidebar-section-wrapper {
padding-block: 0.45em;
.sidebar-section-header {
font-size: var(--font-down-1);
@include viewport.from(xl) {
padding-block: 0.45em;
}
@include viewport.until(sm) {
.hamburger-panel .revamped & {
margin-bottom: var(--spacing-block-m);
}
}
.sidebar-section-header {
font-size: var(--font-down-2);
}
.sidebar-section-content {
margin: 0;
display: flex;
flex-direction: column;
gap: var(--spacing-block-xs);
@include viewport.from(xl) {
gap: var(--spacing-block-xs);
}
}
}
.sidebar-wrapper .sidebar-sections {
--scrollbarThumbBg: var(--d-selected);
padding: 0 1rem;
}
.sidebar-section-link-wrapper .sidebar-section-link:focus,
.sidebar-section-link-wrapper .sidebar-section-link:hover {
.d-icon {
@@ -49,14 +76,18 @@
}
.sidebar-new-topic-button__wrapper {
margin-bottom: 1.5rem;
@media screen and (max-width: 1000px) {
.sidebar-new-topic-button .d-icon {
display: none;
}
margin: 0 var(--spacing-inline-m) var(--spacing-block-l);
.sidebar-new-topic-button .d-icon {
display: none;
}
}
.sidebar-wrapper .sidebar-sections {
padding: 0 1rem;
// put the draft menu above the slide-out hamburger on small desktop screens
@include viewport.until(md) {
html:not(.mobile-view) {
.topic-drafts-menu-content {
z-index: z("modal", "overlay");
}
}
}
+637 -244
View File
@@ -1,161 +1,211 @@
// 390x844 mobile/portrait (Figma iPhone 13 & 14)
// 744x1133 tablet/portrait (Figma iPad mini 8.3)
// 1280x832 desktop small (Figma MacBook Air)
@use "lib/viewport";
:root {
--hot-color: oklch(63.79% 0.1823 34.77);
--d-border-radius-small: calc(var(--d-border-radius) * 0.5);
}
$extra-small: 435px;
$small: 576px;
$medium: 980px;
$extra-large: 1280px;
.topic-list .topic-list-item-separator {
display: none;
}
.topic-list > .topic-list-body > .topic-list-item.last-visit {
border-bottom: 1px solid var(--primary-300);
border-bottom: none;
}
.topic-list,
.category-boxes .subcategories {
.badge-category__wrapper {
border-radius: var(--d-border-radius);
padding: 3px 6px;
background-color: light-dark(
oklch(from var(--category-badge-color) 97% calc(c * 0.3) h),
oklch(from var(--category-badge-color) 45% calc(c * 0.5) h)
);
@include viewport.until(md) {
padding: 2px 6px;
font-size: var(--font-down-2);
}
.badge-category__name {
color: light-dark(
oklch(from var(--category-badge-color) 20% calc(c * 1) h),
oklch(from var(--category-badge-color) 100% calc(c * 0.9) h)
);
}
}
}
// undo all the above for the few instances that arent styled like traditional badges
.category-text-title {
.badge-category__wrapper {
border-radius: 0;
padding: 0;
background-color: transparent;
.badge-category__name {
color: var(--primary);
}
}
}
.topic-list-body {
border: none;
display: flex;
flex-direction: column;
gap: 1em;
@include breakpoint(medium) {
gap: 1.25em;
@include viewport.until(lg) {
gap: 0.5em;
padding: 0 0.5em;
}
}
body.bulk-select-enabled .topic-list-item {
grid-template-areas:
"bulk-select avatar author status status . activity"
". topic-title topic-title topic-title likes-replies likes-replies category";
.bulk-select {
grid-area: bulk-select;
@include viewport.until(sm) {
gap: 0;
padding: 0;
margin: 0;
align-self: center;
justify-self: center;
label {
margin: 0;
}
}
@media screen and (max-width: $medium) {
grid-template-columns: 44px min-content min-content auto min-content min-content min-content;
grid-template-rows: 22px minmax(22px, auto);
grid-template-areas:
"bulk-select avatar author status status . activity"
". topic-title topic-title topic-title . . likes-replies"
". topic-title topic-title topic-title . . category";
}
@media screen and (max-width: $small) {
grid-template-columns: 25px auto repeat(6, 1fr);
grid-template-rows: auto auto auto;
grid-template-areas:
"bulk-select category-status category-status . . . . activity"
"topic-title topic-title topic-title topic-title topic-title topic-title topic-title topic-title"
"avatar author . . . . . likes-replies";
}
}
body.user-messages-page .topic-list-item {
.topic-category-status-data {
display: none;
}
.topic-list-body .topic-list-item {
position: relative;
background: linear-gradient(45deg, var(--active-color), rgb(255 255 255 / 25%));
box-shadow: 4px 4px 6px 0px rgba(10, 18, 35, .38), 0 6px 16px -10px var(--topic-card-shadow);
text-overflow: ellipsis;
padding: var(--space-3);
border: none;
display: grid;
grid-template-columns: min-content min-content min-content auto min-content;
grid-template-areas:
"avatar author status status . . activity"
". topic-title topic-title topic-title likes-replies likes-replies likes-replies";
&.excerpt-expanded {
grid-template-columns: 44px repeat(6, 1fr) auto;
grid-template-rows: 22px auto auto 30px;
grid-template-areas:
"avatar author status status . . . activity"
"avatar topic-title topic-title topic-title topic-title . . ."
". excerpt excerpt excerpt excerpt excerpt . ."
". excerpt excerpt excerpt excerpt excerpt likes-replies likes-replies";
@media screen and (max-width: $extra-large) {
grid-template-areas:
"avatar author status status . . . activity"
"avatar topic-title topic-title topic-title topic-title . . ."
". excerpt excerpt excerpt excerpt excerpt . likes-replies"
". excerpt excerpt excerpt excerpt excerpt . likes-replies";
}
"creator title title title status"
". category activity activity .";
grid-gap: var(--space-3);
border-radius: var(--d-border-radius);
cursor: pointer;
transition:
all 0.2s ease;
&::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
mask-composite: exclude;
pointer-events: none;
}
@media screen and (max-width: $small) {
grid-template-columns: 25px auto repeat(6, 1fr);
grid-template-rows: auto auto;
&.has-replies {
grid-template-areas:
"topic-title topic-title topic-title topic-title topic-title topic-title topic-title activity"
"avatar author . . . . . likes-replies";
.topic-excerpt {
"creator title title title status"
". category likes-replies activity .";
}
&:not(.has-replies) {
.topic-likes-replies-data {
display: none;
}
}
}
.topic-list-item {
-webkit-font-smoothing: antialiased;
text-overflow: ellipsis;
padding: 0.75em 1rem;
border: 1px solid var(--primary-300);
display: grid;
grid-template-columns: 44px min-content min-content auto min-content min-content min-content;
grid-template-rows: 22px minmax(22px, auto);
grid-template-areas:
"avatar author status status . . activity"
". topic-title topic-title topic-title likes-replies likes-replies category";
&.excerpt-expanded {
grid-template-columns: 44px repeat(6, 1fr) auto;
grid-template-rows: 22px auto auto 30px;
@include viewport.until(sm) {
max-width: 100vw;
box-sizing: border-box;
grid-template-areas:
"avatar author status status . . . activity"
"avatar topic-title topic-title topic-title topic-title . . ."
". excerpt excerpt excerpt excerpt excerpt . ."
". excerpt excerpt excerpt excerpt excerpt likes-replies category";
@media screen and (max-width: $extra-large) {
"creator title title title status"
". category activity activity . ";
border: none;
border-bottom: 1px solid var(--primary-200);
box-shadow: none;
border-radius: 0;
padding: var(--space-4) var(--space-3);
&.has-replies {
grid-template-areas:
"avatar author status status . . . activity"
"avatar topic-title topic-title topic-title topic-title . . ."
". excerpt excerpt excerpt excerpt excerpt . likes-replies"
". excerpt excerpt excerpt excerpt excerpt . category";
"creator title title title status"
". category likes-replies activity . ";
}
@media screen and (max-width: $small) {
grid-template-columns: 25px auto repeat(6, 1fr);
grid-template-rows: auto auto auto;
}
.bulk-select-enabled & {
grid-template-columns: min-content min-content min-content auto min-content min-content;
grid-template-areas:
"bulk-select creator title title title status"
"bulk-select category category activity activity .";
&.has-replies {
grid-template-areas:
"category-status category-status category-status . . . . activity"
"topic-title topic-title topic-title topic-title topic-title topic-title topic-title topic-title"
"avatar author . . . . . likes-replies";
.topic-excerpt {
"bulk-select creator title title title status"
"bulk-select category category activity likes-replies likes-replies";
@include viewport.until(sm) {
grid-template-areas:
"bulk-select creator title title title status"
"bulk-select . category likes-replies activity . ";
}
}
@include viewport.until(sm) {
grid-template-columns: min-content min-content min-content min-content auto min-content;
grid-template-areas:
"bulk-select creator title title title status"
"bulk-select . category activity activity . ";
}
}
&:hover {
background: var(--active-color);
box-shadow: 4px 5px 3px 1px rgba(0, 0, 0, .2), 0 8px 20px -10px var(--topic-card-shadow);
border-left: 5px solid #0006;
}
&.selected {
box-shadow:
0 14px 32px -14px rgb(10 18 35 / 48%),
0 0 0 2px oklch(from var(--accent-color) l calc(c * 0.45) h / 0.28),
0 0 0 8px oklch(from var(--accent-color) l calc(c * 0.2) h / 0.14);
}
&.excerpt-expanded {
@include viewport.until(sm) {
.topic-excerpt,
.link-bottom-line {
display: none;
}
}
@include viewport.from(sm) {
grid-template-areas:
"creator title title title status"
". category activity activity . "
". excerpt excerpt excerpt excerpt";
&.has-replies {
grid-template-areas:
"creator title title title status"
". category likes-replies activity ."
". excerpt excerpt excerpt excerpt";
}
.bulk-select-enabled & {
grid-template-areas:
"bulk-select creator title title title status"
"bulk-select category category activity likes-replies likes-replies "
" bulk-select excerpt excerpt excerpt excerpt excerpt";
}
}
}
grid-column-gap: 12px;
grid-row-gap: 8px;
border-radius: var(--d-border-radius);
@media screen and (max-width: $medium) {
grid-template-columns: 44px min-content min-content auto min-content min-content min-content;
grid-template-rows: 22px minmax(22px, auto);
grid-template-areas:
"avatar author status status . . activity"
". topic-title topic-title topic-title . . likes-replies"
". topic-title topic-title topic-title . . category";
}
@media screen and (max-width: $small) {
grid-template-columns: 25px auto repeat(6, 1fr);
grid-template-rows: auto auto auto;
grid-template-areas:
"category-status category-status category-status . . . . activity"
"topic-title topic-title topic-title topic-title topic-title topic-title topic-title topic-title"
"avatar author . . . . . likes-replies";
}
@include breakpoint(medium) {
border: none;
border-bottom: 1px solid var(--primary-200);
.link-top-line {
grid-area: title;
font-weight: 500;
line-height: calc(var(--space-3) * 2); // avatar sizing
@include viewport.until(sm) {
line-height: normal;
}
.title {
padding: 0;
}
}
// display contents
@@ -163,7 +213,8 @@ body.user-messages-page .topic-list-item {
td.posters,
td.posts,
td.views,
td.activity {
td.activity,
td.topic-category-status-data {
display: contents;
}
@@ -171,103 +222,105 @@ body.user-messages-page .topic-list-item {
padding: 0;
}
// avatar & author
.topic-author-avatar-data {
grid-area: avatar;
margin: 0;
}
.topic-author-avatar img.avatar {
width: 44px;
height: 44px;
border-radius: var(--d-border-radius);
@media screen and (max-width: $small) {
width: 25px;
height: 25px;
}
}
td.topic-author-data {
grid-area: author;
display: flex;
gap: 0.5em;
align-items: center;
}
.topic-author-data .topic-author {
color: var(--primary-500);
// display:nones
td.main-link a.topic-status,
.link-bottom-line,
.badge-notification.new-topic::before {
display: none;
}
// status
.topic-status-card {
.topic-category-data {
grid-area: category;
display: flex;
flex-direction: row;
gap: 4px;
align-items: center;
padding: 0 6px;
font-size: var(--font-down-2);
font-weight: 600;
}
.badge-category__wrapper {
border-radius: var(--d-border-radius);
border: 1px solid var(--status-color);
color: var(--status-color);
height: min-content;
grid-area: status;
width: min-content;
@media screen and (max-width: $small) {
height: calc(100% - 2px);
@include viewport.until(sm) {
border-radius: var(--d-border-radius-small);
max-width: 125px;
}
svg {
padding: 0.25em 0.5rem;
background-color: light-dark(
oklch(from var(--category-badge-color) 97% calc(c * 0.3) h),
oklch(from var(--category-badge-color) 45% calc(c * 0.5) h)
);
@include viewport.until(md) {
padding: 0.25em 0.5rem;
font-size: var(--font-down-2);
}
.badge-category {
align-items: center;
}
.badge-category__name {
font-size: var(--font-down-1);
color: var(--status-color);
color: light-dark(
oklch(from var(--category-badge-color) 20% calc(c * 1) h),
oklch(from var(--category-badge-color) 100% calc(c * 0.9) h)
);
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.d-icon {
width: var(--font-down-1);
height: var(--font-down-1);
}
}
.topic-status-card.--bookmark {
display: none;
}
.topic-status-card.--pinned,
.topic-status-card.--unpinned {
--status-color: var(--primary-500);
cursor: pointer;
background-color: transparent;
line-height: unset;
}
.topic-status-card.--hot {
--status-color: var(--hot-color);
// OP avatar
.topic-creator-data {
grid-area: creator;
.avatar {
height: calc(var(--space-3) * 2);
width: calc(var(--space-3) * 2);
border-radius: var(--d-border-radius);
@include viewport.until(sm) {
border-radius: var(--d-border-radius-small);
}
}
}
// title
td.main-link .link-top-line {
font-size: var(--font-0);
grid-area: topic-title;
font-weight: 500;
.dot-separator {
width: 0.25em;
height: 0.25em;
background-color: var(--primary-500);
border-radius: 100%;
margin-inline: 0.25em;
}
.link-top-line .event-date {
font-size: var(--font-down-3);
// topic activity, icon, text
.topic-activity-data {
@include ellipsis;
grid-area: activity;
}
td.main-link a.topic-status {
display: none;
.topic-activity {
display: flex;
font-size: var(--font-down-1);
height: 100%;
align-items: center;
gap: 0.25em;
}
td.main-link .link-top-line a.raw-topic-link {
padding: 0;
.topic-activity__type {
border-radius: 0.25rem;
display: flex;
align-items: center;
justify-content: center;
}
.topic-post-badges .badge-notification.unread-posts {
background-color: var(--tertiary);
color: var(--tertiary);
overflow: hidden;
height: 8px;
width: 8px;
padding: 0;
top: -2px;
min-width: unset;
}
// excerpt
.topic-excerpt {
grid-area: excerpt;
margin: 0;
font-size: var(--font-down-2);
.topic-activity__username {
@include ellipsis;
margin-left: 0.25em;
}
// timestamp
@@ -279,46 +332,118 @@ body.user-messages-page .topic-list-item {
padding: 0;
}
// metadata
// metadata - category
td.main-link .link-bottom-line {
// status
.topic-status-data {
display: none;
}
td.topic-category-status-data {
display: contents;
@media screen and (max-width: $small) {
grid-area: category-status;
display: flex;
gap: 0.5em;
align-items: center;
}
}
td.topic-category-status-data .badge-category__wrapper {
grid-area: category;
&.--has-status-card .topic-status-data {
display: block;
grid-area: status;
}
td.topic-category-status-data .badge-category__wrapper {
overflow: unset;
.topic-status-card {
height: min-content;
margin-left: auto;
display: flex;
flex-direction: row;
gap: 0.25em;
align-items: center;
padding: 0.2em 0.5rem;
font-size: var(--font-down-2);
@include viewport.from(lg) {
font-size: var(--font-down-3);
}
font-weight: 600;
border-radius: var(--d-border-radius);
padding: 6px;
align-self: flex-end;
background-color: light-dark(
oklch(from var(--category-badge-color) 97% calc(c * 0.3) h),
oklch(from var(--category-badge-color) 45% calc(c * 0.5) h)
);
border: 1px solid var(--status-color);
color: var(--status-color);
width: min-content;
@media screen and (max-width: $small) {
padding: 2px 6px;
@include viewport.until(sm) {
border-radius: var(--d-border-radius-small);
padding: 0.35em;
}
.badge-category__name {
color: light-dark(
oklch(from var(--category-badge-color) 20% calc(c * 1) h),
oklch(from var(--category-badge-color) 100% calc(c * 0.9) h)
);
&.--pinned {
--status-color: var(--primary-500);
}
&.--hot {
--status-color: #e45735;
}
@include viewport.from(lg) {
position: absolute;
right: 1rem;
top: 0;
transform: translateY(-45%);
background-color: var(--d-content-background);
}
svg {
color: var(--status-color);
@include viewport.from(lg) {
font-size: var(--font-down-1);
}
}
&__name {
margin: 0;
@include viewport.until(sm) {
display: none;
}
}
}
.link-top-line .event-date {
margin-left: 0.5em;
font-size: var(--font-down-3);
white-space: nowrap;
}
.link-top-line .event-date-container {
top: -0.25rem;
line-height: normal;
}
.topic-list-data {
padding: 0;
}
.topic-post-badges .badge-notification.unread-posts,
.topic-post-badges .badge-notification.new-topic {
background-color: var(--tertiary);
color: var(--tertiary);
overflow: hidden;
height: 8px;
width: 8px;
padding: 0;
top: -2px;
min-width: unset;
}
// metadata - excerpt
.topic-excerpt {
grid-area: excerpt;
margin: 0;
padding: 0;
font-size: var(--font-down-2);
width: 100%;
.excerpt__contents {
color: var(--primary-high);
}
// default category position hidden
.badge-category__wrapper {
display: none;
}
}
td.main-link .discourse-tags {
display: none;
}
@@ -334,34 +459,302 @@ body.user-messages-page .topic-list-item {
grid-area: likes-replies;
display: flex;
flex-direction: row;
gap: 0.5em;
justify-content: flex-end;
gap: var(--space-3);
height: min-content;
align-self: flex-end;
padding-bottom: 4px;
align-self: center;
.topic-likes {
display: none;
}
}
.topic-likes-replies-data .topic-likes,
.topic-likes-replies-data .topic-replies {
display: flex;
flex-direction: row;
gap: 0.5em;
align-items: center;
color: var(--primary-500);
font-size: var(--font-down-1-rem);
svg {
color: var(--primary-600);
}
}
}
.topic-list-header {
display: none;
}
.bulk-select {
grid-area: bulk-select;
padding: 0;
margin: 0;
align-self: center;
justify-self: center;
.topic-list-item {
background: var(--d-content-background);
box-shadow: 0px 0px 26px 1px var(--topic-card-shadow);
&:hover {
border: 1px solid var(--accent-color);
background: var(--d-content-background);
@include viewport.until(sm) {
align-self: flex-start;
}
label {
margin: 0;
}
&th {
display: none;
}
}
// Assigned List
&.assigned-list-item {
.topic-status-data {
display: none;
}
grid-template-areas:
"creator title title title dropdown"
". category activity activity .";
&.has-replies {
grid-template-areas:
"creator title title title dropdown"
"category category likes-replies activity .";
}
.assign-topic-buttons {
display: contents;
.assign-actions-dropdown {
grid-area: dropdown;
justify-content: flex-end;
height: 1em;
.select-kit-header {
padding-top: 0;
margin-left: auto;
align-items: center;
background: transparent;
}
.select-kit-header-wrapper {
height: 1em;
width: 1em;
}
}
}
}
// Bookmarks
&.bookmark-list-item {
grid-template-areas:
"creator title title title dropdown"
"category category activity . . ";
@include viewport.until(sm) {
grid-template-areas:
"title title title title dropdown"
"category category activity activity . ";
.avatar {
display: none;
}
}
&.excerpt-expanded {
grid-template-areas:
"creator title title title dropdown"
"category category activity . . "
"excerpt excerpt excerpt excerpt excerpt";
@include viewport.until(sm) {
grid-template-areas:
"title title title title dropdown"
"category category activity activity . "
"excerpt excerpt excerpt excerpt excerpt";
}
}
&.has-metadata {
grid-template-areas:
"creator title title title dropdown"
"category category activity metadata . ";
@include viewport.until(sm) {
grid-template-areas:
"metadata metadata metadata metadata dropdown"
"title title title title ."
"category category activity activity . ";
}
&.excerpt-expanded {
grid-template-areas:
"creator title title title dropdown"
"category category activity metadata . "
"excerpt excerpt excerpt excerpt excerpt";
@include viewport.until(sm) {
grid-template-areas:
"metadata metadata metadata metadata dropdown"
"title title title title ."
"category category activity activity . "
"excerpt excerpt excerpt excerpt excerpt";
}
}
}
td.author-avatar {
grid-area: creator;
}
td.main-link .link-bottom-line {
display: contents;
.badge-category__wrapper {
grid-area: category;
display: flex;
align-items: center;
width: min-content;
justify-self: flex-end;
}
}
td.main-link .link-top-line {
display: contents;
.bookmark-metadata {
grid-area: metadata;
margin: 0;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: var(--spacing-inline-s);
white-space: nowrap;
}
.bookmark-metadata-item {
margin: 0;
vertical-align: middle;
}
.bookmark-status-with-link {
grid-area: title;
}
}
.post-excerpt {
grid-area: excerpt;
margin: 0;
}
.topic-list-data:last-of-type {
display: contents;
.bookmark-actions-dropdown {
grid-area: dropdown;
align-self: flex-start;
height: 1em;
.select-kit-header {
padding-top: 0;
margin-left: auto;
align-items: center;
background: transparent;
}
.select-kit-header-wrapper {
height: 1em;
width: 1em;
}
}
}
.post-metadata.topic-list-data.updated-at {
grid-area: activity;
display: flex;
align-items: center;
font-size: var(--font-down-1-rem);
}
td.activity .post-activity {
display: none;
}
}
}
// bulk-select overrule for j/k nav
.topic-list tr.selected td:first-of-type,
.topic-list-item.selected td:first-of-type {
box-shadow: none;
}
// User Messages
body.user-messages-page {
.topic-list-body {
gap: 0;
}
.topic-list .topic-list-data.posters a:not(.latest) {
display: block;
}
.topic-list-item {
border-radius: 0;
box-shadow: none;
border-bottom: 1px solid var(--primary-200);
border-top: none;
border-right: none;
border-left: none;
display: grid;
grid-template-areas: "title activity" "posters .";
grid-template-columns: auto auto;
grid-template-rows: auto auto;
&.has-replies {
grid-template-areas: "title activity" "posters .";
}
&:hover {
.discourse-no-touch & {
background-color: var(--primary-low);
border-color: var(--primary-200);
}
}
td.topic-category-data,
td.topic-likes-replies-data,
td.topic-status-data,
td.topic-creator-data {
display: none;
}
.main-link .link-top-line {
grid-area: title;
}
&.visited .main-link .link-top-line {
font-weight: normal;
}
td.topic-activity-data {
grid-area: activity;
}
td.topic-list-data.posters {
grid-area: posters;
display: flex;
align-items: center;
height: 100%;
a {
margin-right: 4px;
}
.avatar {
width: 20px;
height: 20px;
border-radius: 4px;
background-color: var(--primary-low);
}
}
}
}
.event-date-container {
display: inline-flex;
position: relative;
}
+58 -56
View File
@@ -1,79 +1,73 @@
@use "lib/viewport";
.post-stream {
.contents {
font-size: var(--font-up-1);
line-height: 1.25;
-webkit-font-smoothing: antialiased;
}
}
.container.posts .topic-navigation {
// super fragile because new sticky topic title doesnt have a calculated value (= 53px with this font and size but…)
top: calc(
var(--header-offset, 60px) + 53px + calc(var(--spacing-block-l) * 2)
);
}
.timeline-container .topic-timeline {
min-width: unset; // why we have this?
.timeline-scrollarea {
border-left: 1px solid var(--accent-color);
}
.timeline-scroller {
padding: 0.25em;
border: 1px solid var(--accent-color);
border-radius: 0.75em;
padding-left: 0.5em;
margin-left: calc(-0.5em - 2.5px);
background: var(--secondary);
height: 40px !important; // height is coming from element style have no other choice
}
.timelime-scroller-content {
display: flex;
flex-direction: column;
gap: 0.25em;
}
.timeline-replies,
.timeline-ago {
line-height: 1;
}
.timeline-ago {
// font-size: var(--font-down-1);
}
.timeline-handle {
background-color: var(--accent-color);
width: 3px;
border-radius: 2px;
height: calc(100% - 6px);
.timeline-scroller {
@include viewport.from(lg) {
margin-left: -4.5px;
background: var(--d-content-background);
height: 40px !important; // height is coming from element style have no other choice
}
.timeline-replies,
.timeline-ago {
line-height: 1;
}
}
.timeline-handle {
background-color: var(--accent-color);
@include viewport.from(lg) {
width: 8px;
border-radius: 10px;
height: calc(100% - 6px);
}
}
}
}
#topic-title {
@include breakpoint(extra-large, $rule: min-width) {
z-index: z("composer", "content") - 1;
padding: var(--spacing-block-l) var(--spacing-inline-xl);
position: sticky;
margin-bottom: 0;
top: var(--header-offset);
background: var(--d-content-background);
// should probably get rid of this extra specificity class in core?
.timeline-container.timeline-fullscreen {
@include viewport.until(lg) {
.topic-timeline
.timeline-scrollarea
.timeline-scroller
.timeline-scroller-content {
padding-right: 0.5em;
}
}
z-index: z("composer", "content") - 1;
padding: var(--spacing-block-l) var(--spacing-inline-xl);
position: sticky;
margin-bottom: 0;
top: var(--header-offset);
background: var(--d-content-background);
border-radius: var(--d-border-radius-large);
}
.container.posts,
.more-topics__container,
#topic-footer-buttons {
padding: 0 24px;
}
.container.posts {
grid-template-columns: auto 150px;
@media screen and (max-width: 924px) {
grid-template-columns: auto 8em;
@media screen and (width <= 924px) {
grid-template-columns: auto auto;
}
.post-notice {
padding: var(--spacing-block-sm);
border-radius: var(--d-border-radius);
font-size: var(--font-down-1-rem);
.d-icon {
font-size: var(--font-up-1);
width: 1em;
}
}
}
.timeline-container .topic-timeline .timeline-ago {
@@ -113,3 +107,11 @@
position: relative;
right: -4px;
}
nav.post-controls .actions button {
font-size: var(--font-0);
}
.archetype-private_message {
--pm-border-radius: var(--d-border-radius);
}
+2 -38
View File
@@ -1,46 +1,10 @@
:root {
--accent-color: #393edb;
--background-color: light-dark(#f5f8ff, #1b1c1e);
--search-color: light-dark(
oklch(from var(--accent-color) calc(l * 0.65) calc(c * 0.65) h),
oklch(from var(--accent-color) calc(l * 1.5) calc(c * 2) h)
);
--search-banner-text-color: light-dark(
oklch(from var(--accent-color) calc(l * 0.65) calc(c * 0.65) h),
oklch(from var(--accent-color) calc(l * 1.85) calc(c * 2) h)
);
--topic-card-shadow: light-dark(
oklch(from var(--accent-color) calc(l * 2) calc(c * 0.1) h / 0.5),
oklch(from var(--accent-color) calc(l * 0.2) calc(c * 0.01) h / 0.25)
);
--button-box-shadow: light-dark(
oklch(from var(--accent-color) calc(l * 2) calc(c * 0.125) h),
oklch(from var(--accent-color) calc(l * 0.75) calc(c * 0.5) h)
);
--d-selected: light-dark(
oklch(from var(--accent-color) calc(l * 1.9) calc(c * 2) h / 0.3),
oklch(from var(--accent-color) calc(l * 0.65) calc(c * 0.65) h / 0.75)
);
--d-chat-border: light-dark(
oklch(from var(--accent-color) calc(l * 1.5) calc(c * 0.25) h),
oklch(from var(--accent-color) calc(l * 0.25) calc(c * 0.25) h)
);
--d-max-width: 1000px;
--d-border-radius-large: 20px;
--d-border-radius: 8px;
--d-input-border-radius: 6px;
--accent-text-color: light-dark(#ffffff, #0f1024);
--d-content-background: var(--secondary);
--d-nav-color--active: var(--accent-color);
--d-sidebar-background: var(--background-color);
--d-sidebar-footer-fade: rgba(var(--tertiary-50-rgb), 1);
--d-sidebar-link-color: var(--primary);
--d-sidebar-highlight-color: var(--primary);
--d-sidebar-highlight-background: var(--d-selected);
--d-sidebar-section-link-icon-size: 1em;
--d-input-bg-color: var(--d-content-background);
// --d-sidebar-row-height: 2.8em;
//the idea is: block spacing can grow with font-size, but inline spacing should not to maintain horizontal (text) alignment
// the idea is: block spacing can grow with font-size, but inline spacing should not to maintain horizontal (text) alignment
--spacing-block-xs: 0.25em;
--spacing-block-s: 0.5em;
--spacing-block-sm: 0.75em;
+117
View File
@@ -0,0 +1,117 @@
@use "lib/viewport";
.welcome-banner {
&__wrap {
display: grid;
grid-template-rows: 0.33fr 0.33fr 0.33fr;
grid-template-columns: 1fr 1fr;
grid-column-gap: 1em;
grid-row-gap: 0.5em;
border-bottom: 1px solid var(--primary-300);
padding: 1.5em 0 2.5em;
margin-bottom: 0;
@media screen and (width <= 768px) {
padding: 1em;
}
@include viewport.until(sm) {
display: block;
padding: 0.5em;
margin-top: 0;
}
.search-menu {
grid-column: 2/3;
grid-row: 1/-1;
width: 100%;
align-self: center;
@media screen and (width <= 1028px) {
grid-row: 2/-1;
grid-column: 1/-1;
}
@media screen and (width <= 768px) {
grid-column: 2/-1;
grid-row: 1/-1;
}
@media screen and (width <= 600px) {
grid-row: 2/-1;
grid-column: 1/-1;
}
@include viewport.until(sm) {
display: none;
}
}
p {
display: none;
}
}
.search-menu .search-input,
.search-menu-container .search-input {
background: var(--d-content-background);
border: 1px solid var(--search-color);
box-shadow: 0 4px 10px rgb(52, 6, 121, 15%);
}
.search-menu .search-input:focus-within,
.search-menu-container .search-input:focus-within {
border: 1px solid var(--search-color);
outline: 2px solid var(--search-color);
}
.search-menu .d-icon,
.search-menu .searching .d-icon,
.search-menu .searching .show-advanced-search .d-icon {
color: var(--search-color);
}
.panel-body {
z-index: z("dropdown");
}
.results {
background: var(--d-content-background);
}
&__title {
grid-column: 1/2;
grid-row: 1/-1;
text-align: left;
align-self: center;
margin: 0;
font-weight: 400;
color: var(--search-color);
@media screen and (width <= 1028px) {
font-size: var(--font-up-4);
grid-column: 1/-1;
grid-row: 1;
text-align: center;
margin-bottom: 0.5em;
}
@media screen and (width <= 768px) {
text-align: left;
grid-column: 1/2;
grid-row: 1/-1;
font-size: var(--font-up-3);
}
@media screen and (width <= 600px) {
grid-column: 1/-1;
grid-row: 1;
text-align: center;
margin-bottom: 0.5em;
}
@include viewport.until(sm) {
font-size: var(--font-up-2);
}
}
}
+37
View File
@@ -0,0 +1,37 @@
enable_welcome_banner:
default: true
description: "Overrides the core `enable welcome banner` site setting"
search_experience:
type: enum
default: search_field
choices:
- search_field
- search_icon
description: "Overrides the core `search experience` site setting"
home_bg_image:
type: upload
default: ""
description: "首页背景图"
default_cursor:
type: upload
default: ""
description: "默认光标 SVG 文件"
hover_cursor:
type: upload
default: ""
description: "悬停光标 SVG 文件"
pointer_cursor:
type: upload
default: ""
description: "链接光标 SVG 文件"
text_cursor:
type: upload
default: ""
description: "文本光标 SVG 文件"
+54
View File
@@ -0,0 +1,54 @@
# frozen_string_literal: true
describe "Composer peek", type: :system do
fab!(:current_user) { Fabricate(:user, refresh_auto_groups: true) }
fab!(:topic) { Fabricate(:topic_with_op) }
let(:topic_page) { PageObjects::Pages::Topic.new }
let(:composer) { PageObjects::Components::Composer.new }
before do
upload_theme
sign_in(current_user)
end
it "does not show composer peek for small windows" do
topic_page.visit_topic(topic)
topic_page.click_footer_reply
expect(composer).to be_opened
resize_window(width: 600) { expect(page).to have_no_css(".peek-mode-toggle") }
end
it "turns on composer peek and remembers this preference on page load" do
topic_page.visit_topic(topic)
topic_page.click_footer_reply
expect(composer).to be_opened
resize_window(width: 1380) do
find(".peek-mode-toggle").click
expect(page).to have_css("body.peek-mode-active")
topic_page.visit_topic(topic)
topic_page.click_footer_reply
expect(composer).to be_opened
expect(page).to have_css("body.peek-mode-active")
find(".peek-mode-toggle").click
expect(page).to have_no_css("body.peek-mode-active")
end
end
it "hides the composer preview when toggling" do
topic_page.visit_topic(topic)
topic_page.click_footer_reply
expect(composer).to be_opened
expect(composer).to have_composer_preview
resize_window(width: 1380) do
find(".peek-mode-toggle").click
expect(page).to have_css("body.peek-mode-active")
expect(composer).to have_no_composer_preview
end
end
end
+22
View File
@@ -0,0 +1,22 @@
# frozen_string_literal: true
RSpec.describe "Core features", type: :system do
fab!(:current_user) { Fabricate(:user, refresh_auto_groups: true) }
let(:composer) { PageObjects::Components::Composer.new }
before { upload_theme_or_component }
it_behaves_like "having working core features",
skip_examples: %i[search:quick_search topics:create]
it "creates a new topic" do
sign_in(current_user)
visit("/new-topic")
composer.fill_title("This is a new topic")
composer.fill_content("This is a long enough sentence.")
expect(page).to have_css(".d-editor-preview p", visible: true)
within(".save-or-cancel") { click_button("Create Topic") }
expect(page).to have_content("This is a new topic")
expect(page).to have_content("This is a long enough sentence.")
end
end
+74
View File
@@ -0,0 +1,74 @@
# frozen_string_literal: true
require_relative "./page_objects/components/user_color_palette_selector"
describe "Horizon theme | High level", type: :system do
let!(:theme) do
horizon_theme = upload_theme
ColorScheme
.where(theme_id: horizon_theme.id)
.where.not("name LIKE '%Dark%'")
.update_all(user_selectable: true)
horizon_theme
end
fab!(:current_user) { Fabricate(:user) }
fab!(:tag_1) { Fabricate(:tag, name: "wow-cool") }
fab!(:tag_2) { Fabricate(:tag, name: "another-tag") }
fab!(:category)
fab!(:topic_1) { Fabricate(:topic_with_op, category: category, tags: [tag_1, tag_2]) }
let(:topic_list) { PageObjects::Components::TopicList.new }
let(:topic_page) { PageObjects::Pages::Topic.new }
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
let(:palette_selector) { PageObjects::Components::UserColorPaletteSelector.new }
def run_all_high_level_tests
expect(page).to have_css(".experimental-screen")
expect(sidebar).to have_categories_section
expect(sidebar).to have_section_link(category.name)
expect(topic_list).to have_topic(topic_1)
# Ensure the topic list columns are in the correct order via 'topic-list-columns' valueTransformer
#
# NOTE(martin): Maybe there is a better way to do this in a qunit test instead.
topic_item = find(topic_list.topic_list_item_class(topic_1))
expect(topic_item.all("td").map { |el| el["class"] }).to eq(
[
"main-link topic-list-data",
"topic-category-data",
"topic-creator-data",
"topic-activity-data",
],
)
# Can see a topic in the list and navigate to it successfully.
topic_list.visit_topic(topic_1)
expect(topic_page).to have_topic_title(topic_1.title)
# Can change site colors from the sidebar palette, which are remembered
# across page reloads.
marigold_palette = theme.color_schemes.find_by(name: "Marigold")
palette_selector.open_palette_menu
palette_selector.click_palette_menu_item(marigold_palette.name)
expect(palette_selector).to have_no_palette_menu
page.refresh
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_tertiary_color(marigold_palette)
end
it "works for anon" do
visit "/"
run_all_high_level_tests
end
context "for signed in users" do
before { sign_in(current_user) }
it "works" do
visit "/"
run_all_high_level_tests
end
end
end
@@ -0,0 +1,55 @@
# frozen_string_literal: true
module PageObjects
module Components
class UserColorPaletteSelector < PageObjects::Components::Base
def sidebar_footer_button_css
".sidebar-footer-actions .user-color-palette-selector"
end
def palette_menu
PageObjects::Components::DMenu.new(find(sidebar_footer_button_css))
end
def open_palette_menu
palette_menu.expand
end
def has_no_palette_menu?
has_no_css?(".user-color-palette-selector-content")
end
def click_palette_menu_item(palette_name)
find(
".user-color-palette-menu__content .user-color-palette-menu__item[data-color-palette='#{palette_name}']",
).click
end
def has_selected_palette?(palette)
has_css?(
".user-color-palette-selector-trigger[data-selected-color-palette-id=\"#{palette.id}\"]",
)
end
def has_loaded_css?
has_css?(".user-color-palette-selector.user-color-palette-css-loaded")
end
def has_tertiary_color?(palette)
computed_color_hex =
page.evaluate_script(
"getComputedStyle(document.documentElement).getPropertyValue('--tertiary')",
)
computed_color_hex == "#" + palette.colors.find { |color| color.name == "tertiary" }.hex
end
def has_computed_color?(color)
computed_background_color =
page.evaluate_script(
"getComputedStyle(document.querySelector(\"li.sidebar-section-link-wrapper[data-list-item-name='everything'] .active\")).backgroundColor",
)
computed_background_color == color
end
end
end
end
+55
View File
@@ -0,0 +1,55 @@
# frozen_string_literal: true
RSpec.describe "Sidebar New Topic Button", system: true do
before { upload_theme }
fab!(:group)
fab!(:user) { Fabricate(:user, trust_level: 3, groups: [group]) }
fab!(:category)
fab!(:private_category) do
c = Fabricate(:category_with_definition)
c.set_permissions(group => :readonly)
c.save
c
end
context "for signed in users" do
before { sign_in(user) }
it "renders the new topic button in the sidebar" do
visit("/latest")
expect(page).to have_css(".sidebar-new-topic-button__wrapper")
expect(page).to have_css(".sidebar-new-topic-button:not(.disabled)")
end
it "opens the composer when clicked" do
visit("/")
find(".sidebar-new-topic-button").click
expect(page).to have_css("#reply-title")
end
it "shows draft menu when drafts exist" do
Draft.create!(user: user, draft_key: "topic_1", data: {})
visit("/")
expect(page).to have_css(".sidebar-new-topic-button__wrapper .topic-drafts-menu-trigger")
end
it "disables button when visiting read-only category" do
visit("/c/#{private_category.slug}/#{private_category.id}")
expect(page).to have_css(".sidebar-new-topic-button[disabled]")
visit("/c/#{category.slug}/#{category.id}")
expect(page).not_to have_css(".sidebar-new-topic-button[disabled]")
end
end
context "for anon" do
it "does not render the sidebar button for anons" do
visit("/latest")
expect(page).not_to have_css(".sidebar-new-topic-button__wrapper")
expect(page).not_to have_css(".sidebar-new-topic-button:not(.disabled)")
end
end
end
@@ -0,0 +1,119 @@
# frozen_string_literal: true
require_relative "./page_objects/components/user_color_palette_selector"
describe "Horizon theme | User color palette selector", type: :system do
let(:set_theme_as_default) { true }
let!(:theme) do
horizon_theme = upload_theme(set_theme_as_default: set_theme_as_default)
horizon_theme.color_schemes.update_all(user_selectable: true)
horizon_theme
end
fab!(:current_user) { Fabricate(:user) }
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
let(:palette_selector) { PageObjects::Components::UserColorPaletteSelector.new }
let(:interface_color_mode) { PageObjects::Components::InterfaceColorMode.new }
let(:interface_color_selector) do
PageObjects::Components::InterfaceColorSelector.new(".sidebar-footer-actions")
end
let(:marigold_palette) { theme.color_schemes.find_by(name: "Marigold") }
let(:marigold_palette_dark) { theme.color_schemes.find_by(name: "Marigold Dark") }
before { SiteSetting.interface_color_selector = "sidebar_footer" }
it "does not show the sidebar button if there are no user-selectable color palettes" do
ColorScheme.update_all(user_selectable: false)
visit "/"
expect(page).to have_no_css(palette_selector.sidebar_footer_button_css)
end
describe "for logged in user" do
before { sign_in(current_user) }
it "can open the user color palette menu and select a palette, which is preseved on reload" do
visit "/"
palette_selector.open_palette_menu
palette_selector.click_palette_menu_item(marigold_palette.name)
expect(palette_selector).to have_no_palette_menu
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_loaded_css
expect(palette_selector).to have_tertiary_color(marigold_palette)
page.refresh
expect(palette_selector).to have_selected_palette(marigold_palette)
end
it "uses the dark version of the palette if the user selects dark mode" do
visit "/"
palette_selector.open_palette_menu
palette_selector.click_palette_menu_item(marigold_palette.name)
expect(palette_selector).to have_no_palette_menu
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_loaded_css
expect(palette_selector).to have_computed_color("oklch(0.92 0.0708528 68.5036)")
interface_color_selector.expand
interface_color_selector.dark_option.click
expect(interface_color_mode).to have_dark_mode_forced
expect(palette_selector).to have_computed_color("oklch(0.481966 0.0354264 68.5036)")
page.refresh
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_computed_color("oklch(0.481966 0.0354264 68.5036)")
end
context "when the theme is not default but is selected by a user" do
let(:set_theme_as_default) { false }
it "can open the user color palette menu and select a palette, which is preseved on reload" do
theme.update!(user_selectable: true)
current_user.user_option.update!(theme_ids: [theme.id])
visit "/"
palette_selector.open_palette_menu
palette_selector.click_palette_menu_item(marigold_palette.name)
expect(palette_selector).to have_no_palette_menu
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_loaded_css
expect(palette_selector).to have_tertiary_color(marigold_palette)
end
end
end
describe "for anon" do
it "can open the user color palette menu and select a palette, which is preseved on reload" do
visit "/"
palette_selector.open_palette_menu
palette_selector.click_palette_menu_item(marigold_palette.name)
expect(palette_selector).to have_no_palette_menu
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_loaded_css
expect(palette_selector).to have_tertiary_color(marigold_palette)
end
it "uses the dark version of the palette if the user selects dark mode, which is preserved on reload" do
visit "/"
palette_selector.open_palette_menu
palette_selector.click_palette_menu_item(marigold_palette.name)
expect(palette_selector).to have_no_palette_menu
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_loaded_css
expect(palette_selector).to have_computed_color("oklch(0.92 0.0708528 68.5036)")
interface_color_selector.expand
interface_color_selector.dark_option.click
expect(interface_color_mode).to have_dark_mode_forced
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_loaded_css
expect(palette_selector).to have_computed_color("oklch(0.481966 0.0354264 68.5036)")
page.refresh
expect(palette_selector).to have_selected_palette(marigold_palette)
expect(palette_selector).to have_computed_color("oklch(0.481966 0.0354264 68.5036)")
end
end
end
+3
View File
@@ -0,0 +1,3 @@
export default {
extends: ["@discourse/lint-configs/stylelint"],
};