mirror of
https://github.com/discourse/discourse.git
synced 2025-03-01 20:03:10 +08:00

``` WARNING: Sass's behavior for declarations that appear after nested rules will be changing to match the behavior specified by CSS in an upcoming version. To keep the existing behavior, move the declaration above the nested rule. To opt into the new behavior, wrap the declaration in `& {}`. More info: https://sass-lang.com/d/mixed-decls ```
312 lines
7.2 KiB
SCSS
312 lines
7.2 KiB
SCSS
// --------------------------------------------------
|
|
// Mixins used throughout the theme
|
|
// --------------------------------------------------
|
|
|
|
// Media queries
|
|
// --------------------------------------------------
|
|
|
|
@use "sass:color";
|
|
@use "sass:math";
|
|
@use "sass:string";
|
|
|
|
$breakpoints: (
|
|
mobile-small: 320px,
|
|
mobile-medium: 350px,
|
|
mobile-large: 450px,
|
|
mobile-extra-large: 550px,
|
|
tablet: 768px,
|
|
medium: 850px,
|
|
large: 1000px,
|
|
extra-large: 1140px,
|
|
);
|
|
|
|
@mixin breakpoint($bp, $rule: max-width, $type: screen, $sidebar: false) {
|
|
/* stylelint-disable-next-line scss/no-global-function-names */
|
|
$bp-value: map-get($breakpoints, $bp);
|
|
|
|
@if $rule == min-width {
|
|
$bp-value: calc(#{$bp-value} + 1px);
|
|
}
|
|
|
|
@media #{$type} and (#{$rule}: #{$bp-value}) {
|
|
@content;
|
|
}
|
|
|
|
// if you want to consider the sidebar in your breakpoint
|
|
// you can pass in $sidebar: true
|
|
// note that your breakpoint will need to be at the root level
|
|
@if $sidebar {
|
|
// when the sidebar is shown, we want to increase the breakpoints by the width of the sidebar
|
|
/* stylelint-disable-next-line scss/no-global-function-names */
|
|
@media #{$type} and (#{$rule}: calc(#{map-get($breakpoints, $bp)} + #{$d-sidebar-width})) {
|
|
.has-sidebar-page {
|
|
@content;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// CSS3 properties
|
|
// --------------------------------------------------
|
|
|
|
// Clearfix
|
|
|
|
@mixin clearfix() {
|
|
&::before,
|
|
&::after {
|
|
content: "";
|
|
display: table;
|
|
}
|
|
|
|
&::after {
|
|
clear: both;
|
|
}
|
|
}
|
|
|
|
@mixin linear-gradient($start-color, $end-color) {
|
|
background-color: $start-color;
|
|
background-image: linear-gradient(to bottom, $start-color, $end-color);
|
|
}
|
|
|
|
@mixin darken-background($background-color, $amt) {
|
|
$overlay: dark-light-choose(
|
|
rgba(var(--primary-rgb), $amt),
|
|
rgba(var(--secondary-rgb), $amt)
|
|
);
|
|
background-image: linear-gradient(to bottom, $overlay 100%, $overlay 100%);
|
|
}
|
|
|
|
// Visibility
|
|
// --------------------------------------------------
|
|
|
|
// Only shows hover on non-touch devices
|
|
@mixin hover {
|
|
.discourse-no-touch & {
|
|
&:hover,
|
|
&.btn-hover {
|
|
@content;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin ellipsis {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
@mixin line-clamp($lines) {
|
|
display: -webkit-box;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
word-wrap: break-word;
|
|
-webkit-line-clamp: $lines;
|
|
-moz-box-orient: vertical;
|
|
-webkit-box-orient: vertical;
|
|
}
|
|
|
|
//
|
|
// --------------------------------------------------
|
|
|
|
$vpad: 0.5em;
|
|
$hpad: 0.65em;
|
|
|
|
// for consistent sizing across inputs, buttons and dropdowns
|
|
@mixin form-item-sizing {
|
|
border: 1px solid transparent;
|
|
font-size: var(--font-0);
|
|
line-height: normal;
|
|
box-sizing: border-box;
|
|
padding: $vpad $hpad;
|
|
}
|
|
|
|
@mixin sticky {
|
|
position: sticky;
|
|
}
|
|
|
|
// Unselectable (avoids unwanted selections with iPad, touch laptops, etc)
|
|
|
|
@mixin user-select($mode) {
|
|
-webkit-user-select: $mode;
|
|
user-select: $mode;
|
|
}
|
|
|
|
@mixin unselectable {
|
|
cursor: default;
|
|
@include user-select(none);
|
|
}
|
|
|
|
// Stuff we repeat
|
|
@mixin post-aside {
|
|
border-left: 5px solid var(--primary-300);
|
|
background-color: var(--blend-primary-secondary-5);
|
|
}
|
|
|
|
// We still need -webkit for latest iPhone and Safari
|
|
@mixin transform($transforms) {
|
|
transform: $transforms;
|
|
}
|
|
|
|
@mixin appearance-none() {
|
|
// resets default browser styles
|
|
appearance: none;
|
|
}
|
|
|
|
@mixin default-focus() {
|
|
border-color: var(--tertiary);
|
|
outline: 2px solid var(--tertiary);
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
@mixin fa-rotate($degrees, $rotation) {
|
|
transform: rotate($degrees);
|
|
}
|
|
|
|
/// Helper function to easily use an SVG inline in CSS
|
|
/// without encoding it to base64, saving bytes.
|
|
/// It also helps with browser support, especially for IE11.
|
|
///
|
|
/// @author Jakob Eriksen
|
|
/// @link http://codepen.io/jakob-e/pen/doMoML
|
|
/// @param {String} $svg - SVG image to encode
|
|
/// @return {String} - Encoded SVG data uri
|
|
@function svg-uri($svg) {
|
|
$encoded: "";
|
|
$slice: 2000;
|
|
$index: 0;
|
|
$loops: math.ceil(math.div(string.length($svg), $slice));
|
|
|
|
@for $i from 1 through $loops {
|
|
$chunk: string.slice($svg, $index, $index + $slice - 1);
|
|
$chunk: str-replace($chunk, '"', "'");
|
|
$chunk: str-replace($chunk, "<", "%3C");
|
|
$chunk: str-replace($chunk, ">", "%3E");
|
|
$chunk: str-replace($chunk, "&", "%26");
|
|
$chunk: str-replace($chunk, "#", "%23");
|
|
$encoded: #{$encoded}#{$chunk};
|
|
$index: $index + $slice;
|
|
}
|
|
|
|
@return url("data:image/svg+xml;charset=utf8,#{$encoded}");
|
|
}
|
|
|
|
/// Replace `$search` with `$replace` in `$string`
|
|
/// @author Hugo Giraudel
|
|
/// @link http://sassmeister.com/gist/1b4f2da5527830088e4d
|
|
/// @param {String} $string - Initial string
|
|
/// @param {String} $search - Substring to replace
|
|
/// @param {String} $replace ('') - New value
|
|
/// @return {String} - Updated string
|
|
@function str-replace($string, $search, $replace: "") {
|
|
$index: string.index($string, $search);
|
|
|
|
@if $index {
|
|
@return string.slice($string, 1, $index - 1) + $replace +
|
|
str-replace(
|
|
string.slice($string, $index + string.length($search)),
|
|
$search,
|
|
$replace
|
|
);
|
|
}
|
|
|
|
@return $string;
|
|
}
|
|
|
|
// SCSS accepts HEX or RGB colors for rgba($color, 0.5)
|
|
// CSS custom properties only accept RGB
|
|
// Example usage:
|
|
|
|
// --primary-rgb: #{hexToRGB($primary)};
|
|
// ...
|
|
// rgba(var(--primary-low-rgb), 0.5)
|
|
|
|
@function hexToRGB($hex) {
|
|
@return color.red($hex), color.green($hex), color.blue($hex);
|
|
}
|
|
|
|
@function schemeType() {
|
|
@if is-light-color-scheme() {
|
|
@return "light";
|
|
} @else {
|
|
@return "dark";
|
|
}
|
|
}
|
|
|
|
@function absolute-image-url($path) {
|
|
// public_image_path is added by the stylesheet importer
|
|
// it returns a CDN or subfolder path (if applicable).
|
|
// SCSS will compile (and return the relative path) if public_image_path is missing.
|
|
/* stylelint-disable-next-line scss/no-global-function-names */
|
|
@if global-variable-exists(public_image_path) {
|
|
@if string.index("#{$path}", "/plugins") == 1 {
|
|
$plugin_asset_path: str-replace($public_image_path, "/images", "");
|
|
@return url("#{$plugin_asset_path}#{$path}");
|
|
} @else {
|
|
@return url("#{$public_image_path}#{$path}");
|
|
}
|
|
} @else {
|
|
@return url("#{$path}");
|
|
}
|
|
}
|
|
|
|
@mixin mention() {
|
|
display: inline;
|
|
font-size: 0.93em;
|
|
font-weight: normal;
|
|
color: var(--primary);
|
|
padding: 0.14em 0.34em 0.19em;
|
|
background: var(--primary-low);
|
|
border-radius: 0.6em;
|
|
text-decoration: none;
|
|
text-wrap: nowrap;
|
|
|
|
&.--bot {
|
|
background: var(--success-low);
|
|
}
|
|
|
|
&.--wide {
|
|
background: var(--highlight-low-or-medium);
|
|
}
|
|
|
|
&.--current {
|
|
background: var(--tertiary-400);
|
|
}
|
|
}
|
|
|
|
@mixin nav-active() {
|
|
color: var(--d-nav-color--active);
|
|
background: var(--d-nav-bg-color--active);
|
|
|
|
.d-icon {
|
|
color: var(--d-nav-color--active);
|
|
}
|
|
|
|
&::after {
|
|
content: "";
|
|
position: absolute;
|
|
left: 0;
|
|
bottom: 0;
|
|
right: 0;
|
|
height: var(--d-nav-underline-height);
|
|
background: var(--d-nav-color--active);
|
|
}
|
|
}
|
|
|
|
@mixin click-counter-badge {
|
|
content: attr(data-clicks);
|
|
font-weight: normal;
|
|
background-color: var(--primary-low);
|
|
color: var(--primary-medium);
|
|
position: relative;
|
|
top: -1px;
|
|
padding: 0.21em 0.42em;
|
|
min-width: 0.5em;
|
|
line-height: var(--line-height-small);
|
|
font-size: var(--font-down-2);
|
|
text-align: center;
|
|
border-radius: 10px;
|
|
white-space: nowrap;
|
|
display: inline-block;
|
|
margin: 0.15em;
|
|
}
|