tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

_TopSites.scss (19360B)


      1 @use 'sass:math';
      2 
      3 /* stylelint-disable max-nesting-depth */
      4 
      5 $top-sites-size: $grid-unit-small;
      6 $rich-icon-size: 96px;
      7 $default-icon-wrapper-size: 40px;
      8 $default-icon-size: 40px;
      9 $default-icon-offset: 6px;
     10 $half-base-gutter: math.div($base-gutter, 2);
     11 $hover-transition-duration: 150ms;
     12 $letter-fallback-color: $white;
     13 $calculated-max-width-medium: $break-point-medium + $card-width;
     14 $calculated-max-width-large: $break-point-large + $card-width;
     15 $calculated-max-width-twice-large: $break-point-large + 2 * $card-width;
     16 $calculated-max-width-widest: $break-point-widest + $card-width;
     17 $calculated-max-width-twice-widest: $break-point-widest + 2 * $card-width;
     18 
     19 .top-sites-list {
     20  &:not(.dnd-active) {
     21    .top-site-outer:is(.active, :focus, :hover) {
     22      @include wallpaper-contrast-fix;
     23 
     24      // Ideally this would just match button --button-background-color-hover.
     25      // However, --button-background-color-hover uses currentColor.
     26      // We cannot change the shortcut's color to match,
     27      // so we just use --button-text-color-hover directly.
     28      background: color-mix(in srgb, var(--button-text-color-hover) 14%, transparent);
     29 
     30      .tile {
     31        box-shadow: 0 2px 8px 0 var(--newtab-section-card-box-shadow-color);
     32      }
     33 
     34      .icon-pin-small {
     35        opacity: 1;
     36      }
     37 
     38      .lightWallpaper &,
     39      .darkWallpaper & {
     40        background: color-mix(in srgb, var(--button-text-color-hover) 14%, transparent);
     41 
     42        @media (prefers-contrast) {
     43          background-color: var(--background-color-box);
     44        }
     45      }
     46    }
     47  }
     48 
     49  list-style: none;
     50  margin: 0 calc(var(--space-large) * -1);
     51  padding: 0;
     52  display: grid;
     53  grid-template-columns: repeat(3, auto);
     54  justify-content: center; // Center shortcuts when fewer than max number of sites per row
     55  row-gap: var(--space-small);
     56 
     57  @media (min-width: $break-point-layout-variant) {
     58    grid-template-columns: repeat(6, auto);
     59  }
     60 
     61  @media (min-width: $break-point-widest) {
     62    grid-template-columns: repeat(8, auto);
     63  }
     64 
     65  a {
     66    text-decoration: none;
     67  }
     68 
     69  // Two columns
     70  @media (max-width: $break-point-medium) {
     71    > :nth-child(2n+1) {
     72      @include context-menu-open-middle;
     73    }
     74 
     75    > :nth-child(2n) {
     76      @include context-menu-open-left;
     77    }
     78  }
     79 
     80  // Four columns
     81  @media (min-width: $break-point-medium) and (max-width: $break-point-large) {
     82    :nth-child(4n) {
     83      @include context-menu-open-left;
     84    }
     85  }
     86 
     87  @media (min-width: $break-point-medium) and (max-width: $calculated-max-width-medium) {
     88    :nth-child(4n+3) {
     89      @include context-menu-open-left;
     90    }
     91  }
     92 
     93  // Six columns
     94  @media (min-width: $break-point-large) and (max-width: $calculated-max-width-twice-large) {
     95    :nth-child(6n) {
     96      @include context-menu-open-left;
     97    }
     98  }
     99 
    100  @media (min-width: $break-point-large) and (max-width: $calculated-max-width-large) {
    101    :nth-child(6n+5) {
    102      @include context-menu-open-left;
    103    }
    104  }
    105 
    106  // Eight columns
    107  @media (min-width: $break-point-widest) and (max-width: $calculated-max-width-twice-widest) {
    108    :nth-child(8n) {
    109      @include context-menu-open-left;
    110    }
    111  }
    112 
    113  @media (min-width: $break-point-widest) and (max-width: $calculated-max-width-widest) {
    114    :nth-child(8n+7) {
    115      @include context-menu-open-left;
    116    }
    117  }
    118 
    119  .hide-for-narrow {
    120    display: none;
    121  }
    122 
    123  @media (min-width: $break-point-medium) {
    124    .hide-for-narrow {
    125      display: none;
    126    }
    127  }
    128 
    129  @media (min-width: $break-point-large) {
    130    .hide-for-narrow {
    131      display: none;
    132    }
    133  }
    134 
    135  @media (min-width: $break-point-widest) {
    136    .hide-for-narrow {
    137      display: inline-block;
    138    }
    139  }
    140 }
    141 
    142 .discovery-stream.ds-layout.ds-layout-topsites {
    143  display: flex;
    144  justify-content: center;
    145 
    146  .top-sites-list {
    147    padding-block-start: 0;
    148  }
    149 }
    150 
    151 // container for drop zone
    152 .top-site-outer {
    153  width: 120px;
    154  // Compact layout spacing migrated from .thumbs-ui-compact
    155  margin-block-end: var(--space-medium);
    156  border-radius: var(--border-radius-large);
    157  display: inline-block;
    158 
    159  .top-site-inner {
    160    position: relative;
    161 
    162    > a {
    163      padding: var(--space-large) var(--space-large) var(--space-xsmall);
    164      color: inherit;
    165      display: block;
    166      outline: none;
    167    }
    168  }
    169 
    170  &:hover, &:focus {
    171    .context-menu-button {
    172      opacity: 1;
    173      transition: opacity 200ms;
    174 
    175      @include wallpaper-contrast-fix;
    176    }
    177 
    178    .tile {
    179      background-color: var(--newtab-background-color-secondary);
    180    }
    181 
    182    .icon-pin-small {
    183      opacity: 1;
    184    }
    185  }
    186 
    187  &:not(:hover, :active, .active) {
    188    @include wallpaper-contrast-fix;
    189  }
    190 
    191  &.active .context-menu-button {
    192    opacity: 1;
    193    background-color: var(--newtab-button-active-background);
    194  }
    195 
    196  .tile {
    197    background: var(--newtab-background-card);
    198    border-radius: var(--border-radius-large);
    199    box-shadow: $shadow-card;
    200    height: calc(var(--size-item-large) * 2);
    201    width: calc(var(--size-item-large) * 2);
    202    margin: 0 auto;
    203    position: relative;
    204    display: flex;
    205    align-items: center;
    206    justify-content: center;
    207    text-transform: uppercase;
    208    font-size: var(--font-size-xxlarge);
    209    color: var(--newtab-contextual-text-secondary-color);
    210    cursor: pointer;
    211 
    212    .icon-wrapper {
    213      border-radius: var(--border-radius-small);
    214      width: $default-icon-wrapper-size;
    215      height: $default-icon-wrapper-size;
    216      display: flex;
    217      align-items: center;
    218      justify-content: center;
    219      overflow: hidden;
    220      position: relative;
    221 
    222      &.letter-fallback {
    223        border-radius: var(--border-radius-circle);
    224 
    225        &::before {
    226          content: attr(data-fallback);
    227          font-size: var(--font-size-xlarge);
    228          transform: none;
    229          position: static;
    230        }
    231      }
    232    }
    233 
    234    .top-site-icon {
    235      background-color: transparent;
    236      border-radius: var(--border-radius-medium);
    237      background-position: center;
    238      background-repeat: no-repeat;
    239      position: absolute;
    240    }
    241  }
    242 
    243  .context-menu-button {
    244    background-image: url('chrome://global/skin/icons/more.svg');
    245    border: 0;
    246    border-radius: var(--border-radius-small);
    247    cursor: pointer;
    248    fill: var(--newtab-button-text);
    249    -moz-context-properties: fill;
    250    height: var(--size-item-medium);
    251    width: var(--size-item-medium);
    252    inset-inline-end: 0;
    253    inset-block-start: var(--space-medium);
    254    position: absolute;
    255    opacity: 0;
    256 
    257    &:hover {
    258      background-color: var(--newtab-button-hover-background);
    259 
    260      &:active {
    261        background-color: var(--newtab-button-active-background);
    262      }
    263    }
    264 
    265    &:focus-visible {
    266      background-color: var(--newtab-button-focus-background);
    267      outline: var(--focus-outline); // Backup for when wallpaper is not set
    268      opacity: 1;
    269 
    270      .lightWallpaper &,
    271      .darkWallpaper & {
    272        &::after {
    273          content: '';
    274          position: absolute;
    275          inset: 0;
    276          border-radius: var(--border-radius-small);
    277          outline: var(--focus-outline);
    278          color-scheme: initial; // Override wallpaper-contrast-fix for focus outline color
    279        }
    280      }
    281    }
    282  }
    283 
    284  .context-menu {
    285    inset-block-start: calc(var(--space-large) + var(--space-xlarge));
    286  }
    287 
    288  .icon-pin-small {
    289    inset-block-start: var(--space-small);
    290    inset-inline-start: var(--space-small);
    291    opacity: 0;
    292    position: absolute;
    293  }
    294 
    295  .top-site-button {
    296    padding: var(--space-large) var(--space-large) var(--space-small);
    297 
    298    &:focus + div .context-menu-button {
    299      opacity: 1;
    300    }
    301 
    302    &:focus .tile {
    303      .lightWallpaper &,
    304      .darkWallpaper & {
    305        outline: var(--focus-outline);
    306        color-scheme: initial;
    307      }
    308    }
    309  }
    310 
    311  .title {
    312    color: var(--newtab-contextual-text-primary-color);
    313    padding-block-start: var(--space-small);
    314    font: caption;
    315    text-align: center;
    316    position: relative;
    317 
    318    .icon {
    319      margin-inline-end: var(--space-xxsmall);
    320      fill: currentColor;
    321    }
    322 
    323    .sponsored-label {
    324      color: var(--newtab-contextual-text-secondary-color);
    325      font-size: var(--font-size-xsmall);
    326    }
    327 
    328    &:not(.sponsored) .sponsored-label {
    329      display: none;
    330    }
    331 
    332    .search-topsite {
    333      margin-inline-end: var(--space-xxsmall);
    334      fill: currentColor;
    335      background-size: var(--icon-size-xsmall);
    336      height: var(--icon-size-xsmall);
    337      width: var(--icon-size-xsmall);
    338      background-position: center;
    339      background-repeat: no-repeat;
    340      background-color: transparent;
    341      position: static;
    342      display: inline-block;
    343      color: var(--icon-color);
    344      box-shadow: none;
    345    }
    346  }
    347 
    348  .rich-icon {
    349    background-size: cover;
    350    height: 100%;
    351    width: 100%;
    352    position: absolute;
    353    inset-inline-start: 0;
    354    inset-block-start: 0;
    355  }
    356 
    357  .default-icon,
    358  .search-topsite {
    359    background-size: $default-icon-size;
    360    height: $default-icon-wrapper-size;
    361    width: $default-icon-wrapper-size;
    362    align-items: center;
    363    display: flex;
    364    justify-content: center;
    365    font-size: var(--font-size-xlarge);
    366 
    367    &[data-fallback]::before {
    368      content: attr(data-fallback);
    369    }
    370  }
    371 
    372  .search-topsite {
    373    background-image: url('chrome://global/skin/icons/search-glass.svg');
    374    background-size: 16px;
    375    background-color: var(--newtab-primary-action-background);
    376    border-radius: var(--border-radius-circle);
    377    -moz-context-properties: fill;
    378    fill: var(--newtab-primary-element-text-color);
    379    box-shadow: $shadow-card;
    380    transition: background-size $hover-transition-duration,
    381      bottom $hover-transition-duration,
    382      inset-inline-end $hover-transition-duration,
    383      height $hover-transition-duration,
    384      width $hover-transition-duration;
    385    height: 32px;
    386    width: 32px;
    387    // Bug 1967304 - $variable
    388    inset-block-end: -$default-icon-offset; // stylelint-disable-line declaration-property-value-disallowed-list
    389    inset-inline-end: -$default-icon-offset; // stylelint-disable-line declaration-property-value-disallowed-list
    390  }
    391 
    392  &.placeholder {
    393    .tile {
    394      box-shadow: $shadow-card;
    395      cursor: default;
    396    }
    397  }
    398 
    399  &.add-button {
    400    .tile {
    401      background-color: var(--button-background-color);
    402 
    403      .icon-wrapper {
    404        background-image: url('chrome://global/skin/icons/plus-20.svg');
    405        background-size: cover;
    406        background-repeat: no-repeat;
    407        height: 20px;
    408        width: 20px;
    409        fill: var(--icon-color);
    410        -moz-context-properties: fill;
    411      }
    412    }
    413 
    414    &:hover {
    415      .tile {
    416        background-color: var(--newtab-background-color-secondary);
    417        color-scheme: initial;
    418      }
    419    }
    420  }
    421 
    422  &.search-shortcut {
    423    .rich-icon {
    424      background-color: $white;
    425    }
    426  }
    427 
    428  .edit-button {
    429    background-image: url('chrome://global/skin/icons/edit.svg');
    430  }
    431 
    432  &.dragged {
    433    .tile {
    434      *,
    435      &::before {
    436        display: none;
    437      }
    438    }
    439 
    440    .title {
    441      visibility: hidden;
    442    }
    443  }
    444 }
    445 
    446 // Preserve shortcuts-refresh variant from compact thumbs UI
    447 .shortcuts-refresh {
    448  .top-site-outer {
    449    margin-block-end: 0;
    450  }
    451 }
    452 
    453 .edit-topsites-wrapper {
    454  .top-site-inner > .top-site-button > .tile {
    455    border: 1px solid var(--border-color);
    456  }
    457 
    458  .modal {
    459    box-shadow: $shadow-secondary;
    460    inset-inline-start: 0;
    461    margin: 0 auto;
    462    max-height: calc(100% - 40px);
    463    position: fixed;
    464    inset-inline-end: 0;
    465    inset-block-start: var(--space-xxlarge);
    466    width: $wrapper-default-width;
    467 
    468    @media (min-width: $break-point-medium) {
    469      width: $wrapper-max-width-medium;
    470    }
    471 
    472    @media (min-width: $break-point-large) {
    473      width: $wrapper-max-width-large;
    474    }
    475  }
    476 }
    477 
    478 .topsite-form {
    479  $form-width: 300px;
    480  $form-spacing: 32px;
    481 
    482  .section-title {
    483    font-size: inherit;
    484    margin: 0 0 var(--space-large);
    485  }
    486 
    487  .form-input-container {
    488    max-width: $form-width + 3 * $form-spacing + $rich-icon-size;
    489    margin: 0 auto;
    490    padding: var(--space-xxlarge);
    491 
    492    .top-site-outer {
    493      pointer-events: none;
    494    }
    495  }
    496 
    497  .search-shortcuts-container {
    498    max-width: 700px;
    499    margin: 0 auto;
    500    padding: var(--space-xxlarge);
    501 
    502    > div {
    503      margin-inline-end: calc(var(--space-xxlarge) * -1);
    504    }
    505 
    506    .top-site-outer {
    507      margin-inline-start: 0;
    508      margin-inline-end: var(--space-xxlarge);
    509    }
    510  }
    511 
    512  .top-site-outer {
    513    padding: 0;
    514    margin: var(--space-xlarge) 0 0;
    515    margin-inline-start: var(--space-xxlarge);
    516  }
    517 
    518  .fields-and-preview {
    519    display: flex;
    520  }
    521 
    522  label {
    523    font-size: $section-title-font-size;
    524  }
    525 
    526  .form-wrapper {
    527    width: 100%;
    528 
    529    .field {
    530      position: relative;
    531 
    532      .icon-clear-input {
    533        position: absolute;
    534        transform: translateY(-50%);
    535        inset-block-start: 50%;
    536        inset-inline-end: var(--space-small);
    537      }
    538    }
    539 
    540    .url {
    541      input:dir(ltr) {
    542        padding-inline-end: var(--space-xxlarge);
    543      }
    544 
    545      input:dir(rtl) {
    546        padding-inline-start: var(--space-xxlarge);
    547 
    548        &:not(:placeholder-shown) {
    549          direction: ltr;
    550          text-align: end;
    551        }
    552      }
    553    }
    554 
    555    .enable-custom-image-input {
    556      display: inline-block;
    557      font-size: var(--font-size-small);
    558      margin-block-start: var(--space-xsmall);
    559      cursor: pointer;
    560    }
    561 
    562    .custom-image-input-container {
    563      margin-block-start: var(--space-xsmall);
    564 
    565      .loading-container {
    566        width: 16px;
    567        height: 16px;
    568        overflow: hidden;
    569        position: absolute;
    570        transform: translateY(-50%);
    571        inset-block-start: 50%;
    572        inset-inline-end: var(--space-small);
    573      }
    574 
    575      // This animation is derived from Firefox's tab loading animation
    576      // See https://searchfox.org/mozilla-central/rev/b29daa46443b30612415c35be0a3c9c13b9dc5f6/browser/themes/shared/tabs.inc.css#208-216
    577      .loading-animation {
    578        @keyframes tab-throbber-animation {
    579          100% { transform: translateX(-960px); }
    580        }
    581 
    582        @keyframes tab-throbber-animation-rtl {
    583          100% { transform: translateX(960px); }
    584        }
    585 
    586        width: 960px;
    587        height: 16px;
    588        -moz-context-properties: fill;
    589        fill: var(--newtab-primary-action-background);
    590        background-image: url('chrome://browser/skin/tabbrowser/loading.svg');
    591        animation: tab-throbber-animation 1.05s steps(60) infinite;
    592 
    593        &:dir(rtl) {
    594          animation-name: tab-throbber-animation-rtl;
    595        }
    596      }
    597    }
    598 
    599    input {
    600      &[type='text'] {
    601        background-color: var(--newtab-background-color-secondary);
    602        border: 1px solid var(--border-color-interactive);
    603        margin: var(--space-small) 0;
    604        padding: 0 var(--space-small);
    605        height: 32px;
    606        width: 100%;
    607        font-size: inherit;
    608 
    609        &[disabled] {
    610          border: 1px solid var(--border-color-interactive-disabled);
    611          box-shadow: none;
    612          opacity: 0.4;
    613        }
    614      }
    615    }
    616 
    617    .invalid {
    618      input {
    619        &[type='text'] {
    620          border: 1px solid var(--outline-color-error);
    621          box-shadow: $input-error-boxshadow;
    622        }
    623      }
    624    }
    625 
    626    .error-tooltip {
    627      animation: fade-up-tt 450ms;
    628      background: var(--newtab-status-error);
    629      border-radius: var(--border-radius-small);
    630      color: $white;
    631      inset-inline-start: var(--space-xxsmall);
    632      padding: var(--space-xsmall) var(--space-medium);
    633      position: absolute;
    634      inset-block-start: var(--space-xxlarge);
    635      z-index: 1;
    636 
    637      // tooltip caret
    638      &::before {
    639        background: var(--newtab-status-error);
    640        inset-block-end: calc(var(--space-small) * -1);
    641        content: '.';
    642        height: 16px;
    643        inset-inline-start: var(--space-medium);
    644        position: absolute;
    645        text-indent: -999px;
    646        inset-block-start: calc(var(--space-small) * -1);
    647        transform: rotate(45deg);
    648        white-space: nowrap;
    649        width: 16px;
    650        z-index: -1;
    651      }
    652    }
    653  }
    654 
    655  .actions {
    656    justify-content: flex-end;
    657 
    658    button {
    659      margin-inline-start: var(--space-small);
    660      margin-inline-end: 0;
    661    }
    662  }
    663 
    664  @media (max-width: $break-point-medium) {
    665    .fields-and-preview {
    666      flex-direction: column;
    667 
    668      .top-site-outer {
    669        margin-inline-start: 0;
    670      }
    671    }
    672  }
    673 
    674  // prevent text selection of keyword label when clicking to select
    675  .title {
    676    user-select: none;
    677  }
    678 
    679  // CSS styled checkbox
    680  [type='checkbox']:not(:checked),
    681  [type='checkbox']:checked {
    682    inset-inline-start: -9999px; // stylelint-disable-line declaration-property-value-disallowed-list
    683    position: absolute;
    684  }
    685 
    686  [type='checkbox']:not(:checked) + label,
    687  [type='checkbox']:checked + label {
    688    cursor: pointer;
    689    display: block;
    690    position: relative;
    691  }
    692 
    693  $checkbox-offset: calc(var(--space-small) * -1);
    694 
    695  [type='checkbox']:not(:checked) + label::before,
    696  [type='checkbox']:checked + label::before {
    697    background: var(--newtab-background-color);
    698    border: 1px solid var(--border-color);
    699    border-radius: var(--border-radius-small);
    700    content: '';
    701    height: 21px;
    702    inset-inline-start: calc(var(--space-small) * -1);
    703    position: absolute;
    704    inset-block-start: calc(var(--space-small) * -1);
    705    width: 21px;
    706    z-index: 1;
    707 
    708    [dir='rtl'] & {
    709      inset-inline-start: auto;
    710      inset-inline-end: calc(var(--space-small) * -1);
    711    }
    712  }
    713 
    714  // checkmark
    715  [type='checkbox']:not(:checked) + label::after,
    716  [type='checkbox']:checked + label::after {
    717    background: url('chrome://global/skin/icons/check.svg') no-repeat center center;
    718    content: '';
    719    height: 21px;
    720    inset-inline-start: calc(var(--space-small) * -1);
    721    position: absolute;
    722    inset-block-start: calc(var(--space-small) * -1);
    723    width: 21px;
    724    -moz-context-properties: fill;
    725    fill: var(--newtab-primary-action-background);
    726    z-index: 2;
    727 
    728    [dir='rtl'] & {
    729      inset-inline-start: auto;
    730      inset-inline-end: calc(var(--space-small) * -1);
    731    }
    732  }
    733 
    734  // when selected, highlight the tile
    735  [type='checkbox']:checked + label {
    736    .tile {
    737      box-shadow: $shadow-focus;
    738    }
    739  }
    740 
    741  // checkmark changes
    742  [type='checkbox']:not(:checked) + label::after {
    743    opacity: 0;
    744  }
    745 
    746  [type='checkbox']:checked + label::after {
    747    opacity: 1;
    748  }
    749 
    750  // accessibility
    751  [type='checkbox']:checked:focus + label::before,
    752  [type='checkbox']:not(:checked):focus + label::before {
    753    border: 1px dotted var(--newtab-primary-action-background);
    754  }
    755 }
    756 
    757 .top-sites-list,
    758 .fields-and-preview {
    759  .top-site-outer {
    760    .top-site-button {
    761      display: flex;
    762      flex-direction: column;
    763      justify-content: center;
    764      align-items: center;
    765    }
    766 
    767    .title {
    768      .title-label {
    769        display: block;
    770        overflow: hidden;
    771        text-overflow: ellipsis;
    772        -webkit-line-clamp: 2;
    773        white-space: wrap;
    774        word-break: break-word;
    775        min-height: 2lh;
    776        width: 100px;
    777        padding: 0 var(--space-xsmall);
    778      }
    779 
    780      &.sponsored .title-label {
    781        -webkit-line-clamp: 1;
    782        min-height: 1lh;
    783      }
    784    }
    785  }
    786 }
    787 
    788 // used for tooltips below form element
    789 @keyframes fade-up-tt {
    790  0% {
    791    opacity: 0;
    792    transform: translateY(15px);
    793  }
    794 
    795  100% {
    796    opacity: 1;
    797    transform: translateY(0);
    798  }
    799 }
    800 
    801 // used for TopSites impression wrapper
    802 .topsite-impression-observer {
    803  position: absolute;
    804  inset-block-start: 0;
    805  width: 100%;
    806  height: 100%;
    807  pointer-events: none;
    808 }