snapdrop

A Progressive Web App for local file sharing https://github.com/RobinLinus/snapdrop snapdrop.net
git clone http://git.hanabi.in/repos/snapdrop.git
Log | Files | Refs | README | LICENSE

styles.css (11921B)


      1 /* Constants */
      2 
      3 :root {
      4     --icon-size: 24px;
      5     --primary-color: #4285f4;
      6     --peer-width: 120px;
      7     color-scheme: light dark;
      8 }
      9 
     10 /* Layout */
     11 
     12 html {
     13     height: 100%;
     14 }
     15 
     16 html,
     17 body {
     18     margin: 0;
     19     display: flex;
     20     flex-direction: column;
     21     width: 100%;
     22     overflow-x: hidden;
     23 }
     24 
     25 body {
     26     flex-grow: 1;
     27     align-items: center;
     28     justify-content: center;
     29     overflow-y: hidden;
     30 }
     31 
     32 .row-reverse {
     33     display: flex;
     34     flex-direction: row-reverse;
     35 }
     36 
     37 .row {
     38     display: flex;
     39     flex-direction: row;
     40 }
     41 
     42 .column {
     43     display: flex;
     44     flex-direction: column;
     45 }
     46 
     47 .center {
     48     display: flex;
     49     align-items: center;
     50     justify-content: center;
     51 }
     52 
     53 .grow {
     54     flex-grow: 1;
     55 }
     56 
     57 .full {
     58     position: absolute;
     59     top: 0;
     60     left: 0;
     61     right: 0;
     62     bottom: 0;
     63 }
     64 
     65 header {
     66     position: absolute;
     67     top: 0;
     68     left: 0;
     69     right: 0;
     70     height: 56px;
     71     align-items: center;
     72     padding: 16px;
     73     box-sizing: border-box;
     74 }
     75 
     76 [hidden] {
     77     display: none !important;
     78 }
     79 
     80 
     81 /* Typography */
     82 
     83 body {
     84     font-family: -apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
     85     -webkit-font-smoothing: antialiased;
     86     -moz-osx-font-smoothing: grayscale;
     87 }
     88 
     89 h1 {
     90     font-size: 34px;
     91     font-weight: 400;
     92     letter-spacing: -.01em;
     93     line-height: 40px;
     94     margin: 8px 0 0;
     95 }
     96 
     97 h2 {
     98     font-size: 24px;
     99     font-weight: 400;
    100     letter-spacing: -.012em;
    101     line-height: 32px;
    102 }
    103 
    104 h3 {
    105     font-size: 20px;
    106     font-weight: 500;
    107     margin: 16px 0;
    108 }
    109 
    110 .font-subheading {
    111     font-size: 16px;
    112     font-weight: 400;
    113     line-height: 24px;
    114 }
    115 
    116 .font-body1,
    117 body {
    118     font-size: 14px;
    119     font-weight: 400;
    120     line-height: 20px;
    121 }
    122 
    123 .font-body2 {
    124     font-size: 12px;
    125     line-height: 18px;
    126 }
    127 
    128 a {
    129     text-decoration: none;
    130     color: currentColor;
    131     cursor: pointer;
    132 }
    133 
    134 
    135 
    136 /* Icons */
    137 
    138 .icon {
    139     width: var(--icon-size);
    140     height: var(--icon-size);
    141     fill: currentColor;
    142 }
    143 
    144 
    145 
    146 /* Shadows */
    147 
    148 [shadow="1"] {
    149     box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14),
    150         0 1px 8px 0 rgba(0, 0, 0, 0.12),
    151         0 3px 3px -2px rgba(0, 0, 0, 0.4);
    152 }
    153 
    154 [shadow="2"] {
    155     box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14),
    156         0 1px 10px 0 rgba(0, 0, 0, 0.12),
    157         0 2px 4px -1px rgba(0, 0, 0, 0.4);
    158 }
    159 
    160 
    161 
    162 
    163 /* Animations */
    164 
    165 @keyframes fade-in {
    166     0% {
    167         opacity: 0;
    168     }
    169 }
    170 
    171 /* Main Header */
    172 
    173 body>header a {
    174     margin-left: 8px;
    175 }
    176 
    177 /* Peers List */
    178 
    179 x-peers {
    180     width: 100%;
    181     overflow: hidden;
    182     flex-flow: row wrap;
    183     z-index: 2;
    184 }
    185 
    186 /* Empty Peers List */
    187 
    188 x-no-peers {
    189     padding: 8px;
    190     text-align: center;
    191     /* prevent flickering on load */
    192     animation: fade-in 300ms;
    193     animation-delay: 500ms;
    194     animation-fill-mode: backwards;
    195 }
    196 
    197 x-no-peers h2,
    198 x-no-peers a {
    199     color: var(--primary-color);
    200 }
    201 
    202 x-peers:not(:empty)+x-no-peers {
    203     display: none;
    204 }
    205 
    206 
    207 
    208 /* Peer */
    209 
    210 x-peer {
    211     -webkit-user-select: none;
    212     user-select: none;
    213 }
    214 
    215 x-peer label {
    216     width: var(--peer-width);
    217     padding: 8px;
    218     cursor: pointer;
    219     touch-action: manipulation;
    220     -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    221     position: relative;
    222 }
    223 
    224 x-peer .name {
    225     width: var(--peer-width);
    226     white-space: nowrap;
    227     overflow: hidden;
    228     text-overflow: ellipsis;
    229     text-align: center;
    230 }
    231 
    232 input[type="file"] {
    233     visibility: hidden;
    234     position: absolute;
    235 }
    236 
    237 x-peer x-icon {
    238     --icon-size: 40px;
    239     width: var(--icon-size);
    240     padding: 12px;
    241     border-radius: 50%;
    242     background: var(--primary-color);
    243     color: white;
    244     display: flex;
    245     margin-bottom: 8px;
    246     transition: transform 150ms;
    247     will-change: transform;
    248 }
    249 
    250 x-peer:not([transfer]):hover x-icon,
    251 x-peer:not([transfer]):focus x-icon {
    252     transform: scale(1.05);
    253 }
    254 
    255 x-peer[transfer] x-icon {
    256     box-shadow: none;
    257     opacity: 0.8;
    258     transform: scale(1);
    259 }
    260 
    261 .status,
    262 .device-name {
    263     height: 18px;
    264     opacity: 0.7;
    265 }
    266 
    267 x-peer[transfer] .status:before {
    268     content: 'Transferring...';
    269 }
    270 
    271 x-peer:not([transfer]) .status,
    272 x-peer[transfer] .device-name {
    273     display: none;
    274 }
    275 
    276 x-peer x-icon {
    277     animation: pop 600ms ease-out 1;
    278 }
    279 
    280 @keyframes pop {
    281     0% {
    282         transform: scale(0.7);
    283     }
    284 
    285     40% {
    286         transform: scale(1.2);
    287     }
    288 }
    289 
    290 x-peer[drop] x-icon {
    291     transform: scale(1.1);
    292 }
    293 
    294 
    295 
    296 /* Footer */
    297 
    298 footer {
    299     position: absolute;
    300     bottom: 0;
    301     left: 0;
    302     right: 0;
    303     align-items: center;
    304     padding: 0 0 16px 0;
    305     text-align: center;
    306 }
    307 
    308 footer .logo {
    309     --icon-size: 80px;
    310     margin-bottom: 8px;
    311     color: var(--primary-color);
    312 }
    313 
    314 footer .font-body2 {
    315     color: var(--primary-color);
    316 }
    317 
    318 @media (min-height: 800px) {
    319     footer {
    320         margin-bottom: 16px;
    321     }
    322 }
    323 
    324 
    325 /* Dialog */
    326 
    327 x-dialog x-background {
    328     background: rgba(0, 0, 0, 0.61);
    329     z-index: 10;
    330     transition: opacity 300ms;
    331     will-change: opacity;
    332     padding: 16px;
    333 }
    334 
    335 x-dialog x-paper {
    336     z-index: 3;
    337     background: white;
    338     border-radius: 8px;
    339     padding: 16px 24px;
    340     width: 100%;
    341     max-width: 400px;
    342     box-sizing: border-box;
    343     transition: transform 300ms;
    344     will-change: transform;
    345 }
    346 
    347 x-dialog:not([show]) {
    348     pointer-events: none;
    349 }
    350 
    351 x-dialog:not([show]) x-paper {
    352     transform: scale(0.1);
    353 }
    354 
    355 x-dialog:not([show]) x-background {
    356     opacity: 0;
    357 }
    358 
    359 x-dialog .row-reverse>.button {
    360     margin-top: 16px;
    361     margin-left: 8px;
    362 }
    363 
    364 x-dialog a {
    365     color: var(--primary-color);
    366 }
    367 
    368 /* Receive Dialog */
    369 #receiveDialog .row {
    370     margin-top: 24px;
    371     margin-bottom: 8px;
    372 }
    373 
    374 /* Receive Text Dialog */
    375 
    376 #receiveTextDialog #text {
    377     width: 100%;
    378     word-break: break-all;
    379     max-height: 300px;
    380     overflow-x: hidden;
    381     overflow-y: auto;
    382     -webkit-user-select: all;
    383     -moz-user-select: all;
    384     user-select: all;
    385     white-space: pre-wrap;
    386 }
    387 
    388 #receiveTextDialog #text a {
    389     cursor: pointer;
    390 }
    391 
    392 #receiveTextDialog #text a:hover {
    393     text-decoration: underline;
    394 }
    395 
    396 #receiveTextDialog h3 {
    397     /* Select the received text when double-clicking the dialog */
    398     user-select: none;
    399     pointer-events: none;
    400 }
    401 
    402 /* Button */
    403 
    404 .button {
    405     padding: 0 16px;
    406     box-sizing: border-box;
    407     min-height: 36px;
    408     min-width: 100px;
    409     font-size: 14px;
    410     line-height: 24px;
    411     font-weight: 700;
    412     letter-spacing: 0.12em;
    413     text-transform: uppercase;
    414     white-space: nowrap;
    415     cursor: pointer;
    416     user-select: none;
    417     background: inherit;
    418     color: var(--primary-color);
    419 }
    420 
    421 .button,
    422 .icon-button {
    423     position: relative;
    424     display: flex;
    425     align-items: center;
    426     justify-content: center;
    427     -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    428     touch-action: manipulation;
    429     border: none;
    430     outline: none;
    431 }
    432 
    433 .button:before,
    434 .icon-button:before {
    435     content: '';
    436     position: absolute;
    437     top: 0;
    438     left: 0;
    439     right: 0;
    440     bottom: 0;
    441     background: currentColor;
    442     opacity: 0;
    443     transition: opacity 300ms;
    444 }
    445 
    446 .button:hover:before,
    447 .icon-button:hover:before {
    448     opacity: 0.1;
    449 }
    450 
    451 .button:before {
    452     border-radius: 8px;
    453 }
    454 
    455 .button:focus:before,
    456 .icon-button:focus:before {
    457     opacity: 0.2;
    458 }
    459 
    460 
    461 
    462 button::-moz-focus-inner {
    463     border: 0;
    464 }
    465 
    466 
    467 /* Icon Button */
    468 
    469 .icon-button {
    470     width: 40px;
    471     height: 40px;
    472 }
    473 
    474 .icon-button:before {
    475     border-radius: 50%;
    476 }
    477 
    478 
    479 
    480 /* Text Input */
    481 
    482 .textarea {
    483     box-sizing: border-box;
    484     border: none;
    485     outline: none;
    486     padding: 16px 24px;
    487     border-radius: 16px;
    488     margin: 8px 0;
    489     font-size: 14px;
    490     font-family: inherit;
    491     background: #f1f3f4;
    492     display: block;
    493     overflow: auto;
    494     resize: none;
    495     min-height: 40px;
    496     line-height: 16px;
    497     max-height: 300px;
    498 }
    499 
    500 
    501 /* Info Animation */
    502 
    503 #about {
    504     color: white;
    505     z-index: 11;
    506     overflow: hidden;
    507     pointer-events: none;
    508     text-align: center;
    509 }
    510 
    511 #about .fade-in {
    512     transition: opacity 300ms;
    513     will-change: opacity;
    514     transition-delay: 300ms;
    515     z-index: 11;
    516     pointer-events: all;
    517 }
    518 
    519 #about:not(:target) .fade-in {
    520     opacity: 0;
    521     pointer-events: none;
    522     transition-delay: 0;
    523 }
    524 
    525 #about .logo {
    526     --icon-size: 96px;
    527 }
    528 
    529 #about x-background {
    530     position: absolute;
    531     top: calc(32px - 200px);
    532     right: calc(32px - 200px);
    533     width: 400px;
    534     height: 400px;
    535     border-radius: 50%;
    536     background: var(--primary-color);
    537     transform: scale(0);
    538     z-index: -1;
    539 }
    540 
    541 /* Hack such that initial scale(0) isn't animated */
    542 #about x-background {
    543     will-change: transform;
    544     transition: transform 800ms cubic-bezier(0.77, 0, 0.175, 1);
    545 }
    546 
    547 #about:target x-background {
    548     transform: scale(10);
    549 }
    550 
    551 #about .row a {
    552     margin: 8px 8px -16px;
    553 }
    554 
    555 
    556 /* Loading Indicator */
    557 
    558 .progress {
    559     width: 80px;
    560     height: 80px;
    561     position: absolute;
    562     top: 0px;
    563     clip: rect(0px, 80px, 80px, 40px);
    564     --progress: rotate(0deg);
    565     transition: transform 200ms;
    566 }
    567 
    568 .circle {
    569     width: 72px;
    570     height: 72px;
    571     border: 4px solid var(--primary-color);
    572     border-radius: 40px;
    573     position: absolute;
    574     clip: rect(0px, 40px, 80px, 0px);
    575     will-change: transform;
    576     transform: var(--progress);
    577 }
    578 
    579 .over50 {
    580     clip: rect(auto, auto, auto, auto);
    581 }
    582 
    583 .over50 .circle.right {
    584     transform: rotate(180deg);
    585 }
    586 
    587 
    588 /* Generic placeholder */
    589 [placeholder]:empty:before {
    590     content: attr(placeholder);
    591 }
    592 
    593 /* Toast */
    594 
    595 .toast-container {
    596     padding: 0 8px 24px;
    597     overflow: hidden;
    598     pointer-events: none;
    599 }
    600 
    601 x-toast {
    602     position: absolute;
    603     min-height: 48px;
    604     bottom: 24px;
    605     width: 100%;
    606     max-width: 344px;
    607     background-color: #323232;
    608     color: rgba(255, 255, 255, 0.95);
    609     align-items: center;
    610     box-sizing: border-box;
    611     padding: 8px 24px;
    612     z-index: 20;
    613     transition: opacity 200ms, transform 300ms ease-out;
    614     cursor: default;
    615     line-height: 24px;
    616     border-radius: 8px;
    617     pointer-events: all;
    618 }
    619 
    620 x-toast:not([show]):not(:hover) {
    621     opacity: 0;
    622     transform: translateY(100px);
    623 }
    624 
    625 
    626 /* Instructions */
    627 
    628 x-instructions {
    629     position: absolute;
    630     top: 120px;
    631     opacity: 0.5;
    632     transition: opacity 300ms;
    633     z-index: -1;
    634     text-align: center;
    635 }
    636 
    637 x-instructions:before {
    638     content: attr(mobile);
    639 }
    640 
    641 x-peers:empty~x-instructions {
    642     opacity: 0;
    643 }
    644 
    645 
    646 /* Responsive Styles */
    647 
    648 @media (min-height: 800px) {
    649     footer {
    650         margin-bottom: 16px;
    651     }
    652 }
    653 
    654 @media screen and (min-height: 800px),
    655 screen and (min-width: 1100px) {
    656     x-instructions:before {
    657         content: attr(desktop);
    658     }
    659 }
    660 
    661 @media (max-height: 420px) {
    662     x-instructions {
    663         top: 24px;
    664     }
    665 
    666     footer .logo {
    667         --icon-size: 40px;
    668     }
    669 }
    670 
    671 /* 
    672     iOS specific styles
    673 */
    674 @supports (-webkit-overflow-scrolling: touch) {
    675 
    676     
    677     html {
    678         position: fixed;
    679     }
    680 
    681     x-instructions:before {
    682         content: attr(mobile);
    683     }
    684 }
    685 
    686 /*
    687     Color Themes
    688 */
    689 
    690 /* Default colors */
    691 body {
    692     --text-color: #333;
    693     --bg-color: #fff;
    694     --bg-color-secondary: #f1f3f4;
    695 }
    696 
    697 /* Dark theme colors */
    698 body.dark-theme {
    699     --text-color: #eee;
    700     --bg-color: #121212;
    701     --bg-color-secondary: #333;
    702 }
    703 
    704 /* Colored Elements */
    705 body {
    706     color: var(--text-color);
    707     background-color: var(--bg-color);
    708     transition: background-color 0.5s ease;
    709 }
    710 
    711 x-dialog x-paper {
    712     background-color: var(--bg-color);
    713 }
    714 
    715 .textarea {
    716     color: var(--text-color);
    717     background-color: var(--bg-color-secondary);
    718 }
    719 /* Image Preview */
    720 #img-preview{
    721     max-height: 50vh;
    722     margin: auto;
    723     display: block;
    724 }
    725 
    726 
    727 /* Styles for users who prefer dark mode at the OS level */
    728 @media (prefers-color-scheme: dark) {
    729 
    730     /* defaults to dark theme */
    731     body {
    732         --text-color: #eee;
    733         --bg-color: #121212;
    734         --bg-color-secondary: #333;
    735     }
    736 
    737     /* Override dark mode with light mode styles if the user decides to swap */
    738     body.light-theme {
    739         --text-color: #333;
    740         --bg-color: #fafafa;
    741         --bg-color-secondary: #f1f3f4;
    742     }
    743 }
    744 
    745 
    746 /* 
    747     Edge specific styles
    748 */
    749 @supports (-ms-ime-align: auto) {
    750 
    751     html,
    752     body {
    753         overflow: hidden;
    754     }
    755 }
    756