signal-desktop/stylesheets/_mixins.scss

1023 lines
20 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: Inter, 'SF Pro', 'SF Pro JP', 'BIZ UDGothic',
'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ Pro W3', , Meiryo,
' Pゴシック', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
/* Farsi (Persian) */
&:lang(fa) {
font-family:
'Vazirmatn',
-apple-system,
system-ui,
BlinkMacSystemFont,
'Segoe UI',
Tahoma,
'Noto Sans Arabic',
Helvetica,
Arial,
sans-serif;
}
/* Urdu */
&:lang(ur) {
font-family: 'Noto Nastaliq Urdu', Gulzar, 'Jameel Noori Nastaleeq',
'Faiz Lahori Nastaleeq', 'Urdu Typesetting', 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 {
font-weight: 600;
font-size: 26px;
line-height: 32px;
letter-spacing: -0.56px;
}
@mixin font-title-2 {
font-weight: 600;
font-size: 20px;
line-height: 26px;
letter-spacing: -0.34px;
}
@mixin font-title-medium {
font-weight: 600;
font-size: 18px;
line-height: 25px;
letter-spacing: -0.25px;
}
@mixin font-body-1 {
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 {
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 {
font-size: 12px;
line-height: 16px;
letter-spacing: 0;
}
@mixin font-subtitle-bold {
@include font-subtitle;
font-weight: 600;
}
@mixin font-caption {
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;
}
}
@mixin any-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',
'chevron-right-bold.svg': 'chevron-left-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) {
-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;
}
$rtl-svg: get-rtl-svg($svg);
@if $rtl-svg {
:dir(rtl) & {
-webkit-mask: url($rtl-svg) no-repeat center;
}
}
}
// 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;
border-style: solid;
border-width: 4px;
cursor: pointer;
height: $bubble-size;
padding: 2px;
width: $bubble-size;
@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: 100vw;
height: 100vh;
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%);
}
@mixin NavTabs__Scroller {
padding-bottom: 8px;
@include scrollbar;
&::-webkit-scrollbar-thumb {
@include light-theme {
background: $color-gray-25;
border-color: $color-gray-04;
}
@include dark-theme {
background: $color-gray-45;
border-color: $color-gray-80;
}
}
}
@mixin draggable-region {
-webkit-app-region: drag;
body.context-menu-open & {
-webkit-app-region: no-drag;
}
}
@mixin tooltip {
& {
@include font-body-2;
@include light-theme {
background-color: $color-gray-04;
color: $color-black;
outline: 1px solid $color-gray-20;
}
@include dark-theme {
background-color: $color-gray-80;
color: $color-gray-15;
outline: 1px solid $color-gray-62;
}
padding-block: 5px;
padding-inline: 12px;
border-radius: 6px;
filter: drop-shadow(0px 4px 3px $color-black-alpha-16);
pointer-events: none;
}
& .module-tooltip-arrow::before {
position: absolute;
content: '';
border-style: solid;
border-width: 7px;
}
&[data-placement='bottom'] .module-tooltip-arrow::before {
@include light-theme {
border-color: transparent transparent $color-gray-20 transparent;
}
@include dark-theme {
border-color: transparent transparent $color-gray-62 transparent;
}
margin-top: -14px;
/* stylelint-disable-next-line liberty/use-logical-spec */
margin-left: -7px;
}
&[data-placement='bottom'] .module-tooltip-arrow::after {
@include light-theme {
border-bottom-color: $color-gray-04;
}
@include dark-theme {
border-bottom-color: $color-gray-80;
}
}
&[data-placement='top'] .module-tooltip-arrow::before {
@include light-theme {
border-color: $color-gray-20 transparent transparent transparent;
}
@include dark-theme {
border-color: $color-gray-62 transparent transparent transparent;
}
margin-top: 0;
/* stylelint-disable-next-line liberty/use-logical-spec */
margin-left: -7px;
}
&[data-placement='top'] .module-tooltip-arrow::after {
@include light-theme {
border-top-color: $color-gray-04;
}
@include dark-theme {
border-top-color: $color-gray-80;
}
}
}
@mixin button-active-call {
$background: $color-accent-green;
@include font-body-2-bold;
@include rounded-corners;
display: flex;
width: auto;
align-items: center;
background-color: $background;
color: $color-white;
outline: none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
&:before {
$icon-size: 16px;
@include color-svg(
'../images/icons/v3/video/video-compact-fill.svg',
$color-white
);
content: '';
display: block;
height: $icon-size;
margin-inline-end: 4px;
min-width: $icon-size;
width: $icon-size;
}
&:not(:disabled) {
&:hover {
@include any-theme {
background-color: darken($background, 16%);
}
}
&:focus {
@include keyboard-mode {
background-color: darken($background, 16%);
}
}
}
}