signal-desktop/stylesheets/_mixins.scss

860 lines
17 KiB
SCSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2016 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
// Fonts
@mixin localized-fonts {
/* Japanese */
&:lang(ja) {
font-family: 'SF Pro JP', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ Pro W3',
, Meiryo, ' Pゴシック', 'Helvetica Neue', Helvetica, Arial,
sans-serif;
}
/* Farsi (Persian) */
&:lang(fa) {
font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI',
Tahoma, 'Noto Sans Arabic', Helvetica, Arial, sans-serif;
}
}
@mixin font-family {
font-family: $inter;
@include localized-fonts;
}
@mixin time-fonts {
font-family: Hatsuishi, $inter;
@include localized-fonts;
}
@mixin font-title-1 {
@include font-family;
font-weight: 600;
font-size: 26px;
line-height: 32px;
letter-spacing: -0.56px;
}
@mixin font-title-2 {
@include font-family;
font-weight: 600;
font-size: 20px;
line-height: 26px;
letter-spacing: -0.34px;
}
@mixin font-body-1 {
@include font-family;
font-size: 14px;
line-height: 20px;
letter-spacing: -0.08px;
}
@mixin font-body-1-bold {
@include font-body-1;
font-weight: 600;
}
@mixin font-body-1-italic {
@include font-body-1;
font-style: italic;
}
@mixin font-body-1-bold-italic {
@include font-body-1;
font-weight: 600;
font-style: italic;
}
@mixin font-body-2 {
@include font-family;
font-size: 13px;
line-height: 18px;
letter-spacing: -0.03px;
}
@mixin font-body-2-bold {
@include font-body-2;
font-weight: 600;
}
@mixin font-body-2-medium {
@include font-body-2;
font-weight: 500;
}
@mixin font-body-2-italic {
@include font-body-2;
font-style: italic;
}
@mixin font-body-2-bold-italic {
@include font-body-2;
font-weight: 600;
font-style: italic;
}
@mixin font-subtitle {
@include font-family;
font-size: 12px;
line-height: 16px;
letter-spacing: 0;
}
@mixin font-subtitle-bold {
@include font-subtitle;
font-weight: 600;
}
@mixin font-caption {
@include font-family;
font-size: 11px;
line-height: 14px;
letter-spacing: 0.06px;
}
@mixin font-caption-bold {
@include font-caption;
font-weight: 600;
}
@mixin font-caption-bold-italic {
@include font-caption;
font-weight: 600;
font-style: italic;
}
// Themes
@mixin light-theme() {
@content;
}
@mixin explicit-light-theme() {
.light-theme & {
@content;
}
}
@mixin dark-theme() {
.dark-theme & {
@content;
}
}
// Utilities
@mixin rounded-corners() {
// This ensures the borders are completely rounded. (A value like 100% would make it an ellipse.)
border-radius: 9999px;
}
@mixin smooth-scroll() {
scroll-behavior: smooth;
@media (prefers-reduced-motion) {
scroll-behavior: auto;
}
}
// NOTE: As of this writing, this mixin only works in the main window, because this class
// is only applied there.
@mixin only-when-page-is-visible {
.page-is-visible & {
@content;
}
}
// Search results loading
@mixin search-results-loading-pulsating-background {
animation: search-results-loading-pulsating-background-animation 2s infinite;
@media (prefers-reduced-motion) {
animation: none;
}
@include light-theme {
background: $color-gray-05;
}
@include dark-theme {
background: $color-gray-65;
}
}
@keyframes search-results-loading-pulsating-background-animation {
0% {
opacity: 1;
}
50% {
opacity: 0.55;
}
100% {
opacity: 1;
}
}
@mixin search-results-loading-box($width) {
width: $width;
height: 12px;
border-radius: 4px;
@include search-results-loading-pulsating-background;
}
// Icons
@function str-replace($string, $search, $replace: '') {
$index: str-index($string, $search);
@if $index {
@return (
str-slice($string, 1, $index - 1) + $replace +
str-replace(
str-slice($string, $index + str-length($search)),
$search,
$replace
)
);
}
@return $string;
}
$rtl-icon-map: (
'chevron-left-16.svg': 'chevron-right-16.svg',
'chevron-right-16.svg': 'chevron-left-16.svg',
'chevron-left-20.svg': 'chevron-right-20.svg',
'chevron-right-20.svg': 'chevron-left-20.svg',
'chevron-left-24.svg': 'chevron-right-24.svg',
'chevron-right-24.svg': 'chevron-left-24.svg',
'arrow-left-32.svg': 'arrow-right-32.svg',
'arrow-right-32.svg': 'arrow-left-32.svg',
// v3 icons
'chevron-left.svg': 'chevron-right.svg',
'chevron-right.svg': 'chevron-left.svg',
'chevron-shallow-left.svg': 'chevron-shallow-right.svg',
'chevron-shallow-right.svg': 'chevron-shallow-left.svg',
'chevron-left-compact-bold.svg': 'chevron-right-compact-bold.svg',
'chevron-right-compact-bold.svg': 'chevron-left-compact-bold.svg',
'arrow-left.svg': 'arrow-right.svg',
'arrow-right.svg': 'arrow-left.svg',
// Ignored cases:
'phone-right-outline-24.svg': '',
'phone-right-solid-24.svg': '',
);
@function get-rtl-svg($svg) {
@each $ltr, $rtl in $rtl-icon-map {
@if str-index($svg, $ltr) {
@if $rtl == '' {
@return $ltr;
}
@return str-replace($svg, $ltr, $rtl);
}
}
@if str-index($svg, 'left') or str-index($svg, 'right') {
@error "Missing RTL icon for #{$svg}";
}
@return false;
}
@mixin color-svg($svg, $color, $stretch: true, $mask-origin: null) {
$rtl-svg: get-rtl-svg($svg);
@if $rtl-svg {
:dir(ltr) & {
-webkit-mask: url($svg) no-repeat center;
@if $stretch {
-webkit-mask-size: 100%;
}
}
:dir(rtl) & {
-webkit-mask: url($rtl-svg) no-repeat center;
@if $stretch {
-webkit-mask-size: 100%;
}
}
} @else {
-webkit-mask: url($svg) no-repeat center;
}
@if $stretch {
-webkit-mask-size: 100%;
}
@if $mask-origin {
-webkit-mask-origin: $mask-origin;
}
background-color: $color;
@media (forced-colors: active) {
background-color: WindowText;
}
}
// Keyboard
@mixin keyboard-mode() {
.keyboard-mode & {
@content;
}
}
@mixin mouse-mode() {
.mouse-mode & {
@content;
}
}
@mixin dark-keyboard-mode() {
.dark-theme.keyboard-mode & {
@content;
}
}
@mixin dark-mouse-mode() {
.dark-theme.mouse-mode & {
@content;
}
}
// Other
@mixin popper-shadow() {
box-shadow: 0px 8px 20px rgba(0, 0, 0, 0.3), 0px 0px 8px rgba(0, 0, 0, 0.05);
@media (forced-colors: active) {
border: 1px solid WindowText;
}
}
@mixin button-reset {
background: none;
color: inherit;
border: none;
padding: 0;
margin: 0;
font: inherit;
cursor: pointer;
outline: inherit;
text-align: inherit;
@media (forced-colors: active) {
border: 1px solid WindowText;
}
}
@mixin staged-attachment-close-button {
@include button-reset;
position: absolute;
top: 4px;
inset-inline-end: 4px;
width: 16px;
height: 16px;
z-index: $z-index-above-base;
}
@mixin calling-text-shadow {
text-shadow: 0 0 4px $color-black-alpha-40;
}
@mixin lonely-local-video-preview {
max-height: calc(100% - 24px);
height: auto;
transform: rotateY(180deg);
width: calc(100% - 24px);
border-radius: 8px;
}
// --- Buttons
// Individual traits
@mixin button-focus-outline {
&:focus {
@include keyboard-mode {
box-shadow: 0px 0px 0px 3px $color-ultramarine;
}
@include dark-keyboard-mode {
box-shadow: 0px 0px 0px 3px $color-ultramarine-light;
}
}
}
@mixin button-blue-text {
@include light-theme {
color: $color-ultramarine;
}
@include dark-theme {
color: $color-ultramarine-light;
}
}
// Complete button styles
@mixin button-primary {
background-color: $color-ultramarine;
// Note: the background colors here need to match the parent component
@include light-theme {
color: $color-white;
border: 1px solid white;
}
@include dark-theme {
color: $color-white-alpha-90;
border: 1px solid $color-gray-95;
}
&:hover {
@include mouse-mode {
background-color: mix($color-black, $color-ultramarine, 15%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $color-ultramarine, 15%);
}
}
&:active {
// We need to include all four here for specificity precedence
@include mouse-mode {
background-color: mix($color-black, $color-ultramarine, 25%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $color-ultramarine, 25%);
}
@include keyboard-mode {
background-color: mix($color-black, $color-ultramarine, 25%);
}
@include dark-keyboard-mode {
background-color: mix($color-black, $color-ultramarine, 25%);
}
}
@include button-focus-outline;
}
@mixin button-secondary {
@include light-theme {
color: $color-gray-90;
background-color: $color-gray-05;
}
@include dark-theme {
color: $color-gray-05;
background-color: $color-gray-65;
}
&:hover {
@include mouse-mode {
background-color: mix($color-black, $color-gray-05, 15%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $color-gray-65, 15%);
}
}
&:active {
// We need to include all four here for specificity precedence
@include mouse-mode {
background-color: mix($color-black, $color-gray-05, 25%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $color-gray-65, 25%);
}
@include keyboard-mode {
background-color: mix($color-black, $color-gray-05, 25%);
}
@include dark-keyboard-mode {
background-color: mix($color-white, $color-gray-65, 25%);
}
}
@include button-focus-outline;
}
@mixin button-secondary-blue-text {
@include button-secondary;
@include button-blue-text;
}
@mixin button-light {
@include light-theme {
color: $color-gray-90;
background-color: $color-gray-02;
}
@include dark-theme {
color: $color-gray-05;
background-color: $color-gray-75;
}
&:hover {
@include mouse-mode {
background-color: mix($color-black, $color-gray-02, 10%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $color-gray-75, 10%);
}
}
&:active {
// We need to include all four here for specificity precedence
@include mouse-mode {
background-color: mix($color-black, $color-gray-02, 20%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $color-gray-75, 20%);
}
@include keyboard-mode {
background-color: mix($color-black, $color-gray-02, 20%);
}
@include dark-keyboard-mode {
background-color: mix($color-white, $color-gray-75, 20%);
}
}
@include button-focus-outline;
}
@mixin button-light-blue-text {
@include button-light;
@include button-blue-text;
}
@mixin button-destructive {
@include light-theme {
color: $color-white;
background-color: $color-accent-red;
}
@include dark-theme {
color: $color-white-alpha-90;
background-color: $color-accent-red;
}
&:hover {
@include mouse-mode {
background-color: mix($color-black, $color-accent-red, 15%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $color-accent-red, 15%);
}
}
&:active {
// We need to include all four here for specificity precedence
@include mouse-mode {
background-color: mix($color-black, $color-accent-red, 25%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $color-accent-red, 25%);
}
@include keyboard-mode {
background-color: mix($color-black, $color-accent-red, 25%);
}
@include dark-keyboard-mode {
background-color: mix($color-white, $color-accent-red, 25%);
}
}
@include button-focus-outline;
}
@mixin button-green {
$background-color: $color-accent-green;
background-color: $background-color;
color: $color-white;
&:active {
// We need to include all four here for specificity precedence
@include mouse-mode {
background-color: mix($color-black, $background-color, 25%);
}
@include dark-mouse-mode {
background-color: mix($color-white, $background-color, 25%);
}
@include keyboard-mode {
background-color: mix($color-black, $background-color, 25%);
}
@include dark-keyboard-mode {
background-color: mix($color-white, $background-color, 25%);
}
}
&[disabled] {
opacity: 0.6;
}
@include button-focus-outline;
}
@mixin button-small {
@include rounded-corners;
padding-block: 7px;
padding-inline: 14px;
}
// Modals
@mixin modal-reset {
@include popper-shadow();
border-radius: 8px;
margin-block: 0;
margin-inline: auto;
max-height: 100%;
max-width: 360px;
padding: 16px;
position: relative;
width: 95%;
display: flex;
flex-direction: column;
@include light-theme() {
background: $color-white;
color: $color-gray-90;
}
@include dark-theme() {
background: $color-gray-95;
color: $color-gray-05;
}
}
@mixin modal-close-button {
@include button-reset;
position: absolute;
inset-inline-end: 12px;
top: 12px;
height: 24px;
width: 24px;
@include light-theme {
@include color-svg('../images/icons/v3/x/x.svg', $color-gray-75);
}
@include dark-theme {
@include color-svg('../images/icons/v3/x/x.svg', $color-gray-15);
}
&:focus {
@include keyboard-mode {
background-color: $color-ultramarine;
}
@include dark-keyboard-mode {
background-color: $color-ultramarine-light;
}
}
}
@mixin color-bubble($bubble-size) {
background-clip: content-box;
border-color: transparent;
border-radius: $bubble-size + 12px;
border-style: solid;
border-width: 4px;
cursor: pointer;
height: $bubble-size + 12px;
padding: 2px;
width: $bubble-size + 12px;
@each $color, $value in $conversation-colors {
&--#{$color} {
background-color: $value;
}
}
@each $color, $value in $conversation-colors-gradient {
&--#{$color} {
background-image: linear-gradient(
map-get($value, 'deg'),
map-get($value, 'start'),
map-get($value, 'end')
);
}
}
}
@mixin avatar-colors {
@each $color, $value in $avatar-colors {
&--#{$color} {
--bg: #{map-get($value, 'bg')};
--fg: #{map-get($value, 'fg')};
background-color: var(--bg);
color: var(--fg);
&--icon {
background-color: var(--fg);
@include dark-theme {
// For specificity
background-color: var(--fg);
}
}
}
}
}
@mixin scrollbar {
&::-webkit-scrollbar-thumb {
border-radius: 4px;
visibility: hidden;
width: 6px;
@include light-theme {
background: $color-black-alpha-40;
}
@include dark-theme {
background: $color-white-alpha-40;
}
}
&::-webkit-scrollbar {
background: transparent;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&:hover::-webkit-scrollbar-thumb {
visibility: visible;
}
}
@mixin normal-input {
@include font-body-1;
padding-block: 8px;
padding-inline: 12px;
border-radius: 6px;
border-width: 2px;
border-style: solid;
width: 100%;
@include light-theme {
background: $color-white;
color: $color-black;
border-color: $color-gray-15;
&:disabled {
background: $color-gray-02;
border-color: $color-gray-05;
color: $color-gray-90;
}
}
@include dark-theme {
background: $color-gray-80;
color: $color-gray-05;
border-color: $color-gray-45;
&:disabled {
background: $color-gray-95;
border-color: $color-gray-60;
color: $color-gray-20;
}
}
&:focus {
outline: none;
@include light-theme {
border-color: $color-ultramarine;
}
@include dark-theme {
border-color: $color-ultramarine-light;
}
}
}
@mixin install-screen {
align-items: center;
display: flex;
width: var(--window-width);
height: var(--window-height);
justify-content: center;
line-height: 30px;
user-select: none;
@include light-theme {
background: $color-gray-02;
color: $color-black;
}
@include dark-theme {
background: $color-gray-95;
color: $color-white;
}
h1 {
@include font-title-2;
}
h2 {
@include font-body-1;
font-weight: normal;
}
}
@mixin timeline-floating-header-node {
@include rounded-corners;
box-shadow: 0 1px 4px $color-black-alpha-20;
@include light-theme {
background: $color-white;
}
@include dark-theme {
background: $color-gray-80;
}
}
@mixin sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
@mixin disabled {
&:is(:disabled, [aria-disabled='true']) {
@content;
}
}
@mixin not-disabled {
&:not(:disabled):not([aria-disabled='true']) {
@content;
}
}
@mixin position-absolute-center {
position: absolute;
top: 50%;
/* stylelint-disable-next-line liberty/use-logical-spec */
left: 50%;
/* stylelint-disable-next-line declaration-property-value-disallowed-list */
transform: translate(-50%, -50%);
}
@mixin position-absolute-center-x {
position: absolute;
/* stylelint-disable-next-line liberty/use-logical-spec */
left: 50%;
/* stylelint-disable-next-line declaration-property-value-disallowed-list */
transform: translateX(-50%);
}
@mixin position-absolute-center-y {
position: absolute;
top: 50%;
transform: translateY(-50%);
}