721 lines
14 KiB
SCSS
721 lines
14 KiB
SCSS
// Copyright 2016 Signal Messenger, LLC
|
||
// SPDX-License-Identifier: AGPL-3.0-only
|
||
|
||
// Fonts
|
||
|
||
@mixin font-family {
|
||
font-family: $inter;
|
||
/* Japanese */
|
||
&:lang(ja) {
|
||
font-family: 'SF Pro JP', 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ Pro W3',
|
||
メイリオ, Meiryo, 'MS 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-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-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
|
||
|
||
@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;
|
||
}
|
||
}
|
||
|
||
// 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: 8px;
|
||
right: 8px;
|
||
width: 18px;
|
||
height: 18px;
|
||
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: 7px 14px;
|
||
}
|
||
|
||
// Modals
|
||
|
||
@mixin modal-reset {
|
||
@include popper-shadow();
|
||
border-radius: 8px;
|
||
margin: 0 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;
|
||
right: 12px;
|
||
top: 12px;
|
||
|
||
height: 24px;
|
||
width: 24px;
|
||
|
||
@include light-theme {
|
||
@include color-svg('../images/icons/v2/x-24.svg', $color-gray-75);
|
||
}
|
||
|
||
@include dark-theme {
|
||
@include color-svg('../images/icons/v2/x-24.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: 8px 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;
|
||
}
|
||
}
|