From 45c44989c8fb6e24badd18bb83ac5f68de0aceaf Mon Sep 17 00:00:00 2001 From: kibigo! Date: Fri, 17 Nov 2017 19:11:18 -0800 Subject: Forking glitch theme --- app/javascript/styles/application.scss | 23 - app/javascript/styles/doodle.scss | 86 - app/javascript/styles/mastodon/_mixins.scss | 42 - app/javascript/styles/mastodon/about.scss | 822 ---- app/javascript/styles/mastodon/accounts.scss | 589 --- app/javascript/styles/mastodon/admin.scss | 349 -- app/javascript/styles/mastodon/basics.scss | 122 - app/javascript/styles/mastodon/boost.scss | 28 - app/javascript/styles/mastodon/compact_header.scss | 34 - app/javascript/styles/mastodon/components.scss | 4828 -------------------- app/javascript/styles/mastodon/containers.scss | 116 - app/javascript/styles/mastodon/emoji_picker.scss | 199 - app/javascript/styles/mastodon/footer.scss | 30 - app/javascript/styles/mastodon/forms.scss | 540 --- app/javascript/styles/mastodon/landing_strip.scss | 36 - app/javascript/styles/mastodon/lists.scss | 19 - app/javascript/styles/mastodon/reset.scss | 91 - app/javascript/styles/mastodon/rtl.scss | 254 - app/javascript/styles/mastodon/stream_entries.scss | 335 -- app/javascript/styles/mastodon/tables.scss | 76 - app/javascript/styles/mastodon/variables.scss | 32 - app/javascript/styles/variables-glitch.scss | 3 - 22 files changed, 8654 deletions(-) delete mode 100644 app/javascript/styles/application.scss delete mode 100644 app/javascript/styles/doodle.scss delete mode 100644 app/javascript/styles/mastodon/_mixins.scss delete mode 100644 app/javascript/styles/mastodon/about.scss delete mode 100644 app/javascript/styles/mastodon/accounts.scss delete mode 100644 app/javascript/styles/mastodon/admin.scss delete mode 100644 app/javascript/styles/mastodon/basics.scss delete mode 100644 app/javascript/styles/mastodon/boost.scss delete mode 100644 app/javascript/styles/mastodon/compact_header.scss delete mode 100644 app/javascript/styles/mastodon/components.scss delete mode 100644 app/javascript/styles/mastodon/containers.scss delete mode 100644 app/javascript/styles/mastodon/emoji_picker.scss delete mode 100644 app/javascript/styles/mastodon/footer.scss delete mode 100644 app/javascript/styles/mastodon/forms.scss delete mode 100644 app/javascript/styles/mastodon/landing_strip.scss delete mode 100644 app/javascript/styles/mastodon/lists.scss delete mode 100644 app/javascript/styles/mastodon/reset.scss delete mode 100644 app/javascript/styles/mastodon/rtl.scss delete mode 100644 app/javascript/styles/mastodon/stream_entries.scss delete mode 100644 app/javascript/styles/mastodon/tables.scss delete mode 100644 app/javascript/styles/mastodon/variables.scss delete mode 100644 app/javascript/styles/variables-glitch.scss (limited to 'app/javascript/styles') diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss deleted file mode 100644 index efd34393f..000000000 --- a/app/javascript/styles/application.scss +++ /dev/null @@ -1,23 +0,0 @@ -@import 'mastodon/mixins'; -@import 'mastodon/variables'; -@import 'variables-glitch'; -@import 'fonts/roboto'; -@import 'fonts/roboto-mono'; -@import 'fonts/montserrat'; - -@import 'mastodon/reset'; -@import 'mastodon/basics'; -@import 'mastodon/containers'; -@import 'mastodon/lists'; -@import 'mastodon/footer'; -@import 'mastodon/compact_header'; -@import 'mastodon/landing_strip'; -@import 'mastodon/forms'; -@import 'mastodon/accounts'; -@import 'mastodon/stream_entries'; -@import 'mastodon/components'; -@import 'mastodon/emoji_picker'; -@import 'mastodon/about'; -@import 'mastodon/tables'; -@import 'mastodon/admin'; -@import 'mastodon/rtl'; diff --git a/app/javascript/styles/doodle.scss b/app/javascript/styles/doodle.scss deleted file mode 100644 index a4a1cfc84..000000000 --- a/app/javascript/styles/doodle.scss +++ /dev/null @@ -1,86 +0,0 @@ -$doodleBg: #d9e1e8; -.doodle-modal { - @extend .boost-modal; - width: unset; -} - -.doodle-modal__container { - background: $doodleBg; - text-align: center; - line-height: 0; // remove weird gap under canvas - canvas { - border: 5px solid $doodleBg; - } -} - -.doodle-modal__action-bar { - @extend .boost-modal__action-bar; - - .filler { - flex-grow: 1; - margin: 0; - padding: 0; - } - - .doodle-toolbar { - line-height: 1; - - display: flex; - flex-direction: column; - flex-grow: 0; - justify-content: space-around; - - &.with-inputs { - label { - display: inline-block; - width: 70px; - text-align: right; - margin-right: 2px; - } - - input[type="number"],input[type="text"] { - width: 40px; - } - span.val { - display: inline-block; - text-align: left; - width: 50px; - } - } - } - - .doodle-palette { - padding-right: 0 !important; - border: 1px solid black; - line-height: .2rem; - flex-grow: 0; - background: white; - - button { - appearance: none; - width: 1rem; - height: 1rem; - margin: 0; padding: 0; - text-align: center; - color: black; - text-shadow: 0 0 1px white; - cursor: pointer; - box-shadow: inset 0 0 1px rgba(white, .5); - border: 1px solid black; - outline-offset:-1px; - - &.foreground { - outline: 1px dashed white; - } - - &.background { - outline: 1px dashed red; - } - - &.foreground.background { - outline: 1px dashed red; - border-color: white; - } - } - } -} diff --git a/app/javascript/styles/mastodon/_mixins.scss b/app/javascript/styles/mastodon/_mixins.scss deleted file mode 100644 index 7412991b8..000000000 --- a/app/javascript/styles/mastodon/_mixins.scss +++ /dev/null @@ -1,42 +0,0 @@ -@mixin avatar-radius() { - border-radius: $ui-avatar-border-size; - background: transparent no-repeat; - background-position: 50%; - background-clip: padding-box; -} - -@mixin avatar-size($size:48px) { - width: $size; - height: $size; - background-size: $size $size; -} - -@mixin single-column($media, $parent: '&') { - .auto-columns #{$parent} { - @media #{$media} { - @content; - } - } - .single-column #{$parent} { - @content; - } -} - -@mixin limited-single-column($media, $parent: '&') { - .auto-columns #{$parent}, .single-column #{$parent} { - @media #{$media} { - @content; - } - } -} - -@mixin multi-columns($media, $parent: '&') { - .auto-columns #{$parent} { - @media #{$media} { - @content; - } - } - .multi-columns #{$parent} { - @content; - } -} diff --git a/app/javascript/styles/mastodon/about.scss b/app/javascript/styles/mastodon/about.scss deleted file mode 100644 index 4ec689427..000000000 --- a/app/javascript/styles/mastodon/about.scss +++ /dev/null @@ -1,822 +0,0 @@ -.landing-page { - p, - li { - font-family: 'mastodon-font-sans-serif', sans-serif; - font-size: 16px; - font-weight: 400; - font-size: 16px; - line-height: 30px; - margin-bottom: 12px; - color: $ui-primary-color; - - a { - color: $ui-highlight-color; - text-decoration: underline; - } - } - - em { - display: inline; - margin: 0; - padding: 0; - font-weight: 500; - background: transparent; - font-family: inherit; - font-size: inherit; - line-height: inherit; - color: lighten($ui-primary-color, 10%); - } - - h1 { - font-family: 'mastodon-font-display', sans-serif; - font-size: 26px; - line-height: 30px; - font-weight: 500; - margin-bottom: 20px; - color: $ui-secondary-color; - - small { - font-family: 'mastodon-font-sans-serif', sans-serif; - display: block; - font-size: 18px; - font-weight: 400; - color: $ui-base-lighter-color; - } - } - - h2 { - font-family: 'mastodon-font-display', sans-serif; - font-size: 22px; - line-height: 26px; - font-weight: 500; - margin-bottom: 20px; - color: $ui-secondary-color; - } - - h3 { - font-family: 'mastodon-font-display', sans-serif; - font-size: 18px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $ui-secondary-color; - } - - h4 { - font-family: 'mastodon-font-display', sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $ui-secondary-color; - } - - h5 { - font-family: 'mastodon-font-display', sans-serif; - font-size: 14px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $ui-secondary-color; - } - - h6 { - font-family: 'mastodon-font-display', sans-serif; - font-size: 12px; - line-height: 24px; - font-weight: 500; - margin-bottom: 20px; - color: $ui-secondary-color; - } - - ul, - ol { - margin-left: 20px; - - &[type='a'] { - list-style-type: lower-alpha; - } - - &[type='i'] { - list-style-type: lower-roman; - } - } - - ul { - list-style: disc; - } - - ol { - list-style: decimal; - } - - li > ol, - li > ul { - margin-top: 6px; - } - - hr { - border-color: rgba($ui-base-lighter-color, .6); - } - - .container { - width: 100%; - box-sizing: border-box; - max-width: 800px; - margin: 0 auto; - word-wrap: break-word; - } - - .header-wrapper { - padding-top: 15px; - background: $ui-base-color; - background: linear-gradient(150deg, lighten($ui-base-color, 8%), $ui-base-color); - position: relative; - - &.compact { - background: $ui-base-color; - padding-bottom: 15px; - - .hero .heading { - padding-bottom: 20px; - font-family: 'mastodon-font-sans-serif', sans-serif; - font-size: 16px; - font-weight: 400; - font-size: 16px; - line-height: 30px; - color: $ui-primary-color; - - a { - color: $ui-highlight-color; - text-decoration: underline; - } - } - } - - .mascot-container { - max-width: 800px; - margin: 0 auto; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 100%; - } - - .mascot { - position: absolute; - bottom: -14px; - width: auto; - height: auto; - left: 60px; - z-index: 3; - } - } - - .header { - line-height: 30px; - overflow: hidden; - - .container { - display: flex; - justify-content: space-between; - } - - .links { - position: relative; - z-index: 4; - - a { - display: flex; - justify-content: center; - align-items: center; - color: $ui-primary-color; - text-decoration: none; - padding: 12px 16px; - line-height: 32px; - font-family: 'mastodon-font-display', sans-serif; - font-weight: 500; - font-size: 14px; - - &:hover { - color: $ui-secondary-color; - } - } - - .brand { - a { - padding-left: 0; - padding-right: 0; - color: $white; - } - - img { - height: 32px; - position: relative; - top: 4px; - left: -10px; - } - } - - ul { - list-style: none; - margin: 0; - - li { - display: inline-block; - vertical-align: bottom; - margin: 0; - - &:first-child a { - padding-left: 0; - } - - &:last-child a { - padding-right: 0; - } - } - } - } - - .hero { - margin-top: 50px; - align-items: center; - position: relative; - - .floats { - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - - div { - position: absolute; - transition: all 0.1s linear; - animation-name: floating; - animation-iteration-count: infinite; - animation-direction: alternate; - animation-timing-function: ease-in-out; - z-index: 2; - } - - .float-1 { - width: 324px; - height: 170px; - right: -120px; - bottom: 0; - animation-duration: 3s; - background-image: url('data:image/svg+xml;utf8,'); - } - - .float-2 { - width: 241px; - height: 100px; - right: 210px; - bottom: 0; - animation-duration: 3.5s; - animation-delay: 0.2s; - background-image: url('data:image/svg+xml;utf8,'); - } - - .float-3 { - width: 267px; - height: 140px; - right: 110px; - top: -30px; - animation-duration: 4s; - animation-delay: 0.5s; - background-image: url('data:image/svg+xml;utf8,'); - } - } - - .heading { - position: relative; - z-index: 4; - padding-bottom: 150px; - } - - .simple_form, - .closed-registrations-message { - background: darken($ui-base-color, 4%); - width: 280px; - padding: 15px 20px; - border-radius: 4px 4px 0 0; - line-height: initial; - position: relative; - z-index: 4; - - .actions { - margin-bottom: 0; - - button, - .button, - .block-button { - margin-bottom: 0; - } - } - } - - .closed-registrations-message { - min-height: 330px; - display: flex; - flex-direction: column; - justify-content: space-between; - } - } - } - - .about-short { - background: darken($ui-base-color, 4%); - padding: 50px 0 30px; - font-family: 'mastodon-font-sans-serif', sans-serif; - font-size: 16px; - font-weight: 400; - font-size: 16px; - line-height: 30px; - color: $ui-primary-color; - - a { - color: $ui-highlight-color; - text-decoration: underline; - } - } - - .information-board { - background: darken($ui-base-color, 4%); - padding: 20px 0; - - .container { - position: relative; - padding-right: 280px + 15px; - } - - .information-board-sections { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - } - - .section { - flex: 1 0 0; - font-family: 'mastodon-font-sans-serif', sans-serif; - font-size: 16px; - line-height: 28px; - color: $primary-text-color; - text-align: right; - padding: 10px 15px; - - span, - strong { - display: block; - } - - span { - &:last-child { - color: $ui-secondary-color; - } - } - - strong { - font-weight: 500; - font-size: 32px; - line-height: 48px; - } - } - - .panel { - position: absolute; - width: 280px; - box-sizing: border-box; - background: darken($ui-base-color, 8%); - padding: 20px; - padding-top: 10px; - border-radius: 4px 4px 0 0; - right: 0; - bottom: -40px; - - .panel-header { - font-family: 'mastodon-font-display', sans-serif; - font-size: 14px; - line-height: 24px; - font-weight: 500; - color: $ui-primary-color; - padding-bottom: 5px; - margin-bottom: 15px; - border-bottom: 1px solid lighten($ui-base-color, 4%); - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - - a, - span { - font-weight: 400; - color: darken($ui-primary-color, 10%); - } - - a { - text-decoration: none; - } - } - } - - .owner { - text-align: center; - - .avatar { - @include avatar-size(80px); - margin: 0 auto; - margin-bottom: 15px; - - img { - @include avatar-radius(); - @include avatar-size(80px); - display: block; - } - } - - .name { - font-size: 14px; - - a { - display: block; - color: $primary-text-color; - text-decoration: none; - - &:hover { - .display_name { - text-decoration: underline; - } - } - } - - .username { - display: block; - color: $ui-primary-color; - } - } - } - } - - .features { - padding: 50px 0; - - .container { - display: flex; - } - - #mastodon-timeline { - display: flex; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - font-family: 'mastodon-font-sans-serif', sans-serif; - font-size: 13px; - line-height: 18px; - font-weight: 400; - color: $primary-text-color; - width: 330px; - margin-right: 30px; - flex: 0 0 auto; - background: $ui-base-color; - overflow: hidden; - border-radius: 4px; - box-shadow: 0 0 6px rgba($black, 0.1); - - .column-header { - color: inherit; - font-family: inherit; - font-size: 16px; - line-height: inherit; - font-weight: inherit; - margin: 0; - padding: 15px; - } - - .column { - padding: 0; - border-radius: 4px; - overflow: hidden; - } - - .scrollable { - height: 400px; - } - - p { - font-size: inherit; - line-height: inherit; - font-weight: inherit; - color: $primary-text-color; - margin-bottom: 20px; - - &:last-child { - margin-bottom: 0; - } - - a { - color: $ui-secondary-color; - text-decoration: none; - } - } - } - - .about-mastodon { - max-width: 675px; - - p { - margin-bottom: 20px; - } - - .features-list { - margin-top: 20px; - - .features-list__row { - display: flex; - padding: 10px 0; - justify-content: space-between; - - &:first-child { - padding-top: 0; - } - - .visual { - flex: 0 0 auto; - display: flex; - align-items: center; - margin-left: 15px; - - .fa { - display: block; - color: $ui-primary-color; - font-size: 48px; - } - } - - .text { - font-size: 16px; - line-height: 30px; - color: $ui-primary-color; - - h6 { - font-size: inherit; - line-height: inherit; - margin-bottom: 0; - } - } - } - } - } - } - - .extended-description { - padding: 50px 0; - font-family: 'mastodon-font-sans-serif', sans-serif; - font-size: 16px; - font-weight: 400; - font-size: 16px; - line-height: 30px; - color: $ui-primary-color; - - a { - color: $ui-highlight-color; - text-decoration: underline; - } - } - - .footer-links { - padding-bottom: 50px; - text-align: right; - color: $ui-base-lighter-color; - - p { - font-size: 14px; - } - - a { - color: inherit; - text-decoration: underline; - } - } - - @media screen and (max-width: 840px) { - .container { - padding: 0 20px; - } - - .information-board { - - .container { - padding-right: 20px; - } - - .section { - text-align: center; - } - - .panel { - position: static; - margin-top: 20px; - width: 100%; - border-radius: 4px; - - .panel-header { - text-align: center; - } - } - } - - .header-wrapper .mascot { - left: 20px; - } - } - - @media screen and (max-width: 689px) { - .header-wrapper .mascot { - display: none; - } - } - - @media screen and (max-width: 675px) { - .header-wrapper { - padding-top: 0; - - &.compact { - padding-bottom: 0; - } - - &.compact .hero .heading { - text-align: initial; - } - } - - .header .container, - .features .container { - display: block; - } - - .header { - - .links { - padding-top: 15px; - background: darken($ui-base-color, 4%); - - a { - padding: 12px 8px; - } - - .nav { - display: flex; - flex-flow: row wrap; - justify-content: space-around; - } - - .brand img { - left: 0; - top: 0; - } - } - - .hero { - margin-top: 30px; - padding: 0; - - .floats { - display: none; - } - - .heading { - padding: 30px 20px; - text-align: center; - } - - .simple_form, - .closed-registrations-message { - background: darken($ui-base-color, 8%); - width: 100%; - border-radius: 0; - box-sizing: border-box; - } - } - } - - .features #mastodon-timeline { - height: 70vh; - width: 100%; - margin-bottom: 50px; - - .column { - width: 100%; - } - } - } - - .cta { - margin: 20px; - } - - &.tag-page { - .features { - padding: 30px 0; - - .container { - max-width: 820px; - - #mastodon-timeline { - margin-right: 0; - border-top-right-radius: 0; - } - - .about-mastodon { - .about-hashtag { - background: darken($ui-base-color, 4%); - padding: 0 20px 20px 30px; - border-radius: 0 5px 5px 0; - - .brand { - padding-top: 20px; - margin-bottom: 20px; - - img { - height: 48px; - width: auto; - } - } - - p { - strong { - color: $ui-secondary-color; - font-weight: 700; - } - } - - .cta { - margin: 0; - - .button { - margin-right: 4px; - } - } - } - - .features-list { - margin-left: 30px; - margin-right: 10px; - } - } - } - } - - @media screen and (max-width: 675px) { - .features { - padding: 10px 0; - - .container { - display: flex; - flex-direction: column; - - #mastodon-timeline { - order: 2; - flex: 0 0 auto; - height: 60vh; - margin-bottom: 20px; - border-top-right-radius: 4px; - } - - .about-mastodon { - order: 1; - flex: 0 0 auto; - max-width: 100%; - - .about-hashtag { - background: unset; - padding: 0; - border-radius: 0; - - .cta { - margin: 20px 0; - } - } - - .features-list { - display: none; - } - } - } - } - } - } -} - -@keyframes floating { - from { - transform: translate(0, 0); - } - - 65% { - transform: translate(0, 4px); - } - - to { - transform: translate(0, -0); - } -} diff --git a/app/javascript/styles/mastodon/accounts.scss b/app/javascript/styles/mastodon/accounts.scss deleted file mode 100644 index 2cf98c642..000000000 --- a/app/javascript/styles/mastodon/accounts.scss +++ /dev/null @@ -1,589 +0,0 @@ -.card { - background-color: lighten($ui-base-color, 4%); - background-size: cover; - background-position: center; - border-radius: 4px 4px 0 0; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - overflow: hidden; - position: relative; - display: flex; - - &::after { - background: rgba(darken($ui-base-color, 8%), 0.5); - display: block; - content: ""; - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - z-index: 1; - } - - @media screen and (max-width: 740px) { - border-radius: 0; - box-shadow: none; - } - - .card__illustration { - padding: 60px 0; - position: relative; - flex: 1 1 auto; - display: flex; - justify-content: center; - align-items: center; - } - - .card__bio { - max-width: 260px; - flex: 1 1 auto; - display: flex; - flex-direction: column; - justify-content: space-between; - background: rgba(darken($ui-base-color, 8%), 0.8); - position: relative; - z-index: 2; - } - - &.compact { - padding: 30px 0; - border-radius: 4px; - - .avatar { - margin-bottom: 0; - - img { - object-fit: cover; - } - } - } - - .name { - display: block; - font-size: 20px; - line-height: 18px * 1.5; - color: $primary-text-color; - padding: 10px 15px; - padding-bottom: 0; - font-weight: 500; - position: relative; - z-index: 2; - margin-bottom: 30px; - overflow: hidden; - text-overflow: ellipsis; - - small { - display: block; - font-size: 14px; - color: $ui-highlight-color; - font-weight: 400; - overflow: hidden; - text-overflow: ellipsis; - } - } - - .avatar { - @include avatar-size(120px); - margin: 0 auto; - position: relative; - z-index: 2; - - img { - @include avatar-radius(); - @include avatar-size(120px); - display: block; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - } - } - - .controls { - position: absolute; - top: 15px; - left: 15px; - z-index: 2; - - .icon-button { - color: rgba($white, 0.8); - text-decoration: none; - font-size: 13px; - line-height: 13px; - font-weight: 500; - - .fa { - font-weight: 400; - margin-right: 5px; - } - - &:hover, - &:active, - &:focus { - color: $white; - } - } - } - - .roles { - margin-bottom: 30px; - padding: 0 15px; - } - - .details-counters { - margin-top: 30px; - display: flex; - flex-direction: row; - width: 100%; - } - - .counter { - width: 33.3%; - box-sizing: border-box; - flex: 0 0 auto; - color: $ui-primary-color; - padding: 5px 10px 0; - margin-bottom: 10px; - border-right: 1px solid lighten($ui-base-color, 4%); - cursor: default; - text-align: center; - position: relative; - - a { - display: block; - } - - &:last-child { - border-right: 0; - } - - &::after { - display: block; - content: ""; - position: absolute; - bottom: -10px; - left: 0; - width: 100%; - border-bottom: 4px solid $ui-primary-color; - opacity: 0.5; - transition: all 400ms ease; - } - - &.active { - &::after { - border-bottom: 4px solid $ui-highlight-color; - opacity: 1; - } - } - - &:hover { - &::after { - opacity: 1; - transition-duration: 100ms; - } - } - - a { - text-decoration: none; - color: inherit; - } - - .counter-label { - font-size: 12px; - display: block; - margin-bottom: 5px; - } - - .counter-number { - font-weight: 500; - font-size: 18px; - color: $primary-text-color; - font-family: 'mastodon-font-display', sans-serif; - } - } - - .bio { - font-size: 14px; - line-height: 18px; - padding: 0 15px; - color: $ui-secondary-color; - } - - .metadata { - $meta-table-border: darken($classic-highlight-color, 20%);//#174f77; - - border-collapse: collapse; - padding: 0; - margin: 15px -15px -10px -15px; - border: 0 none; - border-top: 1px solid $meta-table-border; - border-bottom: 1px solid $meta-table-border; - - td, th { - padding: 10px; - border: 0 none; - border-bottom: 1px solid $meta-table-border; - vertical-align: middle; - } - - tr:last-child { - td, th { - border-bottom: 0 none; - } - } - - td { - color: $ui-primary-color; - width:100%; // makes it stretch - padding-left: 0; - } - - th { - padding-left: 15px; - font-weight: bold; - text-align: left; - width: 94px; - color: $ui-secondary-color; - background: darken($ui-base-color, 8%); - //background: #131415; - } - - a { - color: $classic-highlight-color; - } - } - - @media screen and (max-width: 480px) { - display: block; - - .card__bio { - max-width: none; - } - - .name, - .roles { - text-align: center; - margin-bottom: 15px; - } - - .bio { - margin-bottom: 15px; - } - } -} - -.pagination { - padding: 30px 0; - text-align: center; - overflow: hidden; - - a, - .current, - .next, - .prev, - .page, - .gap { - font-size: 14px; - color: $primary-text-color; - font-weight: 500; - display: inline-block; - padding: 6px 10px; - text-decoration: none; - } - - .current { - background: $simple-background-color; - border-radius: 100px; - color: $ui-base-color; - cursor: default; - margin: 0 10px; - } - - .gap { - cursor: default; - } - - .prev, - .next { - text-transform: uppercase; - color: $ui-secondary-color; - } - - .prev { - float: left; - padding-left: 0; - - .fa { - display: inline-block; - margin-right: 5px; - } - } - - .next { - float: right; - padding-right: 0; - - .fa { - display: inline-block; - margin-left: 5px; - } - } - - .disabled { - cursor: default; - color: lighten($ui-base-color, 10%); - } - - @media screen and (max-width: 700px) { - padding: 30px 20px; - - .page { - display: none; - } - - .next, - .prev { - display: inline-block; - } - } -} - -.accounts-grid { - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - background: darken($simple-background-color, 8%); - border-radius: 0 0 4px 4px; - padding: 20px 5px; - padding-bottom: 10px; - overflow: hidden; - display: flex; - flex-wrap: wrap; - z-index: 2; - position: relative; - - @media screen and (max-width: 740px) { - border-radius: 0; - box-shadow: none; - } - - .account-grid-card { - box-sizing: border-box; - width: 335px; - background: $simple-background-color; - border-radius: 4px; - color: $ui-base-color; - margin: 0 5px 10px; - position: relative; - - @media screen and (max-width: 740px) { - width: calc(100% - 10px); - } - - .account-grid-card__header { - overflow: hidden; - height: 100px; - border-radius: 4px 4px 0 0; - background-color: lighten($ui-base-color, 4%); - background-size: cover; - background-position: center; - position: relative; - - &::after { - background: rgba(darken($ui-base-color, 8%), 0.5); - display: block; - content: ""; - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - z-index: 1; - } - } - - .account-grid-card__avatar { - box-sizing: border-box; - padding: 15px; - position: absolute; - z-index: 2; - top: 100px - (40px + 2px); - left: -2px; - } - - .avatar { - @include avatar-size(80px); - - img { - display: block; - @include avatar-radius(); - @include avatar-size(80px); - border: 2px solid $simple-background-color; - background: $simple-background-color; - } - } - - .name { - padding: 15px; - padding-top: 10px; - padding-left: 15px + 80px + 15px; - - a { - display: block; - color: $ui-base-color; - text-decoration: none; - text-overflow: ellipsis; - overflow: hidden; - font-weight: 500; - - &:hover { - .display_name { - text-decoration: underline; - } - } - } - } - - .display_name { - font-size: 16px; - display: block; - text-overflow: ellipsis; - overflow: hidden; - } - - .username { - color: lighten($ui-base-color, 34%); - font-size: 14px; - font-weight: 400; - } - - .note { - padding: 10px 15px; - padding-top: 15px; - box-sizing: border-box; - color: lighten($ui-base-color, 26%); - word-wrap: break-word; - min-height: 80px; - } - } -} - -.nothing-here { - width: 100%; - display: block; - color: $ui-primary-color; - font-size: 14px; - font-weight: 500; - text-align: center; - padding: 60px 0; - padding-top: 55px; - cursor: default; -} - -.account-card { - padding: 14px 10px; - background: $simple-background-color; - border-radius: 4px; - text-align: left; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - - .detailed-status__display-name { - display: block; - overflow: hidden; - margin-bottom: 15px; - - &:last-child { - margin-bottom: 0; - } - - & > div { - @include avatar-size(48px); - float: left; - margin-right: 10px; - } - - .avatar { - @include avatar-radius(); - display: block; - } - - .display-name { - display: block; - max-width: 100%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - cursor: default; - - strong { - font-weight: 500; - color: $ui-base-color; - } - - span { - font-size: 14px; - color: $ui-primary-color; - } - } - - &:hover { - .display-name { - strong { - text-decoration: none; - } - } - } - } - - .account__header__content { - font-size: 14px; - color: $ui-base-color; - } -} - -.activity-stream-tabs { - background: $simple-background-color; - border-bottom: 1px solid $ui-secondary-color; - position: relative; - z-index: 2; - - a { - display: inline-block; - padding: 15px; - text-decoration: none; - color: $ui-highlight-color; - text-transform: uppercase; - font-weight: 500; - - &:hover, - &:active, - &:focus { - color: lighten($ui-highlight-color, 8%); - } - - &.active { - color: $ui-base-color; - cursor: default; - } - } -} - -.account-role { - display: inline-block; - padding: 4px 6px; - cursor: default; - border-radius: 3px; - font-size: 12px; - line-height: 12px; - font-weight: 500; - color: $ui-secondary-color; - background-color: rgba($ui-secondary-color, 0.1); - border: 1px solid rgba($ui-secondary-color, 0.5); - - &.moderator { - color: $success-green; - background-color: rgba($success-green, 0.1); - border-color: rgba($success-green, 0.5); - } - - &.admin { - color: lighten($error-red, 12%); - background-color: rgba(lighten($error-red, 12%), 0.1); - border-color: rgba(lighten($error-red, 12%), 0.5); - } -} diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss deleted file mode 100644 index 87bc710af..000000000 --- a/app/javascript/styles/mastodon/admin.scss +++ /dev/null @@ -1,349 +0,0 @@ -.admin-wrapper { - display: flex; - justify-content: center; - height: 100%; - - .sidebar-wrapper { - flex: 1; - height: 100%; - background: $ui-base-color; - display: flex; - justify-content: flex-end; - } - - .sidebar { - width: 240px; - height: 100%; - padding: 0; - overflow-y: auto; - - .logo { - display: block; - margin: 40px auto; - width: 100px; - height: 100px; - } - - ul { - list-style: none; - border-radius: 4px 0 0 4px; - overflow: hidden; - margin-bottom: 20px; - - a { - display: block; - padding: 15px; - color: rgba($primary-text-color, 0.7); - text-decoration: none; - transition: all 200ms linear; - border-radius: 4px 0 0 4px; - - i.fa { - margin-right: 5px; - } - - &:hover { - color: $primary-text-color; - background-color: darken($ui-base-color, 5%); - transition: all 100ms linear; - } - - &.selected { - background: darken($ui-base-color, 2%); - border-radius: 4px 0 0; - } - } - - ul { - background: darken($ui-base-color, 4%); - border-radius: 0 0 0 4px; - margin: 0; - - a { - border: 0; - padding: 15px 35px; - - &.selected { - color: $primary-text-color; - background-color: $ui-highlight-color; - border-bottom: 0; - border-radius: 0; - - &:hover { - background-color: lighten($ui-highlight-color, 5%); - } - } - } - } - } - } - - .content-wrapper { - flex: 2; - overflow: auto; - } - - .content { - max-width: 700px; - padding: 20px 15px; - padding-top: 60px; - padding-left: 25px; - - h2 { - color: $ui-secondary-color; - font-size: 24px; - line-height: 28px; - font-weight: 400; - margin-bottom: 40px; - } - - h3 { - color: $ui-secondary-color; - font-size: 20px; - line-height: 28px; - font-weight: 400; - margin-bottom: 30px; - } - - h6 { - font-size: 16px; - color: $ui-secondary-color; - line-height: 28px; - font-weight: 400; - } - - & > p { - font-size: 14px; - line-height: 18px; - color: $ui-secondary-color; - margin-bottom: 20px; - - strong { - color: $primary-text-color; - font-weight: 500; - } - } - - hr { - margin: 20px 0; - border: 0; - background: transparent; - border-bottom: 1px solid $ui-base-color; - } - - .muted-hint { - color: $ui-primary-color; - - a { - color: $ui-highlight-color; - } - } - - .positive-hint { - color: $valid-value-color; - font-weight: 500; - } - } - - .simple_form { - max-width: 400px; - - &.edit_user, - &.new_form_admin_settings, - &.new_form_two_factor_confirmation, - &.new_form_delete_confirmation, - &.new_import, - &.new_domain_block, - &.edit_domain_block { - max-width: none; - } - - .form_two_factor_confirmation_code, - .form_delete_confirmation_password { - max-width: 400px; - } - - .actions { - max-width: 400px; - } - } - - @media screen and (max-width: 600px) { - display: block; - overflow-y: auto; - -webkit-overflow-scrolling: touch; - - .sidebar-wrapper, - .content-wrapper { - flex: 0 0 auto; - height: auto; - overflow: initial; - } - - .sidebar { - width: 100%; - padding: 10px 0; - height: auto; - - .logo { - margin: 20px auto; - } - } - - .content { - padding-top: 20px; - } - } -} - -.filters { - display: flex; - flex-wrap: wrap; - - .filter-subset { - flex: 0 0 auto; - margin: 0 40px 10px 0; - - &:last-child { - margin-bottom: 20px; - } - - ul { - margin-top: 5px; - list-style: none; - - li { - display: inline-block; - margin-right: 5px; - } - } - - strong { - font-weight: 500; - text-transform: uppercase; - font-size: 12px; - } - - a { - display: inline-block; - color: rgba($primary-text-color, 0.7); - text-decoration: none; - text-transform: uppercase; - font-size: 12px; - font-weight: 500; - border-bottom: 2px solid $ui-base-color; - - &:hover { - color: $primary-text-color; - border-bottom: 2px solid lighten($ui-base-color, 5%); - } - - &.selected { - color: $ui-highlight-color; - border-bottom: 2px solid $ui-highlight-color; - } - } - } -} - -.report-accounts { - display: flex; - flex-wrap: wrap; - margin-bottom: 20px; -} - -.report-accounts__item { - display: flex; - flex: 250px; - flex-direction: column; - margin: 0 5px; - - & > strong { - display: block; - margin: 0 0 10px -5px; - font-weight: 500; - font-size: 14px; - line-height: 18px; - color: $ui-secondary-color; - } - - .account-card { - flex: 1 1 auto; - } -} - -.report-status, -.account-status { - display: flex; - margin-bottom: 10px; - - .activity-stream { - flex: 2 0 0; - margin-right: 20px; - max-width: calc(100% - 60px); - - .entry { - border-radius: 4px; - } - } -} - -.report-status__actions, -.account-status__actions { - flex: 0 0 auto; - display: flex; - flex-direction: column; - - .icon-button { - font-size: 24px; - width: 24px; - text-align: center; - margin-bottom: 10px; - } -} - -.batch-form-box { - display: flex; - flex-wrap: wrap; - margin-bottom: 5px; - - #form_status_batch_action { - margin: 0 5px 5px 0; - font-size: 14px; - } - - input.button { - margin: 0 5px 5px 0; - } - - .media-spoiler-toggle-buttons { - margin-left: auto; - - .button { - overflow: visible; - margin: 0 0 5px 5px; - float: right; - } - } -} - -.batch-checkbox, -.batch-checkbox-all { - display: flex; - align-items: center; - margin-right: 5px; -} - -.back-link { - margin-bottom: 10px; - font-size: 14px; - - a { - color: $classic-highlight-color; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } -} diff --git a/app/javascript/styles/mastodon/basics.scss b/app/javascript/styles/mastodon/basics.scss deleted file mode 100644 index b5d77ff63..000000000 --- a/app/javascript/styles/mastodon/basics.scss +++ /dev/null @@ -1,122 +0,0 @@ -body { - font-family: 'mastodon-font-sans-serif', sans-serif; - background: $ui-base-color; - background-size: cover; - background-attachment: fixed; - font-size: 13px; - line-height: 18px; - font-weight: 400; - color: $primary-text-color; - padding-bottom: 20px; - text-rendering: optimizelegibility; - font-feature-settings: "kern"; - text-size-adjust: none; - -webkit-tap-highlight-color: rgba(0,0,0,0); - -webkit-tap-highlight-color: transparent; - - &.system-font { - // system-ui => standard property (Chrome/Android WebView 56+, Opera 43+, Safari 11+) - // -apple-system => Safari <11 specific - // BlinkMacSystemFont => Chrome <56 on macOS specific - // Segoe UI => Windows 7/8/10 - // Oxygen => KDE - // Ubuntu => Unity/Ubuntu - // Cantarell => GNOME - // Fira Sans => Firefox OS - // Droid Sans => Older Androids (<4.0) - // Helvetica Neue => Older macOS <10.11 - // mastodon-font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0) - font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", mastodon-font-sans-serif, sans-serif; - } - - &.app-body { - position: absolute; - width: 100%; - height: 100%; - padding: 0; - background: $ui-base-color; - } - - &.about-body { - background: darken($ui-base-color, 8%); - padding-bottom: 0; - } - - &.tag-body { - background: darken($ui-base-color, 8%); - padding-bottom: 0; - } - - &.embed { - background: transparent; - margin: 0; - padding-bottom: 0; - - .container { - position: absolute; - width: 100%; - height: 100%; - overflow: hidden; - } - } - - &.admin { - background: darken($ui-base-color, 4%); - position: fixed; - width: 100%; - height: 100%; - padding: 0; - } - - &.error { - position: absolute; - text-align: center; - color: $ui-primary-color; - background: $ui-base-color; - width: 100%; - height: 100%; - padding: 0; - display: flex; - justify-content: center; - align-items: center; - - .dialog { - vertical-align: middle; - margin: 20px; - - img { - display: block; - max-width: 470px; - width: 100%; - height: auto; - margin-top: -120px; - } - - h1 { - font-size: 20px; - line-height: 28px; - font-weight: 400; - } - } - } -} - -button { - font-family: inherit; - cursor: pointer; - - &:focus { - outline: none; - } -} - -.app-holder { - &, - & > div { - display: flex; - width: 100%; - height: 100%; - align-items: center; - justify-content: center; - } -} diff --git a/app/javascript/styles/mastodon/boost.scss b/app/javascript/styles/mastodon/boost.scss deleted file mode 100644 index b07b72f8e..000000000 --- a/app/javascript/styles/mastodon/boost.scss +++ /dev/null @@ -1,28 +0,0 @@ -@function hex-color($color) { - @if type-of($color) == 'color' { - $color: str-slice(ie-hex-str($color), 4); - } - @return '%23' + unquote($color) -} - -button.icon-button i.fa-retweet { - background-image: url("data:image/svg+xml;utf8,"); - - &:hover { - background-image: url("data:image/svg+xml;utf8,"); - } -} - -// Disabled variant -button.icon-button.disabled i.fa-retweet { - &, &:hover { - background-image: url("data:image/svg+xml;utf8,"); - } -} - -// Disabled variant for use with DMs -.status-direct button.icon-button.disabled i.fa-retweet { - &, &:hover { - background-image: url("data:image/svg+xml;utf8,"); - } -} diff --git a/app/javascript/styles/mastodon/compact_header.scss b/app/javascript/styles/mastodon/compact_header.scss deleted file mode 100644 index 90d98cc8c..000000000 --- a/app/javascript/styles/mastodon/compact_header.scss +++ /dev/null @@ -1,34 +0,0 @@ -.compact-header { - h1 { - font-size: 24px; - line-height: 28px; - color: $ui-primary-color; - font-weight: 500; - margin-bottom: 20px; - padding: 0 10px; - word-wrap: break-word; - - @media screen and (max-width: 740px) { - text-align: center; - padding: 20px 10px 0; - } - - a { - color: inherit; - text-decoration: none; - } - - small { - font-weight: 400; - color: $ui-secondary-color; - } - - img { - display: inline-block; - margin-bottom: -5px; - margin-right: 15px; - width: 36px; - height: 36px; - } - } -} diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss deleted file mode 100644 index 6a6d1bdca..000000000 --- a/app/javascript/styles/mastodon/components.scss +++ /dev/null @@ -1,4828 +0,0 @@ -@import 'variables'; -@import 'variables-glitch'; - -@mixin fullwidth-gallery { - &.full-width { - margin-left: -22px; - margin-right: -22px; - width: inherit; - } -} - -.app-body { - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; -} - -.button { - background-color: darken($ui-highlight-color, 3%); - border: 10px none; - border-radius: 4px; - box-sizing: border-box; - color: $primary-text-color; - cursor: pointer; - display: inline-block; - font-family: inherit; - font-size: 14px; - font-weight: 500; - height: 36px; - letter-spacing: 0; - line-height: 36px; - overflow: hidden; - padding: 0 16px; - position: relative; - text-align: center; - text-transform: uppercase; - text-decoration: none; - text-overflow: ellipsis; - transition: all 100ms ease-in; - white-space: nowrap; - width: auto; - - &:active, - &:focus, - &:hover { - background-color: lighten($ui-highlight-color, 7%); - transition: all 200ms ease-out; - } - - &:disabled { - background-color: $ui-primary-color; - cursor: default; - } - - &.button-alternative { - font-size: 16px; - line-height: 36px; - height: auto; - color: $ui-base-color; - background: $ui-primary-color; - text-transform: none; - padding: 4px 16px; - - &:active, - &:focus, - &:hover { - background-color: lighten($ui-primary-color, 4%); - } - } - - &.button-secondary { - font-size: 16px; - line-height: 36px; - height: auto; - color: $ui-primary-color; - text-transform: none; - background: transparent; - padding: 3px 15px; - border-radius: 4px; - border: 1px solid $ui-primary-color; - - &:active, - &:focus, - &:hover { - border-color: lighten($ui-primary-color, 4%); - color: lighten($ui-primary-color, 4%); - } - } - - &.button--block { - display: block; - width: 100%; - } -} - -.column__wrapper { - display: flex; - flex: 1 1 auto; - position: relative; -} - -.column-icon { - background: lighten($ui-base-color, 4%); - color: $ui-primary-color; - cursor: pointer; - font-size: 16px; - padding: 15px; - position: absolute; - right: 0; - top: -48px; - z-index: 3; - - &:hover { - color: lighten($ui-primary-color, 7%); - } -} - -.icon-button { - display: inline-block; - padding: 0; - color: $ui-base-lighter-color; - border: none; - background: transparent; - cursor: pointer; - transition: color 100ms ease-in; - - &:hover, - &:active, - &:focus { - color: lighten($ui-base-color, 33%); - transition: color 200ms ease-out; - } - - &.disabled { - color: lighten($ui-base-color, 13%); - cursor: default; - } - - &.active { - color: $ui-highlight-color; - } - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } - - &.inverted { - color: lighten($ui-base-color, 33%); - - &:hover, - &:active, - &:focus { - color: $ui-base-lighter-color; - } - - &.disabled { - color: $ui-primary-color; - } - - &.active { - color: $ui-highlight-color; - - &.disabled { - color: lighten($ui-highlight-color, 13%); - } - } - } - - &.overlayed { - box-sizing: content-box; - background: rgba($base-overlay-background, 0.6); - color: rgba($primary-text-color, 0.7); - border-radius: 4px; - padding: 2px; - - &:hover { - background: rgba($base-overlay-background, 0.9); - } - } -} - -.text-icon-button { - color: lighten($ui-base-color, 33%); - border: none; - background: transparent; - cursor: pointer; - font-weight: 600; - font-size: 11px; - padding: 0 3px; - line-height: 27px; - outline: 0; - transition: color 100ms ease-in; - - &:hover, - &:active, - &:focus { - color: $ui-base-lighter-color; - transition: color 200ms ease-out; - } - - &.disabled { - color: lighten($ui-base-color, 13%); - cursor: default; - } - - &.active { - color: $ui-highlight-color; - } - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } -} - -.dropdown-menu { - position: absolute; -} - -.dropdown--active .icon-button { - color: $ui-highlight-color; -} - -.dropdown--active::after { - @media screen and (min-width: 631px) { - content: ""; - display: block; - position: absolute; - width: 0; - height: 0; - border-style: solid; - border-width: 0 4.5px 7.8px; - border-color: transparent transparent $ui-secondary-color; - bottom: 8px; - right: 104px; - } -} - -.invisible { - font-size: 0; - line-height: 0; - display: inline-block; - width: 0; - height: 0; - position: absolute; - - img, - svg { - margin: 0 !important; - border: 0 !important; - padding: 0 !important; - width: 0 !important; - height: 0 !important; - } -} - -.ellipsis { - &::after { - content: "…"; - } -} - -.lightbox .icon-button { - color: $ui-base-color; -} - -.compose-form { - padding: 10px; -} - -.compose-form__warning { - color: darken($ui-secondary-color, 65%); - margin-bottom: 15px; - background: $ui-primary-color; - box-shadow: 0 2px 6px rgba($base-shadow-color, 0.3); - padding: 8px 10px; - border-radius: 4px; - font-size: 13px; - font-weight: 400; - - strong { - color: darken($ui-secondary-color, 65%); - font-weight: 500; - } - - a { - color: darken($ui-primary-color, 33%); - font-weight: 500; - text-decoration: underline; - - &:hover, - &:active, - &:focus { - text-decoration: none; - } - } -} - -.compose-form__modifiers { - color: $ui-base-color; - font-family: inherit; - font-size: 14px; - background: $simple-background-color; -} - -.compose-form__buttons-wrapper { - display: flex; - justify-content: space-between; -} - -.compose-form__buttons { - padding: 10px; - background: darken($simple-background-color, 8%); - box-shadow: inset 0 5px 5px rgba($base-shadow-color, 0.05); - border-radius: 0 0 4px 4px; - display: flex; - - .icon-button { - box-sizing: content-box; - padding: 0 3px; - } -} - -.compose-form__buttons-separator { - border-left: 1px solid #c3c3c3; - margin: 0 3px; -} - -.compose-form__upload-button-icon { - line-height: 27px; -} - -.compose-form__sensitive-button { - display: none; - - &.compose-form__sensitive-button--visible { - display: block; - } - - .compose-form__sensitive-button__icon { - line-height: 27px; - } -} - -.compose-form__upload-wrapper { - overflow: hidden; -} - -.compose-form__uploads-wrapper { - display: flex; - flex-direction: row; - padding: 5px; - flex-wrap: wrap; -} - -.compose-form__upload { - flex: 1 1 0; - min-width: 40%; - margin: 5px; - - &-description { - position: absolute; - z-index: 2; - bottom: 0; - left: 0; - right: 0; - box-sizing: border-box; - background: linear-gradient(0deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent); - padding: 10px; - opacity: 0; - transition: opacity .1s ease; - - input { - background: transparent; - color: $ui-secondary-color; - border: 0; - padding: 0; - margin: 0; - width: 100%; - font-family: inherit; - font-size: 14px; - font-weight: 500; - - &:focus { - color: $white; - } - - &::placeholder { - opacity: 0.54; - color: $ui-secondary-color; - } - } - - &.active { - opacity: 1; - } - } - - .icon-button { - mix-blend-mode: difference; - } -} - -.compose-form__upload-thumbnail { - border-radius: 4px; - background-position: center; - background-size: cover; - background-repeat: no-repeat; - height: 100px; - width: 100%; -} - -.compose-form__label { - display: block; - line-height: 24px; - vertical-align: middle; - - &.with-border { - border-top: 1px solid $ui-base-color; - padding-top: 10px; - } - - .compose-form__label__text { - display: inline-block; - vertical-align: middle; - margin-bottom: 14px; - margin-left: 8px; - color: $ui-primary-color; - } -} - -.compose-form__textarea, -.follow-form__input { - background: $simple-background-color; - - &:disabled { - background: $ui-secondary-color; - } -} - -.compose-form__autosuggest-wrapper { - position: relative; - - .emoji-picker-dropdown { - position: absolute; - right: 5px; - top: 5px; - - ::-webkit-scrollbar-track:hover, - ::-webkit-scrollbar-track:active { - background-color: rgba($base-overlay-background, 0.3); - } - } -} - -.compose-form__publish { - display: flex; - justify-content: flex-end; - min-width: 0; -} - -.compose-form__publish-button-wrapper { - overflow: hidden; - padding-top: 10px; - white-space: nowrap; - display: flex; - - button { - text-overflow: unset; - } -} - -.compose-form__publish__side-arm { - padding: 0 !important; - width: 36px; - text-align: center; - margin-right: 2px; -} - -.compose-form__publish__primary { - padding: 0 10px !important; -} - -.emojione { - display: inline-block; - font-size: inherit; - vertical-align: middle; - object-fit: contain; - margin: -.2ex .15em .2ex; - width: 16px; - height: 16px; - - img { - width: auto; - } -} - -.reply-indicator { - border-radius: 4px 4px 0 0; - position: relative; - bottom: -2px; - background: $ui-primary-color; - padding: 10px; -} - -.reply-indicator__header { - margin-bottom: 5px; - overflow: hidden; -} - -.reply-indicator__cancel { - float: right; - line-height: 24px; -} - -.reply-indicator__display-name { - color: $ui-base-color; - display: block; - max-width: 100%; - line-height: 24px; - overflow: hidden; - padding-right: 25px; - text-decoration: none; -} - -.reply-indicator__display-avatar { - float: left; - margin-right: 5px; -} - -.status__content--with-action { - cursor: pointer; -} - -.status-check-box { - .status__content, - .reply-indicator__content { - color: #3a3a3a; - a { - color: #005aa9; - } - } -} - -.status__content, -.reply-indicator__content { - position: relative; - margin: 10px 0; - padding: 0 12px; - font-size: 15px; - line-height: 20px; - color: $primary-text-color; - word-wrap: break-word; - font-weight: 400; - overflow: visible; - white-space: pre-wrap; - padding-top: 5px; - - &.status__content--with-spoiler { - white-space: normal; - - .status__content__text { - white-space: pre-wrap; - } - } - - .emojione { - width: 20px; - height: 20px; - margin: -5px 0 0; - } - - p { - margin-bottom: 20px; - - &:last-child { - margin-bottom: 0; - } - } - - a { - color: $ui-secondary-color; - text-decoration: none; - - &:hover { - text-decoration: underline; - - .fa { - color: lighten($ui-base-color, 40%); - } - } - - &.mention { - &:hover { - text-decoration: none; - - span { - text-decoration: underline; - } - } - } - - .fa { - color: lighten($ui-base-color, 30%); - } - } - - .status__content__spoiler { - display: none; - - &.status__content__spoiler--visible { - display: block; - } - } -} - -.status__content__spoiler-link { - display: inline-block; - border-radius: 2px; - background: lighten($ui-base-color, 30%); - border: none; - color: lighten($ui-base-color, 8%); - font-weight: 500; - font-size: 11px; - padding: 0 5px; - text-transform: uppercase; - line-height: inherit; - cursor: pointer; - vertical-align: bottom; - - &:hover { - background: lighten($ui-base-color, 33%); - text-decoration: none; - } - - .status__content__spoiler-icon { - display: inline-block; - margin: 0 0 0 5px; - border-left: 1px solid currentColor; - padding: 0 0 0 4px; - font-size: 16px; - vertical-align: -2px; - } -} - -.status__prepend-icon-wrapper { - float: left; - margin: 0 10px 0 -58px; - width: 48px; - text-align: right; -} - -.notif-cleaning { - .status, .notification-follow { - padding-right: ($dismiss-overlay-width + 0.5rem); - } -} - -.notification-follow { - position: relative; - - // same like Status - border-bottom: 1px solid lighten($ui-base-color, 8%); - - .account { - border-bottom: 0 none; - } -} - -.focusable { - &:focus { - outline: 0; - background: lighten($ui-base-color, 4%); - - .status.status-direct { - background: lighten($ui-base-color, 12%); - } - - .detailed-status, - .detailed-status__action-bar { - background: lighten($ui-base-color, 8%); - } - } -} - -.status { - padding: 8px 10px; - position: relative; - height: auto; - min-height: 48px; - border-bottom: 1px solid lighten($ui-base-color, 8%); - cursor: default; - - @supports (-ms-overflow-style: -ms-autohiding-scrollbar) { - // Add margin to avoid Edge auto-hiding scrollbar appearing over content. - // On Edge 16 this is 16px and Edge <=15 it's 12px, so aim for 16px. - padding-right: 26px; // 10px + 16px - } - - @keyframes fade { - 0% { opacity: 0; } - 100% { opacity: 1; } - } - - opacity: 1; - animation: fade 150ms linear; - - .video-player { - margin-top: 8px; - } - - &.status-direct { - background: lighten($ui-base-color, 8%); - - .icon-button.disabled { - color: lighten($ui-base-color, 16%); - } - } - - &.light { - .status__relative-time { - color: $ui-primary-color; - } - - .status__display-name { - color: $ui-base-color; - } - - .display-name { - strong { - color: $ui-base-color; - } - - span { - color: $ui-primary-color; - } - } - - .status__content { - color: $ui-base-color; - - a { - color: $ui-highlight-color; - } - - a.status__content__spoiler-link { - color: $primary-text-color; - background: $ui-primary-color; - - &:hover { - background: lighten($ui-primary-color, 8%); - } - } - } - } - - &.collapsed { - background-position: center; - background-size: cover; - user-select: none; - - &.has-background::before { - display: block; - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - background-image: linear-gradient(to bottom, rgba($base-shadow-color, .75), rgba($base-shadow-color, .65) 24px, rgba($base-shadow-color, .8)); - content: ""; - } - - .display-name:hover .display-name__html { - text-decoration: none; - } - - .status__content { - height: 20px; - overflow: hidden; - text-overflow: ellipsis; - - a:hover { - text-decoration: none; - } - } - } - - .notification__message { - margin: -10px -10px 10px; - } -} - -.notification-favourite { - .status.status-direct { - background: transparent; - - .icon-button.disabled { - color: lighten($ui-base-color, 13%); - } - } -} - -.status__relative-time { - display: inline-block; - margin-left: auto; - padding-left: 18px; - width: 120px; - color: $ui-base-lighter-color; - font-size: 14px; - text-align: right; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.status__display-name { - margin: 0 auto 0 0; - color: $ui-base-lighter-color; - overflow: hidden; -} - -.status__info { - display: flex; - margin: 2px 0 5px; - font-size: 15px; - line-height: 24px; -} - -.status__info__icons { - flex: none; - position: relative; - color: lighten($ui-base-color, 26%); - - .status__visibility-icon { - padding-left: 6px; - } -} - -.status-check-box { - border-bottom: 1px solid $ui-secondary-color; - display: flex; - - .status__content { - flex: 1 1 auto; - padding: 10px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } -} - -.status-check-box-toggle { - align-items: center; - display: flex; - flex: 0 0 auto; - justify-content: center; - padding: 10px; -} - -.status__prepend { - margin: -10px -10px 10px; - color: $ui-base-lighter-color; - padding: 8px 10px 0 68px; - font-size: 14px; - position: relative; - - .status__display-name strong { - color: $ui-base-lighter-color; - } - - > span { - display: block; - overflow: hidden; - text-overflow: ellipsis; - } -} - -.status__action-bar { - align-items: center; - display: flex; - margin: 10px 4px 0; -} - -.status__action-bar-button { - float: left; - margin-right: 18px; - flex: 0 0 auto; -} - -.status__action-bar-dropdown { - float: left; - height: 23.15px; - width: 23.15px; - - // Dropdown style override for centering on the icon - .dropdown--active { - position: relative; - - .dropdown__content.dropdown__right { - left: calc(50% + 3px); - right: initial; - transform: translate(-50%, 0); - top: 22px; - } - - &::after { - right: 1px; - bottom: -2px; - } - } -} - -.detailed-status__action-bar-dropdown { - flex: 1 1 auto; - display: flex; - align-items: center; - justify-content: center; - position: relative; -} - -.detailed-status { - background: lighten($ui-base-color, 4%); - padding: 14px 10px; - - .status__content { - font-size: 19px; - line-height: 24px; - - .emojione { - width: 24px; - height: 24px; - margin: -5px 0 0; - } - } - - .video-player { - margin-top: 8px; - } -} - -.detailed-status__meta { - margin-top: 15px; - color: $ui-base-lighter-color; - font-size: 14px; - line-height: 18px; -} - -.detailed-status__action-bar { - background: lighten($ui-base-color, 4%); - border-top: 1px solid lighten($ui-base-color, 8%); - border-bottom: 1px solid lighten($ui-base-color, 8%); - display: flex; - flex-direction: row; - padding: 10px 0; -} - -.detailed-status__link { - color: inherit; - text-decoration: none; -} - -.detailed-status__favorites, -.detailed-status__reblogs { - display: inline-block; - font-weight: 500; - font-size: 12px; - margin-left: 6px; -} - -.reply-indicator__content { - color: $ui-base-color; - font-size: 14px; - - a { - color: lighten($ui-base-color, 20%); - } -} - -.account { - padding: 10px; - border-bottom: 1px solid lighten($ui-base-color, 8%); - - .account__display-name { - flex: 1 1 auto; - display: block; - color: $ui-primary-color; - overflow: hidden; - text-decoration: none; - font-size: 14px; - } -} - -.account__wrapper { - display: flex; -} - -.account__avatar-wrapper { - float: left; - margin: 6px 16px 6px 6px; -} - -.account__avatar { - @include avatar-radius(); - position: relative; - cursor: pointer; - - &-inline { - display: inline-block; - vertical-align: middle; - margin-right: 5px; - } -} - -.account__avatar-overlay { - position: relative; - @include avatar-size(48px); - - &-base { - @include avatar-radius(); - @include avatar-size(36px); - } - - &-overlay { - @include avatar-radius(); - @include avatar-size(24px); - - position: absolute; - bottom: 0; - right: 0; - z-index: 1; - } -} - -.account__relationship { - height: 18px; - padding: 12px 10px; - white-space: nowrap; -} - -.account__header__wrapper { - flex: 0 0 auto; - background: lighten($ui-base-color, 4%); -} - -.account__header { - text-align: center; - background-size: cover; - background-position: center; - position: relative; - - & > div { - background: rgba(lighten($ui-base-color, 4%), 0.9); - padding: 20px 10px; - } - - .account__header__content { - color: $ui-secondary-color; - } - - .account__header__display-name { - color: $primary-text-color; - display: inline-block; - width: 100%; - font-size: 20px; - line-height: 27px; - font-weight: 500; - overflow: hidden; - text-overflow: ellipsis; - } - - .account__header__username { - color: $ui-highlight-color; - font-size: 14px; - font-weight: 400; - display: block; - margin-bottom: 10px; - overflow: hidden; - text-overflow: ellipsis; - } -} - -.account__disclaimer { - padding: 10px; - border-top: 1px solid lighten($ui-base-color, 8%); - color: $ui-base-lighter-color; - - strong { - font-weight: 500; - } - - a { - font-weight: 500; - color: inherit; - text-decoration: underline; - - &:hover, - &:focus, - &:active { - text-decoration: none; - } - } -} - -.account__header__content { - color: $ui-primary-color; - font-size: 14px; - font-weight: 400; - overflow: hidden; - word-break: normal; - word-wrap: break-word; - - p { - margin-bottom: 20px; - - &:last-child { - margin-bottom: 0; - } - } - - a { - color: inherit; - text-decoration: underline; - - &:hover { - text-decoration: none; - } - } -} - -.account__header__display-name { - .emojione { - width: 25px; - height: 25px; - } -} - -.account__metadata { - width: 100%; - font-size: 15px; - line-height: 20px; - overflow: hidden; - border-collapse: collapse; - - a { - text-decoration: none; - - &:hover{ - text-decoration: underline; - } - } - - tr { - border-top: 1px solid lighten($ui-base-color, 8%); - } - - th, td { - padding: 14px 20px; - vertical-align: middle; - - & > div { - max-height: 40px; - overflow-y: auto; - white-space: pre-wrap; - text-overflow: ellipsis; - } - } - - th { - color: $ui-primary-color; - background: lighten($ui-base-color, 13%); - font-variant: small-caps; - max-width: 120px; - - a { - color: $primary-text-color; - } - } - - td { - flex: auto; - color: $primary-text-color; - background: $ui-base-color; - - a { - color: $ui-highlight-color; - } - } -} - -.account__action-bar { - border-top: 1px solid lighten($ui-base-color, 8%); - border-bottom: 1px solid lighten($ui-base-color, 8%); - line-height: 36px; - overflow: hidden; - flex: 0 0 auto; - display: flex; -} - -.account__action-bar-dropdown { - flex: 0 1 calc(50% - 140px); - padding: 10px; - - .dropdown--active { - .dropdown__content.dropdown__right { - left: 6px; - right: initial; - } - - &::after { - bottom: initial; - margin-left: 11px; - margin-top: -7px; - right: initial; - } - } -} - -.account__action-bar-links { - display: flex; - flex: 1 1 auto; - line-height: 18px; -} - -.account__action-bar__tab { - text-decoration: none; - overflow: hidden; - flex: 0 1 80px; - border-left: 1px solid lighten($ui-base-color, 8%); - padding: 10px 5px; - - & > span { - display: block; - text-transform: uppercase; - font-size: 11px; - color: $ui-primary-color; - } - - strong { - display: block; - font-size: 15px; - font-weight: 500; - color: $primary-text-color; - } - - abbr { - color: $ui-base-lighter-color; - } -} - -.account__header__avatar { - @include avatar-radius(); - @include avatar-size(90px); - display: block; - margin: 0 auto 10px; - overflow: hidden; -} - -.account-authorize { - padding: 14px 10px; - - .detailed-status__display-name { - display: block; - margin-bottom: 15px; - overflow: hidden; - } -} - -.account-authorize__avatar { - float: left; - margin-right: 10px; -} - -.status__display-name, -.status__relative-time, -.detailed-status__display-name, -.detailed-status__datetime, -.detailed-status__application, -.account__display-name { - text-decoration: none; -} - -.status__display-name, -.account__display-name { - strong { - color: $primary-text-color; - } -} - -.muted { - .emojione { - opacity: 0.5; - } -} - -.account__display-name strong { - display: block; - overflow: hidden; - text-overflow: ellipsis; -} - -.detailed-status__application, -.detailed-status__datetime { - color: inherit; -} - -.detailed-status__display-name { - color: $ui-secondary-color; - display: block; - line-height: 24px; - margin-bottom: 15px; - overflow: hidden; - - strong, - span { - display: block; - text-overflow: ellipsis; - overflow: hidden; - } - - strong { - font-size: 16px; - color: $primary-text-color; - } -} - -.detailed-status__display-avatar { - float: left; - margin-right: 10px; -} - -.status__avatar { - flex: none; - margin: 0 10px 0 0; - height: 48px; - width: 48px; -} - -.muted { - .status__content p, - .status__content a { - color: $ui-base-lighter-color; - } - - .status__display-name strong { - color: $ui-base-lighter-color; - } - - .status__avatar, .emojione { - opacity: 0.5; - } - - a.status__content__spoiler-link { - background: $ui-base-lighter-color; - color: lighten($ui-base-color, 4%); - - &:hover { - background: lighten($ui-base-color, 29%); - text-decoration: none; - } - } -} - -.notification__message { - padding: 8px 10px 0 68px; - cursor: default; - color: $ui-primary-color; - font-size: 15px; - position: relative; - - .fa { - color: $ui-highlight-color; - } - - > span { - display: block; - overflow: hidden; - text-overflow: ellipsis; - } -} - -.notification__favourite-icon-wrapper { - float: left; - margin: 0 10px 0 -58px; - width: 48px; - text-align: right; - - .star-icon { - color: $gold-star; - } -} - -.star-icon.active { - color: $gold-star; -} - -.notification__display-name { - color: inherit; - font-weight: 500; - text-decoration: none; - - &:hover { - color: $primary-text-color; - text-decoration: underline; - } -} - -.display-name { - display: block; - padding: 6px 0; - max-width: 100%; - height: 36px; - overflow: hidden; - - strong { - display: block; - height: 18px; - font-size: 16px; - font-weight: 500; - line-height: 18px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - - span { - display: block; - height: 18px; - font-size: 15px; - line-height: 18px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - - &:hover { - strong { - text-decoration: underline; - } - } -} - -.status__relative-time, -.detailed-status__datetime { - &:hover { - text-decoration: underline; - } -} - -.image-loader { - position: relative; - - &.image-loader--loading { - .image-loader__preview-canvas { - filter: blur(2px); - } - } - - .image-loader__img { - position: absolute; - top: 0; - left: 0; - right: 0; - max-width: 100%; - max-height: 100%; - background-image: none; - } - - &.image-loader--amorphous { - position: static; - - .image-loader__preview-canvas { - display: none; - } - - .image-loader__img { - position: static; - width: auto; - height: auto; - } - } -} - -.navigation-bar { - padding: 10px; - display: flex; - flex-shrink: 0; - cursor: default; - color: $ui-primary-color; - - strong { - color: $primary-text-color; - } - - .permalink { - text-decoration: none; - } - - .icon-button { - pointer-events: none; - opacity: 0; - } -} - -.navigation-bar__profile { - flex: 1 1 auto; - margin-left: 8px; - overflow: hidden; -} - -.navigation-bar__profile-account { - display: block; - font-weight: 500; - overflow: hidden; - text-overflow: ellipsis; -} - -.navigation-bar__profile-edit { - color: inherit; - text-decoration: none; -} - -.dropdown { - display: inline-block; -} - -.dropdown__content { - display: none; - position: absolute; -} - -.dropdown-menu__separator { - border-bottom: 1px solid darken($ui-secondary-color, 8%); - margin: 5px 7px 6px; - height: 0; -} - -.dropdown-menu { - background: $ui-secondary-color; - padding: 4px 0; - border-radius: 4px; - box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); - - ul { - list-style: none; - } -} - -.dropdown-menu__arrow { - position: absolute; - width: 0; - height: 0; - border: 0 solid transparent; - - &.left { - right: -5px; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: $ui-secondary-color; - } - - &.top { - bottom: -5px; - margin-left: -13px; - border-width: 5px 7px 0; - border-top-color: $ui-secondary-color; - } - - &.bottom { - top: -5px; - margin-left: -13px; - border-width: 0 7px 5px; - border-bottom-color: $ui-secondary-color; - } - - &.right { - left: -5px; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: $ui-secondary-color; - } -} - -.dropdown-menu__item { - a { - font-size: 13px; - line-height: 18px; - display: block; - padding: 4px 14px; - box-sizing: border-box; - text-decoration: none; - background: $ui-secondary-color; - color: $ui-base-color; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - &:focus, - &:hover, - &:active { - background: $ui-highlight-color; - color: $ui-secondary-color; - outline: 0; - } - } -} - -.dropdown--active .dropdown__content { - display: block; - line-height: 18px; - max-width: 311px; - right: 0; - text-align: left; - z-index: 9999; - - & > ul { - list-style: none; - background: $ui-secondary-color; - padding: 4px 0; - border-radius: 4px; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.4); - min-width: 140px; - position: relative; - } - - &.dropdown__right { - right: 0; - } - - &.dropdown__left { - & > ul { - left: -98px; - } - } - - & > ul > li > a { - font-size: 13px; - line-height: 18px; - display: block; - padding: 4px 14px; - box-sizing: border-box; - text-decoration: none; - background: $ui-secondary-color; - color: $ui-base-color; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - &:focus { - outline: 0; - } - - &:hover { - background: $ui-highlight-color; - color: $ui-secondary-color; - } - } -} - -.dropdown__icon { - vertical-align: middle; -} - -.static-content { - padding: 10px; - padding-top: 20px; - color: $ui-base-lighter-color; - - h1 { - font-size: 16px; - font-weight: 500; - margin-bottom: 40px; - text-align: center; - } - - p { - font-size: 13px; - margin-bottom: 20px; - } -} - -.columns-area { - display: flex; - flex: 1 1 auto; - flex-direction: row; - justify-content: flex-start; - overflow-x: auto; - position: relative; - padding: 10px; -} - -@include limited-single-column('screen and (max-width: 360px)', $parent: null) { - .columns-area { - padding: 0; - } - - .react-swipeable-view-container .columns-area { - height: calc(100% - 20px) !important; - } -} - -.react-swipeable-view-container { - &, - .columns-area, - .drawer, - .column { - height: 100%; - } -} - -.react-swipeable-view-container > * { - display: flex; - align-items: center; - justify-content: center; - height: 100%; -} - -.column { - width: 330px; - position: relative; - box-sizing: border-box; - display: flex; - flex-direction: column; - overflow: hidden; - - .wide & { - flex: auto; - min-width: 330px; - max-width: 400px; - } - - > .scrollable { - background: $ui-base-color; - } -} - -.ui { - flex: 0 0 auto; - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - background: darken($ui-base-color, 7%); -} - -.drawer { - width: 300px; - box-sizing: border-box; - display: flex; - flex-direction: column; - overflow-y: auto; - - .wide & { - flex: 1 1 200px; - min-width: 300px; - max-width: 400px; - } -} - -.drawer__tab { - display: block; - flex: 1 1 auto; - padding: 15px 5px 13px; - color: $ui-primary-color; - text-decoration: none; - text-align: center; - font-size: 16px; - border-bottom: 2px solid transparent; - outline: none; - cursor: pointer; -} - -.column, -.drawer { - flex: 1 1 100%; - overflow: hidden; -} - -@include limited-single-column('screen and (max-width: 360px)', $parent: null) { - .tabs-bar { - margin: 0; - } - - .search { - margin-bottom: 0; - } -} - -:root { // Overrides .wide stylings for mobile view - @include single-column('screen and (max-width: 630px)', $parent: null) { - .column, - .drawer { - flex: auto; - width: 100%; - min-width: 0; - max-width: none; - padding: 0; - } - - .columns-area { - flex-direction: column; - } - - .search__input, - .autosuggest-textarea__textarea { - font-size: 16px; - } - } -} - -@include multi-columns('screen and (min-width: 631px)', $parent: null) { - .columns-area { - padding: 0; - } - - .column, - .drawer { - padding: 10px; - padding-left: 5px; - padding-right: 5px; - - &:first-child { - padding-left: 10px; - } - - &:last-child { - padding-right: 10px; - } - } - - .columns-area > div { - .column, - .drawer { - padding-left: 5px; - padding-right: 5px; - } - } -} - -.drawer__pager { - box-sizing: border-box; - padding: 0; - flex: 1 1 auto; - position: relative; -} - -.drawer__inner { - background: lighten($ui-base-color, 13%); - box-sizing: border-box; - padding: 0; - position: absolute; - height: 100%; - width: 100%; - - &.darker { - position: absolute; - top: 0; - left: 0; - background: $ui-base-color; - width: 100%; - height: 100%; - } -} - -.pseudo-drawer { - background: lighten($ui-base-color, 13%); - font-size: 13px; - text-align: left; -} - -.drawer__header { - flex: 0 0 auto; - font-size: 16px; - background: lighten($ui-base-color, 8%); - margin-bottom: 10px; - display: flex; - flex-direction: row; - - a { - transition: background 100ms ease-in; - - &:hover { - background: lighten($ui-base-color, 3%); - transition: background 200ms ease-out; - } - } -} - -.tabs-bar { - display: flex; - background: lighten($ui-base-color, 8%); - flex: 0 0 auto; - overflow-y: auto; - margin: 10px; - margin-bottom: 0; -} - -.tabs-bar__link { - display: block; - flex: 1 1 auto; - padding: 15px 10px; - color: $primary-text-color; - text-decoration: none; - text-align: center; - font-size: 14px; - font-weight: 500; - border-bottom: 2px solid lighten($ui-base-color, 8%); - transition: all 200ms linear; - - .fa { - font-weight: 400; - font-size: 16px; - } - - &.active { - border-bottom: 2px solid $ui-highlight-color; - color: $ui-highlight-color; - } - - &:hover, - &:focus, - &:active { - @include multi-columns('screen and (min-width: 631px)') { - background: lighten($ui-base-color, 14%); - transition: all 100ms linear; - } - } - - span { - margin-left: 5px; - display: none; - } -} - -@include limited-single-column('screen and (max-width: 600px)', $parent: null) { - .tabs-bar__link { - span { - display: inline; - } - } -} - -@include multi-columns('screen and (min-width: 631px)', $parent: null) { - .tabs-bar { - display: none; - } -} - -.scrollable { - overflow-y: scroll; - overflow-x: hidden; - flex: 1 1 auto; - -webkit-overflow-scrolling: touch; - will-change: transform; // improves perf in mobile Chrome - - &.optionally-scrollable { - overflow-y: auto; - } - - @supports(display: grid) { // hack to fix Chrome <57 - contain: strict; - } -} - -.scrollable.fullscreen { - @supports(display: grid) { // hack to fix Chrome <57 - contain: none; - } -} - -.column-back-button { - background: lighten($ui-base-color, 4%); - color: $ui-highlight-color; - cursor: pointer; - flex: 0 0 auto; - font-size: 16px; - border: 0; - text-align: unset; - padding: 15px; - margin: 0; - z-index: 3; - - &:hover { - text-decoration: underline; - } -} - -.column-header__back-button { - background: lighten($ui-base-color, 4%); - border: 0; - font-family: inherit; - color: $ui-highlight-color; - cursor: pointer; - flex: 0 0 auto; - font-size: 16px; - padding: 0 5px 0 0; - z-index: 3; - - &:hover { - text-decoration: underline; - } - - &:last-child { - padding: 0 15px 0 0; - } -} - -.column-back-button__icon { - display: inline-block; - margin-right: 5px; -} - -.column-back-button--slim { - position: relative; -} - -.column-back-button--slim-button { - cursor: pointer; - flex: 0 0 auto; - font-size: 16px; - padding: 15px; - position: absolute; - right: 0; - top: -48px; -} - -.react-toggle { - display: inline-block; - position: relative; - cursor: pointer; - background-color: transparent; - border: 0; - padding: 0; - user-select: none; - -webkit-tap-highlight-color: rgba($base-overlay-background, 0); - -webkit-tap-highlight-color: transparent; -} - -.react-toggle-screenreader-only { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; -} - -.react-toggle--disabled { - cursor: not-allowed; - opacity: 0.5; - transition: opacity 0.25s; -} - -.react-toggle-track { - width: 50px; - height: 24px; - padding: 0; - border-radius: 30px; - background-color: $ui-base-color; - transition: all 0.2s ease; -} - -.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track { - background-color: darken($ui-base-color, 10%); -} - -.react-toggle--checked .react-toggle-track { - background-color: $ui-highlight-color; -} - -.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track { - background-color: lighten($ui-highlight-color, 10%); -} - -.react-toggle-track-check { - position: absolute; - width: 14px; - height: 10px; - top: 0; - bottom: 0; - margin-top: auto; - margin-bottom: auto; - line-height: 0; - left: 8px; - opacity: 0; - transition: opacity 0.25s ease; -} - -.react-toggle--checked .react-toggle-track-check { - opacity: 1; - transition: opacity 0.25s ease; -} - -.react-toggle-track-x { - position: absolute; - width: 10px; - height: 10px; - top: 0; - bottom: 0; - margin-top: auto; - margin-bottom: auto; - line-height: 0; - right: 10px; - opacity: 1; - transition: opacity 0.25s ease; -} - -.react-toggle--checked .react-toggle-track-x { - opacity: 0; -} - -.react-toggle-thumb { - transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms; - position: absolute; - top: 1px; - left: 1px; - width: 22px; - height: 22px; - border: 1px solid $ui-base-color; - border-radius: 50%; - background-color: darken($simple-background-color, 2%); - box-sizing: border-box; - transition: all 0.25s ease; -} - -.react-toggle--checked .react-toggle-thumb { - left: 27px; - border-color: $ui-highlight-color; -} - -.column-link { - background: lighten($ui-base-color, 8%); - color: $primary-text-color; - display: block; - font-size: 16px; - padding: 15px; - text-decoration: none; - cursor: pointer; - outline: none; - - &:hover { - background: lighten($ui-base-color, 11%); - } -} - -.column-link__icon { - display: inline-block; - margin-right: 5px; -} - -.column-subheading { - background: $ui-base-color; - color: $ui-base-lighter-color; - padding: 8px 20px; - font-size: 12px; - font-weight: 500; - text-transform: uppercase; - cursor: default; -} - -.autosuggest-textarea, -.spoiler-input { - position: relative; -} - -.autosuggest-textarea__textarea, -.spoiler-input__input { - display: block; - box-sizing: border-box; - width: 100%; - margin: 0; - color: $ui-base-color; - background: $simple-background-color; - padding: 10px; - font-family: inherit; - font-size: 14px; - resize: vertical; - border: 0; - outline: 0; - - &:focus { - outline: 0; - } - - @include limited-single-column('screen and (max-width: 600px)') { - font-size: 16px; - } -} - -.spoiler-input__input { - border-radius: 4px; -} - -.autosuggest-textarea__textarea { - min-height: 100px; - border-radius: 4px 4px 0 0; - padding-bottom: 0; - padding-right: 10px + 22px; - resize: none; - - @include limited-single-column('screen and (max-width: 600px)') { - height: 100px !important; // prevent auto-resize textarea - resize: vertical; - } -} - -.autosuggest-textarea__suggestions { - box-sizing: border-box; - display: none; - position: absolute; - top: 100%; - width: 100%; - z-index: 99; - box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4); - background: $ui-secondary-color; - border-radius: 0 0 4px 4px; - color: $ui-base-color; - font-size: 14px; - padding: 6px; - - &.autosuggest-textarea__suggestions--visible { - display: block; - } -} - -.autosuggest-textarea__suggestions__item { - padding: 10px; - cursor: pointer; - border-radius: 4px; - - &:hover, - &:focus, - &:active, - &.selected { - background: darken($ui-secondary-color, 10%); - } -} - -.autosuggest-account, -.autosuggest-emoji { - display: flex; - flex-direction: row; - align-items: center; - justify-content: flex-start; - line-height: 18px; - font-size: 14px; -} - -.autosuggest-account-icon, -.autosuggest-emoji img { - display: block; - margin-right: 8px; - width: 16px; - height: 16px; -} - -.autosuggest-account .display-name__account { - color: lighten($ui-base-color, 36%); -} - -.character-counter__wrapper { - line-height: 36px; - margin: 0 16px 0 8px; - padding-top: 10px; -} - -.character-counter { - cursor: default; - font-size: 16px; -} - -.character-counter--over { - color: $warning-red; -} - -.getting-started__wrapper { - position: relative; - overflow-y: auto; -} - -.getting-started__footer { - display: flex; - flex-direction: column; -} - -.getting-started { - box-sizing: border-box; - padding-bottom: 235px; - background: url('../images/mastodon-getting-started.png') no-repeat 0 100%; - flex: 1 0 auto; - - p { - color: $ui-secondary-color; - } - - a { - color: $ui-base-lighter-color; - } -} - -.setting-text { - color: $ui-primary-color; - background: transparent; - border: none; - border-bottom: 2px solid $ui-primary-color; - box-sizing: border-box; - display: block; - font-family: inherit; - margin-bottom: 10px; - padding: 7px 0; - width: 100%; - - &:focus, - &:active { - color: $primary-text-color; - border-bottom-color: $ui-highlight-color; - } - - @include limited-single-column('screen and (max-width: 600px)') { - font-size: 16px; - } - - &.light { - color: $ui-base-color; - border-bottom: 2px solid lighten($ui-base-color, 27%); - - &:focus, - &:active { - color: $ui-base-color; - border-bottom-color: $ui-highlight-color; - } - } -} - -@import 'boost'; - -button.icon-button i.fa-retweet { - background-position: 0 0; - height: 19px; - transition: background-position 0.9s steps(10); - transition-duration: 0s; - vertical-align: middle; - width: 22px; - - &::before { - display: none !important; - } -} - -button.icon-button.active i.fa-retweet { - transition-duration: 0.9s; - background-position: 0 100%; -} - -.status-card { - display: flex; - cursor: pointer; - font-size: 14px; - border: 1px solid lighten($ui-base-color, 8%); - border-radius: 4px; - color: $ui-base-lighter-color; - margin-top: 14px; - text-decoration: none; - overflow: hidden; - - &:hover { - background: lighten($ui-base-color, 8%); - } -} - -.status-card-video, -.status-card-rich, -.status-card-photo { - margin-top: 14px; - overflow: hidden; - - iframe { - width: 100%; - height: auto; - } -} - -.status-card-photo { - display: block; - text-decoration: none; - - img { - display: block; - width: 100%; - height: auto; - margin: 0; - } -} - -.status-card-video { - iframe { - width: 100%; - height: 100%; - } -} - -.status-card__title { - display: block; - font-weight: 500; - margin-bottom: 5px; - color: $ui-primary-color; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.status-card__content { - flex: 1 1 auto; - overflow: hidden; - padding: 14px 14px 14px 8px; -} - -.status-card__description { - color: $ui-primary-color; -} - -.status-card__host { - display: block; - margin-top: 5px; - font-size: 13px; -} - -.status-card__image { - flex: 0 0 100px; - background: lighten($ui-base-color, 8%); -} - -.status-card.horizontal { - display: block; - - .status-card__image { - width: 100%; - } - - .status-card__image-image { - border-radius: 4px 4px 0 0; - } -} - -.status-card__image-image { - border-radius: 4px 0 0 4px; - display: block; - height: auto; - margin: 0; - width: 100%; -} - -.load-more { - display: block; - color: $ui-base-lighter-color; - background-color: transparent; - border: 0; - font-size: inherit; - text-align: center; - line-height: inherit; - margin: 0; - padding: 15px; - width: 100%; - clear: both; - - &:hover { - background: lighten($ui-base-color, 2%); - } -} - -.missing-indicator { - text-align: center; - font-size: 16px; - font-weight: 500; - color: lighten($ui-base-color, 16%); - background: $ui-base-color; - cursor: default; - display: flex; - flex: 1 1 auto; - align-items: center; - justify-content: center; - - & > div { - background: url('../images/mastodon-not-found.png') no-repeat center -50px; - padding-top: 210px; - width: 100%; - } -} - -.column-header__wrapper { - position: relative; - flex: 0 0 auto; - - &.active { - &::before { - display: block; - content: ""; - position: absolute; - top: 35px; - left: 0; - right: 0; - margin: 0 auto; - width: 60%; - pointer-events: none; - height: 28px; - z-index: 1; - background: radial-gradient(ellipse, rgba($ui-highlight-color, 0.23) 0%, rgba($ui-highlight-color, 0) 60%); - } - } -} - -.column-header { - display: flex; - padding: 15px; - font-size: 16px; - background: lighten($ui-base-color, 4%); - flex: 0 0 auto; - cursor: pointer; - position: relative; - z-index: 2; - outline: 0; - - &.active { - box-shadow: 0 1px 0 rgba($ui-highlight-color, 0.3); - - .column-header__icon { - color: $ui-highlight-color; - text-shadow: 0 0 10px rgba($ui-highlight-color, 0.4); - } - } - - &:focus, - &:active { - outline: 0; - } -} - -.column-header__buttons { - height: 48px; - display: flex; - margin: -15px; - margin-left: 0; -} - -.column-header__button { - background: lighten($ui-base-color, 4%); - border: 0; - color: $ui-primary-color; - cursor: pointer; - font-size: 16px; - padding: 0 15px; - - &:hover { - color: lighten($ui-primary-color, 7%); - } - - &.active { - color: $primary-text-color; - background: lighten($ui-base-color, 8%); - - &:hover { - color: $primary-text-color; - background: lighten($ui-base-color, 8%); - } - } - - // glitch - added focus ring for keyboard navigation - &:focus { - text-shadow: 0 0 4px darken($ui-highlight-color, 5%); - } -} - -.scrollable > div > :first-child .notification__dismiss-overlay > .wrappy { - border-top: 1px solid $ui-base-color; -} - -.notification__dismiss-overlay { - overflow: hidden; - position: absolute; - top: 0; - right: 0; - bottom: -1px; - padding-left: 15px; // space for the box shadow to be visible - - z-index: 999; - align-items: center; - justify-content: flex-end; - cursor: pointer; - - display: flex; - - .wrappy { - width: $dismiss-overlay-width; - align-self: stretch; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - background: lighten($ui-base-color, 8%); - border-left: 1px solid lighten($ui-base-color, 20%); - box-shadow: 0 0 5px black; - border-bottom: 1px solid $ui-base-color; - } - - .ckbox { - border: 2px solid $ui-primary-color; - border-radius: 2px; - width: 30px; - height: 30px; - font-size: 20px; - color: $ui-primary-color; - text-shadow: 0 0 5px black; - display: flex; - justify-content: center; - align-items: center; - } - - &:focus { - outline: 0 !important; - - .ckbox { - box-shadow: 0 0 1px 1px $ui-highlight-color; - } - } -} - -.column-header__notif-cleaning-buttons { - display: flex; - align-items: stretch; - justify-content: space-around; - - button { - @extend .column-header__button; - background: transparent; - text-align: center; - padding: 10px 0; - white-space: pre-wrap; - } - - b { - font-weight: bold; - } -} - -// The notifs drawer with no padding to have more space for the buttons -.column-header__collapsible-inner.nopad-drawer { - padding: 0; -} - -.column-header__collapsible { - max-height: 70vh; - overflow: hidden; - overflow-y: auto; - color: $ui-primary-color; - transition: max-height 150ms ease-in-out, opacity 300ms linear; - opacity: 1; - - &.collapsed { - max-height: 0; - opacity: 0.5; - } - - &.animating { - overflow-y: hidden; - } - - // notif cleaning drawer - &.ncd { - transition: none; - &.collapsed { - max-height: 0; - opacity: 0.7; - } - } -} - -.column-header__collapsible-inner { - background: lighten($ui-base-color, 8%); - padding: 15px; -} - -.column-header__setting-btn { - &:hover { - color: lighten($ui-primary-color, 4%); - text-decoration: underline; - } -} - -.column-header__setting-arrows { - float: right; - - .column-header__setting-btn { - padding: 0 10px; - - &:last-child { - padding-right: 0; - } - } -} - -.column-header__title { - display: inline-block; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - flex: 1; -} - -.text-btn { - display: inline-block; - padding: 0; - font-family: inherit; - font-size: inherit; - color: inherit; - border: 0; - background: transparent; - cursor: pointer; -} - -.column-header__icon { - display: inline-block; - margin-right: 5px; -} - -.loading-indicator { - color: lighten($ui-base-color, 26%); - font-size: 12px; - font-weight: 400; - text-transform: uppercase; - overflow: visible; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - - span { - display: block; - float: left; - margin-left: 50%; - transform: translateX(-50%); - margin: 82px 0 0 50%; - white-space: nowrap; - animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000); - } -} - -.loading-indicator__figure { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 0; - height: 0; - box-sizing: border-box; - border: 0 solid lighten($ui-base-color, 26%); - border-radius: 50%; - animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000); -} - -@keyframes loader-figure { - 0% { - width: 0; - height: 0; - background-color: lighten($ui-base-color, 26%); - } - - 29% { - background-color: lighten($ui-base-color, 26%); - } - - 30% { - width: 42px; - height: 42px; - background-color: transparent; - border-width: 21px; - opacity: 1; - } - - 100% { - width: 42px; - height: 42px; - border-width: 0; - opacity: 0; - background-color: transparent; - } -} - -@keyframes loader-label { - 0% { opacity: 0.25; } - 30% { opacity: 1; } - 100% { opacity: 0.25; } -} - -.video-error-cover { - align-items: center; - background: $base-overlay-background; - color: $primary-text-color; - cursor: pointer; - display: flex; - flex-direction: column; - height: 100%; - justify-content: center; - margin-top: 8px; - position: relative; - text-align: center; - z-index: 100; -} - -.media-spoiler { - background: $base-overlay-background; - color: $ui-primary-color; - border: 0; - width: 100%; - height: 100%; - justify-content: center; - position: relative; - text-align: center; - z-index: 100; - display: flex; - flex-direction: column; - - .status__content > & { - margin-top: 15px; // Add margin when used bare for NSFW video player - } - - @include fullwidth-gallery; -} - -.media-spoiler__warning { - display: block; - font-size: 14px; -} - -.media-spoiler__trigger { - display: block; - font-size: 11px; - font-weight: 500; -} - -.spoiler-button { - display: none; - left: 4px; - position: absolute; - text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color; - top: 4px; - z-index: 100; - - &.spoiler-button--visible { - display: block; - } -} - -.modal-container--preloader { - background: lighten($ui-base-color, 8%); -} - -.account--panel { - background: lighten($ui-base-color, 4%); - border-top: 1px solid lighten($ui-base-color, 8%); - border-bottom: 1px solid lighten($ui-base-color, 8%); - display: flex; - flex-direction: row; - padding: 10px 0; -} - -.account--panel__button, -.detailed-status__button { - flex: 1 1 auto; - text-align: center; -} - -.column-settings__outer { - background: lighten($ui-base-color, 8%); - padding: 15px; -} - -.column-settings__section { - color: $ui-primary-color; - cursor: default; - display: block; - font-weight: 500; - margin-bottom: 10px; -} - -.column-settings__row { - .text-btn { - margin-bottom: 15px; - } -} - -.modal-container__nav { - align-items: center; - background: rgba($base-overlay-background, 0.5); - box-sizing: border-box; - border: 0; - color: $primary-text-color; - cursor: pointer; - display: flex; - font-size: 24px; - height: 100%; - padding: 30px 15px; - position: absolute; - top: 0; -} - -.modal-container__nav--left { - left: -61px; -} - -.modal-container__nav--right { - right: -61px; -} - -.account--follows-info { - color: $primary-text-color; - position: absolute; - top: 10px; - left: 10px; - opacity: 0.7; - display: inline-block; - vertical-align: top; - background-color: rgba($base-overlay-background, 0.4); - text-transform: uppercase; - font-size: 11px; - font-weight: 500; - padding: 4px; - border-radius: 4px; -} - -.account--action-button { - position: absolute; - top: 10px; - right: 20px; -} - -.setting-toggle { - display: block; - line-height: 24px; -} - -.setting-toggle__label, -.setting-meta__label { - color: $ui-primary-color; - display: inline-block; - margin-bottom: 14px; - margin-left: 8px; - vertical-align: middle; -} - -.setting-meta__label { - color: $ui-primary-color; - float: right; -} - -.empty-column-indicator, -.error-column { - color: lighten($ui-base-color, 20%); - background: $ui-base-color; - text-align: center; - padding: 20px; - font-size: 15px; - font-weight: 400; - cursor: default; - display: flex; - flex: 1 1 auto; - align-items: center; - justify-content: center; - @supports(display: grid) { // hack to fix Chrome <57 - contain: strict; - } - - a { - color: $ui-highlight-color; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } -} - -.error-column { - flex-direction: column; -} - -@keyframes heartbeat { - from { - transform: scale(1); - transform-origin: center center; - animation-timing-function: ease-out; - } - - 10% { - transform: scale(0.91); - animation-timing-function: ease-in; - } - - 17% { - transform: scale(0.98); - animation-timing-function: ease-out; - } - - 33% { - transform: scale(0.87); - animation-timing-function: ease-in; - } - - 45% { - transform: scale(1); - animation-timing-function: ease-out; - } -} - -.pulse-loading { - animation: heartbeat 1.5s ease-in-out infinite both; -} - -.emoji-picker-dropdown__menu { - background: $simple-background-color; - position: absolute; - box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4); - border-radius: 4px; - margin-top: 5px; - - .emoji-mart-scroll { - transition: opacity 200ms ease; - } - - &.selecting .emoji-mart-scroll { - opacity: 0.5; - } -} - -.emoji-picker-dropdown__modifiers { - position: absolute; - top: 60px; - right: 11px; - cursor: pointer; -} - -.emoji-picker-dropdown__modifiers__menu { - position: absolute; - z-index: 4; - top: -4px; - left: -8px; - background: $simple-background-color; - border-radius: 4px; - box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2); - overflow: hidden; - - button { - display: block; - cursor: pointer; - border: 0; - padding: 4px 8px; - background: transparent; - - &:hover, - &:focus, - &:active { - background: rgba($ui-secondary-color, 0.4); - } - } - - .emoji-mart-emoji { - height: 22px; - } -} - -.emoji-mart-emoji { - span { - background-repeat: no-repeat; - } -} - -.upload-area { - align-items: center; - background: rgba($base-overlay-background, 0.8); - display: flex; - height: 100%; - justify-content: center; - left: 0; - opacity: 0; - position: absolute; - top: 0; - visibility: hidden; - width: 100%; - z-index: 2000; - - * { - pointer-events: none; - } -} - -.upload-area__drop { - width: 320px; - height: 160px; - display: flex; - box-sizing: border-box; - position: relative; - padding: 8px; -} - -.upload-area__background { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: -1; - border-radius: 4px; - background: $ui-base-color; - box-shadow: 0 0 5px rgba($base-shadow-color, 0.2); -} - -.upload-area__content { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - color: $ui-secondary-color; - font-size: 18px; - font-weight: 500; - border: 2px dashed $ui-base-lighter-color; - border-radius: 4px; -} - -.upload-progress { - padding: 10px; - color: $ui-base-lighter-color; - overflow: hidden; - display: flex; - - .fa { - font-size: 34px; - margin-right: 10px; - } - - span { - font-size: 12px; - text-transform: uppercase; - font-weight: 500; - display: block; - } -} - -.upload-progess__message { - flex: 1 1 auto; -} - -.upload-progress__backdrop { - width: 100%; - height: 6px; - border-radius: 6px; - background: $ui-base-lighter-color; - position: relative; - margin-top: 5px; -} - -.upload-progress__tracker { - position: absolute; - left: 0; - top: 0; - height: 6px; - background: $ui-highlight-color; - border-radius: 6px; -} - -.emoji-button { - display: block; - font-size: 24px; - line-height: 24px; - margin-left: 2px; - width: 24px; - outline: 0; - cursor: pointer; - - &:active, - &:focus { - outline: 0 !important; - } - - img { - filter: grayscale(100%); - opacity: 0.8; - display: block; - margin: 0; - width: 22px; - height: 22px; - margin-top: 2px; - } - - &:hover, - &:active, - &:focus { - img { - opacity: 1; - filter: none; - } - } -} - -.dropdown--active .emoji-button img { - opacity: 1; - filter: none; -} - -.privacy-dropdown__dropdown { - position: absolute; - background: $simple-background-color; - box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); - border-radius: 4px; - margin-left: 40px; - overflow: hidden; -} - -.privacy-dropdown__option { - color: $ui-base-color; - padding: 10px; - cursor: pointer; - display: flex; - - &:hover, - &.active { - background: $ui-highlight-color; - color: $primary-text-color; - - .privacy-dropdown__option__content { - color: $primary-text-color; - - strong { - color: $primary-text-color; - } - } - } - - &.active:hover { - background: lighten($ui-highlight-color, 4%); - } -} - -.privacy-dropdown__option__icon { - display: flex; - align-items: center; - justify-content: center; - margin-right: 10px; -} - -.privacy-dropdown__option__content { - flex: 1 1 auto; - color: darken($ui-primary-color, 24%); - - strong { - font-weight: 500; - display: block; - color: $ui-base-color; - } -} - -.privacy-dropdown.active { - .privacy-dropdown__value { - background: $simple-background-color; - border-radius: 4px 4px 0 0; - box-shadow: 0 -4px 4px rgba($base-shadow-color, 0.1); - - .icon-button { - transition: none; - } - - &.active { - background: $ui-highlight-color; - - .icon-button { - color: $primary-text-color; - } - } - } - - .privacy-dropdown__dropdown { - display: block; - box-shadow: 2px 4px 6px rgba($base-shadow-color, 0.1); - } -} - -.advanced-options-dropdown { - position: relative; -} - -.advanced-options-dropdown__dropdown { - display: none; - position: absolute; - left: 0; - top: 27px; - width: 210px; - background: $simple-background-color; - border-radius: 0 4px 4px; - z-index: 2; - overflow: hidden; -} - -.advanced-options-dropdown__option { - color: $ui-base-color; - padding: 10px; - cursor: pointer; - display: flex; - - &:hover, - &.active { - background: $ui-highlight-color; - color: $primary-text-color; - - .advanced-options-dropdown__option__content { - color: $primary-text-color; - - strong { - color: $primary-text-color; - } - } - } - - &.active:hover { - background: lighten($ui-highlight-color, 4%); - } -} - -.advanced-options-dropdown__option__toggle { - display: flex; - align-items: center; - justify-content: center; - margin-right: 10px; -} - -.advanced-options-dropdown__option__content { - flex: 1 1 auto; - color: darken($ui-primary-color, 24%); - - strong { - font-weight: 500; - display: block; - color: $ui-base-color; - } -} - -.advanced-options-dropdown.open { - .advanced-options-dropdown__value { - background: $simple-background-color; - border-radius: 4px 4px 0 0; - box-shadow: 0 -4px 4px rgba($base-shadow-color, 0.1); - } - - .advanced-options-dropdown__dropdown { - display: block; - box-shadow: 2px 4px 6px rgba($base-shadow-color, 0.1); - } -} - - -.search { - position: relative; - margin-bottom: 10px; -} - -.search__input { - outline: 0; - box-sizing: border-box; - display: block; - width: 100%; - border: none; - padding: 10px; - padding-right: 30px; - font-family: inherit; - background: $ui-base-color; - color: $ui-primary-color; - font-size: 14px; - margin: 0; - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } - - &:focus { - background: lighten($ui-base-color, 4%); - } - - @include limited-single-column('screen and (max-width: 600px)') { - font-size: 16px; - } -} - -.search__icon { - .fa { - position: absolute; - top: 10px; - right: 10px; - z-index: 2; - display: inline-block; - opacity: 0; - transition: all 100ms linear; - font-size: 18px; - width: 18px; - height: 18px; - color: $ui-secondary-color; - cursor: default; - pointer-events: none; - - &.active { - pointer-events: auto; - opacity: 0.3; - } - } - - .fa-search { - transform: rotate(90deg); - - &.active { - pointer-events: none; - transform: rotate(0deg); - } - } - - .fa-times-circle { - top: 11px; - transform: rotate(0deg); - cursor: pointer; - - &.active { - transform: rotate(90deg); - } - - &:hover { - color: $primary-text-color; - } - } -} - -.search-results__header { - color: $ui-base-lighter-color; - background: lighten($ui-base-color, 2%); - border-bottom: 1px solid darken($ui-base-color, 4%); - padding: 15px 10px; - font-size: 14px; - font-weight: 500; -} - -.search-results__section { - background: $ui-base-color; -} - -.search-results__hashtag { - display: block; - padding: 10px; - color: $ui-secondary-color; - text-decoration: none; - - &:hover, - &:active, - &:focus { - color: lighten($ui-secondary-color, 4%); - text-decoration: underline; - } -} - -.modal-root { - transition: opacity 0.3s linear; - will-change: opacity; - z-index: 9999; -} - -.modal-root__overlay { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba($base-overlay-background, 0.7); -} - -.modal-root__container { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - align-content: space-around; - z-index: 9999; - pointer-events: none; - user-select: none; -} - -.modal-root__modal { - pointer-events: auto; - display: flex; - z-index: 9999; -} - -.media-modal { - max-width: 80vw; - max-height: 80vh; - position: relative; - - .extended-video-player, - img, - canvas, - video { - max-width: 80vw; - max-height: 80vh; - width: auto; - height: auto; - margin: auto; - } - - .extended-video-player, - video { - display: flex; - width: 80vw; - height: 80vh; - } - - img, - canvas { - display: block; - background: url('../images/void.png') repeat; - object-fit: contain; - } - - .react-swipeable-view-container { - max-width: 80vw; - } -} - -.media-modal__content { - background: $base-overlay-background; -} - -.media-modal__pagination { - width: 100%; - text-align: center; - position: absolute; - left: 0; - bottom: -40px; -} - -.media-modal__page-dot { - display: inline-block; -} - -.media-modal__button { - background-color: $white; - height: 12px; - width: 12px; - border-radius: 6px; - margin: 10px; - padding: 0; - border: 0; - font-size: 0; -} - -.media-modal__button--active { - background-color: $ui-highlight-color; -} - -.media-modal__close { - position: absolute; - right: 4px; - top: 4px; - z-index: 100; -} - -.onboarding-modal, -.error-modal, -.embed-modal { - background: $ui-secondary-color; - color: $ui-base-color; - border-radius: 8px; - overflow: hidden; - display: flex; - flex-direction: column; -} - -.onboarding-modal__pager { - height: 80vh; - width: 80vw; - max-width: 520px; - max-height: 420px; - - .react-swipeable-view-container > div { - width: 100%; - height: 100%; - box-sizing: border-box; - padding: 25px; - display: none; - flex-direction: column; - align-items: center; - justify-content: center; - display: flex; - user-select: text; - } -} - -.error-modal__body { - height: 80vh; - width: 80vw; - max-width: 520px; - max-height: 420px; - position: relative; - - & > div { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - box-sizing: border-box; - padding: 25px; - display: none; - flex-direction: column; - align-items: center; - justify-content: center; - display: flex; - opacity: 0; - user-select: text; - } -} - -.error-modal__body { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; -} - -@media screen and (max-width: 550px) { - .onboarding-modal { - width: 100%; - height: 100%; - border-radius: 0; - } - - .onboarding-modal__pager { - width: 100%; - height: auto; - max-width: none; - max-height: none; - flex: 1 1 auto; - } -} - -.onboarding-modal__paginator, -.error-modal__footer { - flex: 0 0 auto; - background: darken($ui-secondary-color, 8%); - display: flex; - padding: 25px; - - & > div { - min-width: 33px; - } - - .onboarding-modal__nav, - .error-modal__nav { - color: darken($ui-secondary-color, 34%); - background-color: transparent; - border: 0; - font-size: 14px; - font-weight: 500; - padding: 0; - line-height: inherit; - height: auto; - - &:hover, - &:focus, - &:active { - color: darken($ui-secondary-color, 38%); - } - - &.onboarding-modal__done, - &.onboarding-modal__next { - color: $ui-highlight-color; - } - } -} - -.error-modal__footer { - justify-content: center; -} - -.onboarding-modal__dots { - flex: 1 1 auto; - display: flex; - align-items: center; - justify-content: center; -} - -.onboarding-modal__dot { - width: 14px; - height: 14px; - border-radius: 14px; - background: darken($ui-secondary-color, 16%); - margin: 0 3px; - cursor: pointer; - - &:hover { - background: darken($ui-secondary-color, 18%); - } - - &.active { - cursor: default; - background: darken($ui-secondary-color, 24%); - } -} - -.onboarding-modal__page__wrapper { - pointer-events: none; - - &.onboarding-modal__page__wrapper--active { - pointer-events: auto; - } -} - -.onboarding-modal__page { - cursor: default; - line-height: 21px; - - h1 { - font-size: 18px; - font-weight: 500; - color: $ui-base-color; - margin-bottom: 20px; - } - - a { - color: $ui-highlight-color; - - &:hover, - &:focus, - &:active { - color: lighten($ui-highlight-color, 4%); - } - } - - p { - font-size: 16px; - color: lighten($ui-base-color, 8%); - margin-top: 10px; - margin-bottom: 10px; - - &:last-child { - margin-bottom: 0; - } - - strong { - font-weight: 500; - background: $ui-base-color; - color: $ui-secondary-color; - border-radius: 4px; - font-size: 14px; - padding: 3px 6px; - } - } -} - -.onboarding-modal__page-one { - display: flex; - align-items: center; -} - -.onboarding-modal__page-one__elephant-friend { - background: url('../images/elephant-friend-1.png') no-repeat center center / contain; - width: 155px; - height: 193px; - margin-right: 15px; -} - -@media screen and (max-width: 400px) { - .onboarding-modal__page-one { - flex-direction: column; - align-items: normal; - } - - .onboarding-modal__page-one__elephant-friend { - width: 100%; - height: 30vh; - max-height: 160px; - margin-bottom: 5vh; - } -} - -.onboarding-modal__page-two, -.onboarding-modal__page-three, -.onboarding-modal__page-four, -.onboarding-modal__page-five { - p { - text-align: left; - } - - .figure { - background: darken($ui-base-color, 8%); - color: $ui-secondary-color; - margin-bottom: 20px; - border-radius: 4px; - padding: 10px; - text-align: center; - font-size: 14px; - box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.3); - - .onboarding-modal__image { - border-radius: 4px; - margin-bottom: 10px; - } - - &.non-interactive { - pointer-events: none; - text-align: left; - } - } -} - -.onboarding-modal__page-four__columns { - .row { - display: flex; - margin-bottom: 20px; - - & > div { - flex: 1 1 0; - margin: 0 10px; - - &:first-child { - margin-left: 0; - } - - &:last-child { - margin-right: 0; - } - - p { - text-align: center; - } - } - - &:last-child { - margin-bottom: 0; - } - } - - .column-header { - color: $primary-text-color; - } -} - -@media screen and (max-width: 320px) and (max-height: 600px) { - .onboarding-modal__page p { - font-size: 14px; - line-height: 20px; - } - - .onboarding-modal__page-two .figure, - .onboarding-modal__page-three .figure, - .onboarding-modal__page-four .figure, - .onboarding-modal__page-five .figure { - font-size: 12px; - margin-bottom: 10px; - } - - .onboarding-modal__page-four__columns .row { - margin-bottom: 10px; - } - - .onboarding-modal__page-four__columns .column-header { - padding: 5px; - font-size: 12px; - } -} - -.onboarding-modal__image { - border-radius: 8px; - width: 70vw; - max-width: 450px; - max-height: auto; - display: block; - margin: auto; - margin-bottom: 20px; -} - -.onboard-sliders { - display: inline-block; - max-width: 30px; - max-height: auto; - margin-left: 10px; -} - -.boost-modal, -.confirmation-modal, -.report-modal, -.actions-modal, -.mute-modal { - background: lighten($ui-secondary-color, 8%); - color: $ui-base-color; - border-radius: 8px; - overflow: hidden; - max-width: 90vw; - width: 480px; - position: relative; - flex-direction: column; - - .status__display-name { - display: flex; - } -} - -.actions-modal { - .status { - background: $white; - border-bottom-color: $ui-secondary-color; - padding-top: 10px; - padding-bottom: 10px; - } - - .dropdown-menu__separator { - border-bottom-color: $ui-secondary-color; - } -} - -.boost-modal__container { - overflow-x: scroll; - padding: 10px; - - .status { - user-select: text; - border-bottom: 0; - } -} - -.boost-modal__action-bar, -.confirmation-modal__action-bar, -.mute-modal__action-bar, -.report-modal__action-bar { - display: flex; - justify-content: space-between; - background: $ui-secondary-color; - padding: 10px; - line-height: 36px; - - & > div { - flex: 1 1 auto; - text-align: right; - color: lighten($ui-base-color, 33%); - padding-right: 10px; - } - - .button { - flex: 0 0 auto; - } -} - -.boost-modal__status-header { - font-size: 15px; -} - -.boost-modal__status-time { - float: right; - font-size: 14px; -} - -.confirmation-modal { - max-width: 85vw; - - @media screen and (min-width: 480px) { - max-width: 380px; - } -} - -.mute-modal { - line-height: 24px; -} - -.mute-modal .react-toggle { - vertical-align: middle; -} - -.report-modal__statuses, -.report-modal__comment { - padding: 10px; -} - -.report-modal__statuses { - min-height: 20vh; - max-height: 40vh; - overflow-y: auto; - overflow-x: hidden; -} - -.report-modal__comment { - .setting-text { - margin-top: 10px; - } -} - -.actions-modal { - .status { - overflow-y: auto; - max-height: 300px; - } - - max-height: 80vh; - max-width: 80vw; - - .actions-modal__item-label { - font-weight: 500; - } - - ul { - overflow-y: auto; - flex-shrink: 0; - - li:empty { - margin: 0; - } - - li:not(:empty) { - a { - color: $ui-base-color; - display: flex; - padding: 12px 16px; - font-size: 15px; - align-items: center; - text-decoration: none; - - &, - button { - transition: none; - } - - &.active, - &:hover, - &:active, - &:focus { - &, - button { - background: $ui-highlight-color; - color: $primary-text-color; - } - } - - button:first-child { - margin-right: 10px; - } - } - } - } -} - -.confirmation-modal__action-bar, -.mute-modal__action-bar { - .confirmation-modal__cancel-button, - .mute-modal__cancel-button { - background-color: transparent; - color: darken($ui-secondary-color, 34%); - font-size: 14px; - font-weight: 500; - - &:hover, - &:focus, - &:active { - color: darken($ui-secondary-color, 38%); - } - } -} - -.confirmation-modal__container, -.mute-modal__container, -.report-modal__target { - padding: 30px; - font-size: 16px; - text-align: center; - - strong { - font-weight: 500; - } -} - -.loading-bar { - background-color: $ui-highlight-color; - height: 3px; - position: absolute; - top: 0; - left: 0; -} - -.media-gallery__gifv__label { - display: block; - position: absolute; - color: $primary-text-color; - background: rgba($base-overlay-background, 0.5); - bottom: 6px; - left: 6px; - padding: 2px 6px; - border-radius: 2px; - font-size: 11px; - font-weight: 600; - z-index: 1; - pointer-events: none; - opacity: 0.9; - transition: opacity 0.1s ease; -} - -.media-gallery__gifv { - &.autoplay { - .media-gallery__gifv__label { - display: none; - } - } - - &:hover { - .media-gallery__gifv__label { - opacity: 1; - } - } -} - -.attachment-list { - display: flex; - font-size: 14px; - border: 1px solid lighten($ui-base-color, 8%); - border-radius: 4px; - margin-top: 14px; - overflow: hidden; -} - -.attachment-list__icon { - flex: 0 0 auto; - color: $ui-base-lighter-color; - padding: 8px 18px; - cursor: default; - border-right: 1px solid lighten($ui-base-color, 8%); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: 26px; - - .fa { - display: block; - } -} - -.attachment-list__list { - list-style: none; - padding: 4px 0; - padding-left: 8px; - display: flex; - flex-direction: column; - justify-content: center; - - li { - display: block; - padding: 4px 0; - } - - a { - text-decoration: none; - color: $ui-base-lighter-color; - font-weight: 500; - - &:hover { - text-decoration: underline; - } - } -} - -/* Media Gallery */ -.media-gallery { - box-sizing: border-box; - margin-top: 15px; - overflow: hidden; - position: relative; - background: $base-shadow-color; - width: 100%; - - .detailed-status & { - margin-left:-10px; - width: calc(100% + 22px); - } - - @include fullwidth-gallery; -} - -.media-gallery__item { - border: none; - box-sizing: border-box; - display: block; - float: left; - position: relative; - - &.standalone { - .media-gallery__item-gifv-thumbnail { - transform: none; - } - } -} - -.media-gallery__item-thumbnail { - cursor: zoom-in; - text-decoration: none; - width: 100%; - height: 100%; - line-height: 0; - display: flex; - - img { - width: 100%; - object-fit: contain; - - &:not(.letterbox) { - height: 100%; - object-fit: cover; - } - } -} - -.media-gallery__gifv { - height: 100%; - overflow: hidden; - position: relative; - width: 100%; - display: flex; - justify-content: center; -} - -.media-gallery__item-gifv-thumbnail { - cursor: zoom-in; - height: 100%; - position: relative; - z-index: 1; - object-fit: contain; - - &:not(.letterbox) { - height: 100%; - object-fit: cover; - } -} - -.media-gallery__item-thumbnail-label { - clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ - clip: rect(1px, 1px, 1px, 1px); - overflow: hidden; - position: absolute; -} -/* End Media Gallery */ - -/* Status Video Player */ -.status__video-player { - display: flex; - align-items: center; - background: $base-shadow-color; - box-sizing: border-box; - cursor: default; /* May not be needed */ - margin-top: 15px; - overflow: hidden; - position: relative; - width: 100%; - - @include fullwidth-gallery; -} - -.status__video-player-video { - position: relative; - width: 100%; - z-index: 1; - - &:not(.letterbox) { - height: 100%; - object-fit: cover; - } -} - -.status__video-player-expand, -.status__video-player-mute { - color: $primary-text-color; - opacity: 0.8; - position: absolute; - right: 4px; - text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color; -} - -.status__video-player-spoiler { - display: none; - color: $primary-text-color; - left: 4px; - position: absolute; - text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color; - top: 4px; - z-index: 100; - - &.status__video-player-spoiler--visible { - display: block; - } -} - -.status__video-player-expand { - bottom: 4px; - z-index: 100; -} - -.status__video-player-mute { - top: 4px; - z-index: 5; -} - -.video-player { - overflow: hidden; - position: relative; - background: $base-shadow-color; - max-width: 100%; - - video { - height: 100%; - width: 100%; - z-index: 1; - } - - &.fullscreen { - width: 100% !important; - height: 100% !important; - margin: 0; - - video { - max-width: 100% !important; - max-height: 100% !important; - } - } - - &.inline { - video { - object-fit: cover; - position: relative; - top: 50%; - transform: translateY(-50%); - } - } - - &__controls { - position: absolute; - z-index: 2; - bottom: 0; - left: 0; - right: 0; - box-sizing: border-box; - background: linear-gradient(0deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 60%, transparent); - padding: 0 10px; - opacity: 0; - transition: opacity .1s ease; - - &.active { - opacity: 1; - } - } - - &.inactive { - video, - .video-player__controls { - visibility: hidden; - } - } - - &__spoiler { - display: none; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 4; - border: 0; - background: $base-shadow-color; - color: $ui-primary-color; - transition: none; - pointer-events: none; - - &.active { - display: block; - pointer-events: auto; - - &:hover, - &:active, - &:focus { - color: lighten($ui-primary-color, 8%); - } - } - - &__title { - display: block; - font-size: 14px; - } - - &__subtitle { - display: block; - font-size: 11px; - font-weight: 500; - } - } - - &__buttons { - padding-bottom: 10px; - font-size: 16px; - - &.left { - float: left; - - button { - padding-right: 10px; - } - } - - &.right { - float: right; - - button { - padding-left: 10px; - } - } - - button { - background: transparent; - padding: 0; - border: 0; - color: $white; - - &:active, - &:hover, - &:focus { - color: $ui-highlight-color; - } - } - } - - &__seek { - cursor: pointer; - height: 24px; - position: relative; - - &::before { - content: ""; - width: 100%; - background: rgba($white, 0.35); - display: block; - position: absolute; - height: 4px; - top: 10px; - } - - &__progress, - &__buffer { - display: block; - position: absolute; - height: 4px; - top: 10px; - background: $ui-highlight-color; - } - - &__buffer { - background: rgba($white, 0.2); - } - - &__handle { - position: absolute; - z-index: 3; - opacity: 0; - border-radius: 50%; - width: 12px; - height: 12px; - top: 6px; - margin-left: -6px; - transition: opacity .1s ease; - background: $ui-highlight-color; - pointer-events: none; - - &.active { - opacity: 1; - } - } - - &:hover { - .video-player__seek__handle { - opacity: 1; - } - } - } -} - -.media-spoiler-video { - background-size: cover; - background-repeat: no-repeat; - background-position: center; - cursor: pointer; - margin-top: 15px; - position: relative; - width: 100%; - - @include fullwidth-gallery; - - border: 0; - display: block; -} - -.media-spoiler-video-play-icon { - border-radius: 100px; - color: rgba($primary-text-color, 0.8); - font-size: 36px; - left: 50%; - padding: 5px; - position: absolute; - top: 50%; - transform: translate(-50%, -50%); -} -/* End Video Player */ - -.account-gallery__container { - margin: -2px; - padding: 4px; - display: flex; - flex-wrap: wrap; -} - -.account-gallery__item { - flex: 1 1 auto; - width: calc(100% / 3 - 4px); - height: 95px; - margin: 2px; - - a { - display: block; - width: 100%; - height: 100%; - background-color: $base-overlay-background; - background-size: cover; - background-position: center; - position: relative; - color: inherit; - text-decoration: none; - - &:hover, - &:active, - &:focus { - outline: 0; - } - } -} - -.account-section-headline { - color: $ui-base-lighter-color; - background: lighten($ui-base-color, 2%); - border-bottom: 1px solid lighten($ui-base-color, 4%); - padding: 15px 10px; - font-size: 14px; - font-weight: 500; - position: relative; - cursor: default; - - &::before, - &::after { - display: block; - content: ""; - position: absolute; - bottom: 0; - left: 18px; - width: 0; - height: 0; - border-style: solid; - border-width: 0 10px 10px; - border-color: transparent transparent lighten($ui-base-color, 4%); - } - - &::after { - bottom: -1px; - border-color: transparent transparent $ui-base-color; - } -} - -::-webkit-scrollbar-thumb { - border-radius: 0; -} - -.search-popout { - background: $simple-background-color; - border-radius: 4px; - padding: 10px 14px; - padding-bottom: 14px; - margin-top: 10px; - color: $ui-primary-color; - box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); - - h4 { - text-transform: uppercase; - color: $ui-primary-color; - font-size: 13px; - font-weight: 500; - margin-bottom: 10px; - } - - li { - padding: 4px 0; - } - - ul { - margin-bottom: 10px; - } - - em { - font-weight: 500; - color: $ui-base-color; - } -} - -noscript { - text-align: center; - - img { - width: 200px; - opacity: 0.5; - animation: flicker 4s infinite; - } - - div { - font-size: 14px; - margin: 30px auto; - color: $ui-secondary-color; - max-width: 400px; - - a { - color: $ui-highlight-color; - text-decoration: underline; - - &:hover { - text-decoration: none; - } - } - } -} - -@keyframes flicker { - 0% { opacity: 1; } - 30% { opacity: 0.75; } - 100% { opacity: 1; } -} - -@media screen and (max-width: 630px) and (max-height: 400px) { - $duration: 400ms; - $delay: 100ms; - - .tabs-bar, - .search { - will-change: margin-top; - transition: margin-top $duration $delay; - } - - .navigation-bar { - will-change: padding-bottom; - transition: padding-bottom $duration $delay; - } - - .navigation-bar { - & > a:first-child { - will-change: margin-top, margin-left, width; - transition: margin-top $duration $delay, margin-left $duration ($duration + $delay); - } - - & > .navigation-bar__profile-edit { - will-change: margin-top; - transition: margin-top $duration $delay; - } - - & > .icon-button { - will-change: opacity; - transition: opacity $duration $delay; - } - } - - .is-composing { - .tabs-bar, - .search { - margin-top: -50px; - } - - .navigation-bar { - padding-bottom: 0; - - & > a:first-child { - margin-top: -50px; - margin-left: -40px; - } - - .navigation-bar__profile { - padding-top: 2px; - } - - .navigation-bar__profile-edit { - position: absolute; - margin-top: -50px; - } - - .icon-button { - pointer-events: auto; - opacity: 1; - } - } - } - - // fixes for the navbar-under mode - .is-composing.navbar-under { - .search { - margin-top: -20px; - margin-bottom: -20px; - .search__icon { - display: none; - } - } - } -} - -// more fixes for the navbar-under mode -@mixin fix-margins-for-navbar-under { - .tabs-bar { - margin-top: 0 !important; - margin-bottom: -6px !important; - } -} - -.single-column.navbar-under { - @include fix-margins-for-navbar-under; -} - -.auto-columns.navbar-under { - @media screen and (max-width: 360px) { - @include fix-margins-for-navbar-under; - } -} - -.auto-columns.navbar-under .react-swipeable-view-container .columns-area, -.single-column.navbar-under .react-swipeable-view-container .columns-area { - @media screen and (max-width: 360px) { - height: 100% !important; - } -} - -.embed-modal { - max-width: 80vw; - max-height: 80vh; - - h4 { - padding: 30px; - font-weight: 500; - font-size: 16px; - text-align: center; - } - - .embed-modal__container { - padding: 10px; - - .hint { - margin-bottom: 15px; - } - - .embed-modal__html { - color: $ui-secondary-color; - outline: 0; - box-sizing: border-box; - display: block; - width: 100%; - border: none; - padding: 10px; - font-family: 'mastodon-font-monospace', monospace; - background: $ui-base-color; - color: $ui-primary-color; - font-size: 14px; - margin: 0; - margin-bottom: 15px; - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } - - &:focus { - background: lighten($ui-base-color, 4%); - } - - @media screen and (max-width: 600px) { - font-size: 16px; - } - } - - .embed-modal__iframe { - width: 400px; - max-width: 100%; - overflow: hidden; - border: 0; - } - } -} - -@import 'doodle'; diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss deleted file mode 100644 index af2589e23..000000000 --- a/app/javascript/styles/mastodon/containers.scss +++ /dev/null @@ -1,116 +0,0 @@ -.container { - width: 700px; - margin: 0 auto; - margin-top: 40px; - - @media screen and (max-width: 740px) { - width: 100%; - margin: 0; - } -} - -.logo-container { - margin: 100px auto; - margin-bottom: 50px; - - @media screen and (max-width: 400px) { - margin: 30px auto; - margin-bottom: 20px; - } - - h1 { - display: flex; - justify-content: center; - align-items: center; - - img { - height: 42px; - margin-right: 10px; - } - - a { - display: flex; - justify-content: center; - align-items: center; - color: $primary-text-color; - text-decoration: none; - outline: 0; - padding: 12px 16px; - line-height: 32px; - font-family: 'mastodon-font-display', sans-serif; - font-weight: 500; - font-size: 14px; - } - } -} - -.compose-standalone { - .compose-form { - width: 400px; - margin: 0 auto; - padding: 20px 0; - margin-top: 40px; - box-sizing: border-box; - - @media screen and (max-width: 400px) { - width: 100%; - margin-top: 0; - padding: 20px; - } - } -} - -.account-header { - width: 400px; - margin: 0 auto; - display: flex; - font-size: 13px; - line-height: 18px; - box-sizing: border-box; - padding: 20px 0; - padding-bottom: 0; - margin-bottom: -30px; - margin-top: 40px; - - @media screen and (max-width: 440px) { - width: 100%; - margin: 0; - margin-bottom: 10px; - padding: 20px; - padding-bottom: 0; - } - - .avatar { - width: 40px; - height: 40px; - margin-right: 8px; - - img { - width: 100%; - height: 100%; - display: block; - margin: 0; - border-radius: 4px; - } - } - - .name { - flex: 1 1 auto; - color: $ui-secondary-color; - width: calc(100% - 88px); - - .username { - display: block; - font-weight: 500; - text-overflow: ellipsis; - overflow: hidden; - } - } - - .logout-link { - display: block; - font-size: 32px; - line-height: 40px; - margin-left: 8px; - } -} diff --git a/app/javascript/styles/mastodon/emoji_picker.scss b/app/javascript/styles/mastodon/emoji_picker.scss deleted file mode 100644 index 2b46d30fc..000000000 --- a/app/javascript/styles/mastodon/emoji_picker.scss +++ /dev/null @@ -1,199 +0,0 @@ -.emoji-mart { - &, - * { - box-sizing: border-box; - line-height: 1.15; - } - - font-size: 13px; - display: inline-block; - color: $ui-base-color; - - .emoji-mart-emoji { - padding: 6px; - } -} - -.emoji-mart-bar { - border: 0 solid darken($ui-secondary-color, 8%); - - &:first-child { - border-bottom-width: 1px; - border-top-left-radius: 5px; - border-top-right-radius: 5px; - background: $ui-secondary-color; - } - - &:last-child { - border-top-width: 1px; - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; - display: none; - } -} - -.emoji-mart-anchors { - display: flex; - justify-content: space-between; - padding: 0 6px; - color: $ui-primary-color; - line-height: 0; -} - -.emoji-mart-anchor { - position: relative; - flex: 1; - text-align: center; - padding: 12px 4px; - overflow: hidden; - transition: color .1s ease-out; - cursor: pointer; - - &:hover { - color: darken($ui-primary-color, 4%); - } -} - -.emoji-mart-anchor-selected { - color: darken($ui-highlight-color, 3%); - - &:hover { - color: darken($ui-highlight-color, 3%); - } - - .emoji-mart-anchor-bar { - bottom: 0; - } -} - -.emoji-mart-anchor-bar { - position: absolute; - bottom: -3px; - left: 0; - width: 100%; - height: 3px; - background-color: darken($ui-highlight-color, 3%); -} - -.emoji-mart-anchors { - i { - display: inline-block; - width: 100%; - max-width: 22px; - } - - svg { - fill: currentColor; - max-height: 18px; - } -} - -.emoji-mart-scroll { - overflow-y: scroll; - height: 270px; - max-height: 35vh; - padding: 0 6px 6px; - background: $simple-background-color; - will-change: transform; -} - -.emoji-mart-search { - padding: 10px; - padding-right: 45px; - background: $simple-background-color; - - input { - font-size: 14px; - font-weight: 400; - padding: 7px 9px; - font-family: inherit; - display: block; - width: 100%; - background: rgba($ui-secondary-color, 0.3); - color: $ui-primary-color; - border: 1px solid $ui-secondary-color; - border-radius: 4px; - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } - } -} - -.emoji-mart-category .emoji-mart-emoji { - cursor: pointer; - - span { - z-index: 1; - position: relative; - text-align: center; - } - - &:hover::before { - z-index: 0; - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba($ui-secondary-color, 0.7); - border-radius: 100%; - } -} - -.emoji-mart-category-label { - z-index: 2; - position: relative; - position: -webkit-sticky; - position: sticky; - top: 0; - - span { - display: block; - width: 100%; - font-weight: 500; - padding: 5px 6px; - background: $simple-background-color; - } -} - -.emoji-mart-emoji { - position: relative; - display: inline-block; - font-size: 0; - - span { - width: 22px; - height: 22px; - } -} - -.emoji-mart-no-results { - font-size: 14px; - text-align: center; - padding-top: 70px; - color: $ui-primary-color; - - .emoji-mart-category-label { - display: none; - } - - .emoji-mart-no-results-label { - margin-top: .2em; - } - - .emoji-mart-emoji:hover::before { - content: none; - } -} - -.emoji-mart-preview { - display: none; -} diff --git a/app/javascript/styles/mastodon/footer.scss b/app/javascript/styles/mastodon/footer.scss deleted file mode 100644 index 2d953b34e..000000000 --- a/app/javascript/styles/mastodon/footer.scss +++ /dev/null @@ -1,30 +0,0 @@ -.footer { - text-align: center; - margin-top: 30px; - font-size: 12px; - color: darken($ui-secondary-color, 25%); - - .domain { - font-weight: 500; - - a { - color: inherit; - text-decoration: none; - } - } - - .powered-by, - .single-user-login { - font-weight: 400; - - a { - color: inherit; - text-decoration: underline; - font-weight: 500; - - &:hover { - text-decoration: none; - } - } - } -} diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss deleted file mode 100644 index 61fcf286f..000000000 --- a/app/javascript/styles/mastodon/forms.scss +++ /dev/null @@ -1,540 +0,0 @@ -code { - font-family: 'mastodon-font-monospace', monospace; - font-weight: 400; -} - -.form-container { - max-width: 400px; - padding: 20px; - margin: 0 auto; -} - -.simple_form { - .input { - margin-bottom: 15px; - overflow: hidden; - } - - span.hint { - display: block; - color: $ui-primary-color; - font-size: 12px; - margin-top: 4px; - } - - h4 { - text-transform: uppercase; - font-size: 13px; - font-weight: 500; - color: $ui-primary-color; - padding-bottom: 8px; - margin-bottom: 8px; - border-bottom: 1px solid lighten($ui-base-color, 8%); - } - - p.hint { - margin-bottom: 15px; - color: $ui-primary-color; - - &.subtle-hint { - text-align: center; - font-size: 12px; - line-height: 18px; - margin-top: 15px; - margin-bottom: 0; - color: $ui-primary-color; - - a { - color: $ui-highlight-color; - } - } - } - - .card { - margin-bottom: 15px; - } - - strong { - font-weight: 500; - } - - .label_input { - display: flex; - - label { - flex: 0 0 auto; - } - - input { - flex: 1 1 auto; - } - } - - .input.with_label { - padding: 15px 0; - margin-bottom: 0; - - .label_input { - flex-wrap: wrap; - align-items: flex-start; - } - - &.select .label_input { - align-items: initial; - } - - .label_input > label { - font-family: inherit; - font-size: 16px; - color: $primary-text-color; - display: block; - padding-top: 5px; - margin-bottom: 5px; - flex: 1; - min-width: 150px; - word-wrap: break-word; - - &.select { - flex: 0; - } - - & ~ * { - margin-left: 10px; - } - } - - ul { - flex: 390px; - } - - &.boolean { - padding: initial; - margin-bottom: initial; - - .label_input > label { - font-family: inherit; - font-size: 14px; - color: $primary-text-color; - display: block; - width: auto; - } - - label.checkbox { - position: relative; - padding-left: 25px; - flex: 1 1 auto; - } - } - } - - .input.with_block_label { - & > label { - font-family: inherit; - font-size: 16px; - color: $primary-text-color; - display: block; - padding-top: 5px; - } - - .hint { - margin-bottom: 15px; - } - - li { - float: left; - width: 50%; - } - } - - .fields-group { - margin-bottom: 25px; - } - - .input.radio_buttons .radio label { - margin-bottom: 5px; - font-family: inherit; - font-size: 14px; - color: $primary-text-color; - display: block; - width: auto; - } - - .input.boolean { - margin-bottom: 5px; - - label { - font-family: inherit; - font-size: 14px; - color: $primary-text-color; - display: block; - width: auto; - } - - label.checkbox { - position: relative; - padding-left: 25px; - flex: 1 1 auto; - } - - input[type=checkbox] { - position: absolute; - left: 0; - top: 5px; - margin: 0; - } - - .hint { - padding-left: 25px; - margin-left: 0; - } - } - - .check_boxes { - .checkbox { - label { - font-family: inherit; - font-size: 14px; - color: $primary-text-color; - display: block; - width: auto; - position: relative; - padding-top: 5px; - padding-left: 25px; - flex: 1 1 auto; - } - - input[type=checkbox] { - position: absolute; - left: 0; - top: 5px; - margin: 0; - } - } - } - - input[type=text], - input[type=number], - input[type=email], - input[type=password], - textarea { - background: transparent; - box-sizing: border-box; - border: 0; - border-bottom: 2px solid $ui-primary-color; - border-radius: 2px 2px 0 0; - padding: 7px 4px; - font-size: 16px; - color: $primary-text-color; - display: block; - width: 100%; - outline: 0; - font-family: inherit; - resize: vertical; - - &:invalid { - box-shadow: none; - } - - &:focus:invalid { - border-bottom-color: $error-value-color; - } - - &:required:valid { - border-bottom-color: $valid-value-color; - } - - &:active, - &:focus { - border-bottom-color: $ui-highlight-color; - background: rgba($base-overlay-background, 0.1); - } - } - - .input.field_with_errors { - label { - color: $error-value-color; - } - - input[type=text], - input[type=email], - input[type=password] { - border-bottom-color: $error-value-color; - } - - .error { - display: block; - font-weight: 500; - color: $error-value-color; - margin-top: 4px; - } - } - - .actions { - margin-top: 30px; - display: flex; - } - - button, - .button, - .block-button { - display: block; - width: 100%; - border: 0; - border-radius: 4px; - background: $ui-highlight-color; - color: $primary-text-color; - font-size: 18px; - line-height: inherit; - height: auto; - padding: 10px; - text-transform: uppercase; - text-decoration: none; - text-align: center; - box-sizing: border-box; - cursor: pointer; - font-weight: 500; - outline: 0; - margin-bottom: 10px; - margin-right: 10px; - - &:last-child { - margin-right: 0; - } - - &:hover { - background-color: lighten($ui-highlight-color, 5%); - } - - &:active, - &:focus { - background-color: darken($ui-highlight-color, 5%); - } - - &.negative { - background: $error-value-color; - - &:hover { - background-color: lighten($error-value-color, 5%); - } - - &:active, - &:focus { - background-color: darken($error-value-color, 5%); - } - } - } - - select { - font-size: 16px; - max-height: 29px; - } - - .input-with-append { - position: relative; - - .input input { - padding-right: 127px; - } - - .append { - position: absolute; - right: 0; - top: 0; - padding: 7px 4px; - padding-bottom: 9px; - font-size: 16px; - color: $ui-base-lighter-color; - font-family: inherit; - pointer-events: none; - cursor: default; - } - } -} - -.flash-message { - background: lighten($ui-base-color, 8%); - color: $ui-primary-color; - border-radius: 4px; - padding: 15px 10px; - margin-bottom: 30px; - box-shadow: 0 0 5px rgba($base-shadow-color, 0.2); - text-align: center; - - p { - margin-bottom: 15px; - } - - .oauth-code { - color: $ui-secondary-color; - outline: 0; - box-sizing: border-box; - display: block; - width: 100%; - border: none; - padding: 10px; - font-family: 'mastodon-font-monospace', monospace; - background: $ui-base-color; - color: $ui-primary-color; - font-size: 14px; - margin: 0; - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } - - &:focus { - background: lighten($ui-base-color, 4%); - } - } - - strong { - font-weight: 500; - } - - @media screen and (max-width: 740px) and (min-width: 441px) { - margin-top: 40px; - } -} - -.form-footer { - margin-top: 30px; - text-align: center; - - a { - color: $ui-primary-color; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } -} - -.oauth-prompt, -.follow-prompt { - margin-bottom: 30px; - text-align: center; - color: $ui-primary-color; - - h2 { - font-size: 16px; - margin-bottom: 30px; - } - - strong { - color: $ui-secondary-color; - font-weight: 500; - } - - @media screen and (max-width: 740px) and (min-width: 441px) { - margin-top: 40px; - } -} - -.qr-wrapper { - display: flex; - flex-wrap: wrap; - align-items: flex-start; -} - -.qr-code { - flex: 0 0 auto; - background: $simple-background-color; - padding: 4px; - margin: 0 10px 20px 0; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - display: inline-block; - - svg { - display: block; - margin: 0; - } -} - -.qr-alternative { - margin-bottom: 20px; - color: $ui-secondary-color; - flex: 150px; - - samp { - display: block; - font-size: 14px; - } -} - -.table-form { - p { - margin-bottom: 15px; - - strong { - font-weight: 500; - } - } -} - -.simple_form, -.table-form { - .warning { - box-sizing: border-box; - background: rgba($error-value-color, 0.5); - color: $primary-text-color; - text-shadow: 1px 1px 0 rgba($base-shadow-color, 0.3); - box-shadow: 0 2px 6px rgba($base-shadow-color, 0.4); - border-radius: 4px; - padding: 10px; - margin-bottom: 15px; - - a { - color: $primary-text-color; - text-decoration: underline; - - &:hover, - &:focus, - &:active { - text-decoration: none; - } - } - - strong { - font-weight: 600; - display: block; - margin-bottom: 5px; - - .fa { - font-weight: 400; - } - } - } -} - -.action-pagination { - display: flex; - flex-wrap: wrap; - align-items: center; - - .actions, - .pagination { - flex: 1 1 auto; - } - - .actions { - padding: 30px 0; - padding-right: 20px; - flex: 0 0 auto; - } -} - -.post-follow-actions { - text-align: center; - color: $ui-primary-color; - - div { - margin-bottom: 4px; - } -} diff --git a/app/javascript/styles/mastodon/landing_strip.scss b/app/javascript/styles/mastodon/landing_strip.scss deleted file mode 100644 index 0bf9daafd..000000000 --- a/app/javascript/styles/mastodon/landing_strip.scss +++ /dev/null @@ -1,36 +0,0 @@ -.landing-strip, -.memoriam-strip { - background: rgba(darken($ui-base-color, 7%), 0.8); - color: $ui-primary-color; - font-weight: 400; - padding: 14px; - border-radius: 4px; - margin-bottom: 20px; - display: flex; - align-items: center; - - strong, - a { - font-weight: 500; - } - - a { - color: inherit; - text-decoration: underline; - } - - .logo { - width: 30px; - height: 30px; - flex: 0 0 auto; - margin-right: 15px; - } - - @media screen and (max-width: 740px) { - margin-bottom: 0; - } -} - -.memoriam-strip { - background: rgba($base-shadow-color, 0.7); -} diff --git a/app/javascript/styles/mastodon/lists.scss b/app/javascript/styles/mastodon/lists.scss deleted file mode 100644 index 6019cd800..000000000 --- a/app/javascript/styles/mastodon/lists.scss +++ /dev/null @@ -1,19 +0,0 @@ -.no-list { - list-style: none; - - li { - display: inline-block; - margin: 0 5px; - } -} - -.recovery-codes { - list-style: none; - margin: 0 auto; - - li { - font-size: 125%; - line-height: 1.5; - letter-spacing: 1px; - } -} diff --git a/app/javascript/styles/mastodon/reset.scss b/app/javascript/styles/mastodon/reset.scss deleted file mode 100644 index cc5ba9d7c..000000000 --- a/app/javascript/styles/mastodon/reset.scss +++ /dev/null @@ -1,91 +0,0 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -/* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} - -body { - line-height: 1; -} - -ol, ul { - list-style: none; -} - -blockquote, q { - quotes: none; -} - -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -::-webkit-scrollbar-thumb { - background: lighten($ui-base-color, 4%); - border: 0px none $base-border-color; - border-radius: 50px; -} - -::-webkit-scrollbar-thumb:hover { - background: lighten($ui-base-color, 6%); -} - -::-webkit-scrollbar-thumb:active { - background: lighten($ui-base-color, 4%); -} - -::-webkit-scrollbar-track { - border: 0px none $base-border-color; - border-radius: 0; - background: rgba($base-overlay-background, 0.1); -} - -::-webkit-scrollbar-track:hover { - background: $ui-base-color; -} - -::-webkit-scrollbar-track:active { - background: $ui-base-color; -} - -::-webkit-scrollbar-corner { - background: transparent; -} diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss deleted file mode 100644 index 67bfa8a38..000000000 --- a/app/javascript/styles/mastodon/rtl.scss +++ /dev/null @@ -1,254 +0,0 @@ -body.rtl { - direction: rtl; - - .column-link__icon, - .column-header__icon { - margin-right: 0; - margin-left: 5px; - } - - .character-counter__wrapper { - margin-right: 8px; - margin-left: 16px; - } - - .navigation-bar__profile { - margin-left: 0; - margin-right: 8px; - } - - .search__input { - padding-right: 10px; - padding-left: 30px; - } - - .search__icon .fa { - right: auto; - left: 10px; - } - - .column-header__buttons { - left: 0; - right: auto; - } - - .column-header__back-button { - padding-left: 5px; - padding-right: 0; - } - - .column-header__setting-arrows { - float: left; - } - - .compose-form__modifiers { - border-radius: 0 0 0 4px; - } - - .setting-toggle { - margin-left: 0; - margin-right: 8px; - } - - .setting-meta__label { - float: left; - } - - .status__avatar { - left: auto; - right: 10px; - } - - .status, - .activity-stream .status.light { - padding-left: 10px; - padding-right: 68px; - } - - .status__info .status__display-name, - .activity-stream .status.light .status__display-name { - padding-left: 25px; - padding-right: 0; - } - - .activity-stream .pre-header { - padding-right: 68px; - padding-left: 0; - } - - .status__prepend { - margin-left: 0; - margin-right: 68px; - } - - .status__prepend-icon-wrapper { - left: auto; - right: -26px; - } - - .activity-stream .pre-header .pre-header__icon { - left: auto; - right: 42px; - } - - .account__avatar-overlay-overlay { - right: auto; - left: 0; - } - - .column-back-button--slim-button { - right: auto; - left: 0; - } - - .status__relative-time, - .activity-stream .status.light .status__header .status__meta { - float: left; - } - - .activity-stream .detailed-status.light .detailed-status__display-name > div { - float: right; - margin-right: 0; - margin-left: 10px; - } - - .activity-stream .detailed-status.light .detailed-status__meta span > span { - margin-left: 0; - margin-right: 6px; - } - - .status__action-bar-button { - float: right; - margin-right: 0; - margin-left: 18px; - } - - .status__action-bar-dropdown { - float: right; - } - - .privacy-dropdown__dropdown { - margin-left: 0; - margin-right: 40px; - } - - .privacy-dropdown__option__icon { - margin-left: 10px; - margin-right: 0; - } - - .detailed-status__display-avatar { - margin-right: 0; - margin-left: 10px; - float: right; - } - - .detailed-status__favorites, - .detailed-status__reblogs { - margin-left: 0; - margin-right: 6px; - } - - .fa-ul { - margin-left: 0; - margin-left: 2.14285714em; - } - - .fa-li { - left: auto; - right: -2.14285714em; - } - - .admin-wrapper .sidebar ul a i.fa, - a.table-action-link i.fa { - margin-right: 0; - margin-left: 5px; - } - - .simple_form .check_boxes .checkbox label, - .simple_form .input.with_label.boolean label.checkbox { - padding-left: 0; - padding-right: 25px; - } - - .simple_form .check_boxes .checkbox input[type="checkbox"], - .simple_form .input.boolean input[type="checkbox"] { - left: auto; - right: 0; - } - - .simple_form .input-with-append .input input { - padding-left: 127px; - padding-right: 0; - } - - .simple_form .input-with-append .append { - right: auto; - left: 0; - } - - .table th, - .table td { - text-align: right; - } - - .filters .filter-subset { - margin-right: 0; - margin-left: 45px; - } - - .landing-page .header-wrapper .mascot { - right: 60px; - left: auto; - } - - .landing-page .header .hero .floats .float-1 { - left: -120px; - right: auto; - } - - .landing-page .header .hero .floats .float-2 { - left: 210px; - right: auto; - } - - .landing-page .header .hero .floats .float-3 { - left: 110px; - right: auto; - } - - .landing-page .header .links .brand img { - left: 0; - } - - .landing-page .fa-external-link { - padding-right: 5px; - padding-left: 0 !important; - } - - .landing-page .features #mastodon-timeline { - margin-right: 0; - margin-left: 30px; - } - - @media screen and (min-width: 631px) { - .column, - .drawer { - padding-left: 5px; - padding-right: 5px; - - &:first-child { - padding-left: 5px; - padding-right: 10px; - } - } - - .columns-area > div { - .column, - .drawer { - padding-left: 5px; - padding-right: 5px; - } - } - } -} diff --git a/app/javascript/styles/mastodon/stream_entries.scss b/app/javascript/styles/mastodon/stream_entries.scss deleted file mode 100644 index 453070b7c..000000000 --- a/app/javascript/styles/mastodon/stream_entries.scss +++ /dev/null @@ -1,335 +0,0 @@ -.activity-stream { - clear: both; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - - .entry { - background: $simple-background-color; - - .detailed-status.light, - .status.light { - border-bottom: 1px solid $ui-secondary-color; - animation: none; - } - - &:last-child { - &, - .detailed-status.light, - .status.light { - border-bottom: 0; - border-radius: 0 0 4px 4px; - } - } - - &:first-child { - &, - .detailed-status.light, - .status.light { - border-radius: 4px 4px 0 0; - } - - &:last-child { - &, - .detailed-status.light, - .status.light { - border-radius: 4px; - } - } - } - - @media screen and (max-width: 740px) { - &, - .detailed-status.light, - .status.light { - border-radius: 0 !important; - } - } - } - - &.with-header { - .entry { - &:first-child { - &, - .detailed-status.light, - .status.light { - border-radius: 0; - } - - &:last-child { - &, - .detailed-status.light, - .status.light { - border-radius: 0 0 4px 4px; - } - } - } - } - } - - .status.light { - padding: 14px 14px 14px (48px + 14px * 2); - position: relative; - min-height: 48px; - cursor: default; - - .status__header { - font-size: 15px; - - .status__meta { - float: right; - font-size: 14px; - - .status__relative-time { - color: $ui-primary-color; - } - } - } - - .status__display-name { - display: block; - max-width: 100%; - padding-right: 25px; - color: $ui-base-color; - } - - .status__avatar { - position: absolute; - @include avatar-size(48px); - margin-left: -62px; - - & > div { - @include avatar-size(48px); - } - - img { - @include avatar-radius(); - display: block; - } - } - - .display-name { - display: block; - max-width: 100%; - //overflow: hidden; - //white-space: nowrap; - //text-overflow: ellipsis; - - strong { - font-weight: 500; - color: $ui-base-color; - } - - span { - font-size: 14px; - color: $ui-primary-color; - } - } - - .status__content { - color: $ui-base-color; - - a { - color: $ui-highlight-color; - } - - a.status__content__spoiler-link { - color: $primary-text-color; - background: $ui-primary-color; - - &:hover { - background: lighten($ui-primary-color, 8%); - } - } - } - } - - .detailed-status.light { - padding: 14px; - background: $simple-background-color; - cursor: default; - - .detailed-status__display-name { - display: block; - overflow: hidden; - margin-bottom: 15px; - - & > div { - float: left; - margin-right: 10px; - } - - .display-name { - display: block; - max-width: 100%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - - strong { - font-weight: 500; - color: $ui-base-color; - } - - span { - font-size: 14px; - color: $ui-primary-color; - } - } - } - - .avatar { - @include avatar-size(48px); - - img { - @include avatar-radius(); - display: block; - } - } - - .status__content { - color: $ui-base-color; - - a { - color: $ui-highlight-color; - } - - a.status__content__spoiler-link { - color: $primary-text-color; - background: $ui-primary-color; - - &:hover { - background: lighten($ui-primary-color, 8%); - } - } - } - - .detailed-status__meta { - margin-top: 15px; - color: $ui-primary-color; - font-size: 14px; - line-height: 18px; - - a { - color: inherit; - } - - span > span { - font-weight: 500; - font-size: 12px; - margin-left: 6px; - display: inline-block; - } - } - - .status-card { - border-color: lighten($ui-secondary-color, 4%); - color: darken($ui-primary-color, 4%); - - &:hover { - background: lighten($ui-secondary-color, 4%); - } - } - - .status-card__title, - .status-card__description { - color: $ui-base-color; - } - - .status-card__image { - background: $ui-secondary-color; - } - } - - .media-spoiler { - background: $ui-primary-color; - color: $white; - transition: all 100ms linear; - - &:hover, - &:active, - &:focus { - background: darken($ui-primary-color, 5%); - color: unset; - } - } - - .pre-header { - padding: 14px 0; - padding-left: (48px + 14px * 2); - padding-bottom: 0; - margin-bottom: -4px; - color: $ui-primary-color; - font-size: 14px; - position: relative; - - .pre-header__icon { - position: absolute; - left: (48px + 14px * 2 - 30px); - } - - .status__display-name.muted strong { - color: $ui-primary-color; - } - } - - .open-in-web-link { - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } -} - -.embed { - .activity-stream { - box-shadow: none; - - .entry { - - .detailed-status.light { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: flex-start; - - .detailed-status__display-name { - flex: 1; - margin: 0 5px 15px 0; - } - - .button.button-secondary.logo-button { - flex: 0 auto; - font-size: 14px; - - svg { - width: 20px; - height: auto; - vertical-align: middle; - margin-right: 5px; - - path:first-child { - fill: $ui-primary-color; - } - - path:last-child { - fill: $simple-background-color; - } - } - - &:active, - &:focus, - &:hover { - svg path:first-child { - fill: lighten($ui-primary-color, 4%); - } - } - } - - .status__content, - .detailed-status__meta { - flex: 100%; - } - } - } - } -} diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss deleted file mode 100644 index ad46f5f9f..000000000 --- a/app/javascript/styles/mastodon/tables.scss +++ /dev/null @@ -1,76 +0,0 @@ -.table { - width: 100%; - max-width: 100%; - border-spacing: 0; - border-collapse: collapse; - - th, - td { - padding: 8px; - line-height: 18px; - vertical-align: top; - border-top: 1px solid $ui-base-color; - text-align: left; - } - - & > thead > tr > th { - vertical-align: bottom; - border-bottom: 2px solid $ui-base-color; - border-top: 0; - font-weight: 500; - } - - & > tbody > tr > th { - font-weight: 500; - } - - & > tbody > tr:nth-child(odd) > td, - & > tbody > tr:nth-child(odd) > th { - background: $ui-base-color; - } - - a { - color: $ui-highlight-color; - text-decoration: underline; - - &:hover { - text-decoration: none; - } - } - - strong { - font-weight: 500; - } - - &.inline-table > tbody > tr:nth-child(odd) > td, - &.inline-table > tbody > tr:nth-child(odd) > th { - background: transparent; - } -} - -.table-wrapper { - overflow: auto; - margin-bottom: 20px; -} - -samp { - font-family: 'mastodon-font-monospace', monospace; -} - -a.table-action-link { - text-decoration: none; - display: inline-block; - margin-right: 5px; - padding: 0 10px; - color: rgba($primary-text-color, 0.7); - font-weight: 500; - - &:hover { - color: $primary-text-color; - } - - i.fa { - font-weight: 400; - margin-right: 5px; - } -} diff --git a/app/javascript/styles/mastodon/variables.scss b/app/javascript/styles/mastodon/variables.scss deleted file mode 100644 index 090706ff5..000000000 --- a/app/javascript/styles/mastodon/variables.scss +++ /dev/null @@ -1,32 +0,0 @@ -// Commonly used web colors -$black: #000000; // Black -$white: #ffffff; // White -$success-green: #79bd9a; // Padua -$error-red: #df405a; // Cerise -$warning-red: #ff5050; // Sunset Orange -$gold-star: #ca8f04; // Dark Goldenrod - -// Values from the classic Mastodon UI -$classic-base-color: #282c37; // Midnight Express -$classic-primary-color: #9baec8; // Echo Blue -$classic-secondary-color: #d9e1e8; // Pattens Blue -$classic-highlight-color: #2b90d9; // Summer Sky - -// Variables for defaults in UI -$base-shadow-color: $black !default; -$base-overlay-background: $black !default; -$base-border-color: $white !default; -$simple-background-color: $white !default; -$primary-text-color: $white !default; -$valid-value-color: $success-green !default; -$error-value-color: $error-red !default; - -// Tell UI to use selected colors -$ui-base-color: $classic-base-color !default; // Darkest -$ui-base-lighter-color: lighten($ui-base-color, 26%) !default; // Lighter darkest -$ui-primary-color: $classic-primary-color !default; // Lighter -$ui-secondary-color: $classic-secondary-color !default; // Lightest -$ui-highlight-color: $classic-highlight-color !default; // Vibrant - -// Avatar border size (8% default, 100% for rounded avatars) -$ui-avatar-border-size: 8%; diff --git a/app/javascript/styles/variables-glitch.scss b/app/javascript/styles/variables-glitch.scss deleted file mode 100644 index 44d3322f2..000000000 --- a/app/javascript/styles/variables-glitch.scss +++ /dev/null @@ -1,3 +0,0 @@ -// glitch-soc added variables - -$dismiss-overlay-width: 4rem; -- cgit From e19fc6a9f81e3756e0198006d2eafbc2f3acadb5 Mon Sep 17 00:00:00 2001 From: kibigo! Date: Fri, 17 Nov 2017 19:16:35 -0800 Subject: Restore vanilla components --- app/javascript/mastodon/actions/accounts.js | 659 +++ app/javascript/mastodon/actions/alerts.js | 24 + app/javascript/mastodon/actions/blocks.js | 82 + app/javascript/mastodon/actions/bundles.js | 25 + app/javascript/mastodon/actions/cards.js | 52 + app/javascript/mastodon/actions/columns.js | 40 + app/javascript/mastodon/actions/compose.js | 376 ++ app/javascript/mastodon/actions/domain_blocks.js | 117 + app/javascript/mastodon/actions/emojis.js | 14 + app/javascript/mastodon/actions/favourites.js | 83 + app/javascript/mastodon/actions/height_cache.js | 17 + app/javascript/mastodon/actions/interactions.js | 313 ++ app/javascript/mastodon/actions/modal.js | 16 + app/javascript/mastodon/actions/mutes.js | 103 + app/javascript/mastodon/actions/notifications.js | 190 + app/javascript/mastodon/actions/onboarding.js | 14 + app/javascript/mastodon/actions/pin_statuses.js | 40 + .../mastodon/actions/push_notifications.js | 52 + app/javascript/mastodon/actions/reports.js | 80 + app/javascript/mastodon/actions/search.js | 73 + app/javascript/mastodon/actions/settings.js | 31 + app/javascript/mastodon/actions/statuses.js | 217 + app/javascript/mastodon/actions/store.js | 17 + app/javascript/mastodon/actions/streaming.js | 53 + app/javascript/mastodon/actions/timelines.js | 206 + app/javascript/mastodon/api.js | 26 + app/javascript/mastodon/base_polyfills.js | 18 + .../__tests__/__snapshots__/avatar-test.js.snap | 33 + .../__snapshots__/avatar_overlay-test.js.snap | 24 + .../__tests__/__snapshots__/button-test.js.snap | 114 + .../__snapshots__/display_name-test.js.snap | 23 + .../mastodon/components/__tests__/avatar-test.js | 36 + .../components/__tests__/avatar_overlay-test.js | 29 + .../mastodon/components/__tests__/button-test.js | 75 + .../components/__tests__/display_name-test.js | 18 + app/javascript/mastodon/components/account.js | 116 + .../mastodon/components/attachment_list.js | 33 + .../mastodon/components/autosuggest_emoji.js | 42 + .../mastodon/components/autosuggest_textarea.js | 222 + app/javascript/mastodon/components/avatar.js | 71 + .../mastodon/components/avatar_overlay.js | 30 + app/javascript/mastodon/components/button.js | 63 + app/javascript/mastodon/components/collapsable.js | 22 + app/javascript/mastodon/components/column.js | 52 + .../mastodon/components/column_back_button.js | 28 + .../mastodon/components/column_back_button_slim.js | 27 + .../mastodon/components/column_header.js | 159 + app/javascript/mastodon/components/display_name.js | 20 + .../mastodon/components/dropdown_menu.js | 211 + .../mastodon/components/extended_video_player.js | 54 + app/javascript/mastodon/components/icon_button.js | 114 + .../components/intersection_observer_article.js | 130 + app/javascript/mastodon/components/load_more.js | 26 + .../mastodon/components/loading_indicator.js | 11 + .../mastodon/components/media_gallery.js | 278 ++ .../mastodon/components/missing_indicator.js | 12 + app/javascript/mastodon/components/permalink.js | 34 + .../mastodon/components/relative_timestamp.js | 147 + .../mastodon/components/scrollable_list.js | 198 + app/javascript/mastodon/components/setting_text.js | 34 + app/javascript/mastodon/components/status.js | 246 ++ .../mastodon/components/status_action_bar.js | 188 + .../mastodon/components/status_content.js | 185 + app/javascript/mastodon/components/status_list.js | 72 + .../mastodon/containers/account_container.js | 72 + .../mastodon/containers/card_container.js | 18 + .../mastodon/containers/compose_container.js | 38 + .../mastodon/containers/dropdown_menu_container.js | 16 + .../intersection_observer_article_container.js | 17 + app/javascript/mastodon/containers/mastodon.js | 70 + .../mastodon/containers/media_gallery_container.js | 34 + .../mastodon/containers/status_container.js | 133 + .../mastodon/containers/timeline_container.js | 48 + .../mastodon/containers/video_container.js | 26 + app/javascript/mastodon/extra_polyfills.js | 5 + .../features/account/components/action_bar.js | 133 + .../mastodon/features/account/components/header.js | 128 + .../account_gallery/components/media_item.js | 39 + .../mastodon/features/account_gallery/index.js | 111 + .../features/account_timeline/components/header.js | 89 + .../containers/header_container.js | 96 + .../mastodon/features/account_timeline/index.js | 77 + app/javascript/mastodon/features/blocks/index.js | 70 + .../components/column_settings.js | 35 + .../containers/column_settings_container.js | 17 + .../mastodon/features/community_timeline/index.js | 107 + .../compose/components/autosuggest_account.js | 24 + .../compose/components/character_counter.js | 25 + .../features/compose/components/compose_form.js | 212 + .../compose/components/emoji_picker_dropdown.js | 376 ++ .../features/compose/components/navigation_bar.js | 38 + .../compose/components/privacy_dropdown.js | 200 + .../features/compose/components/reply_indicator.js | 63 + .../mastodon/features/compose/components/search.js | 129 + .../features/compose/components/search_results.js | 65 + .../compose/components/text_icon_button.js | 29 + .../mastodon/features/compose/components/upload.js | 96 + .../features/compose/components/upload_button.js | 77 + .../features/compose/components/upload_form.js | 29 + .../features/compose/components/upload_progress.js | 42 + .../features/compose/components/warning.js | 26 + .../containers/autosuggest_account_container.js | 15 + .../compose/containers/compose_form_container.js | 64 + .../containers/emoji_picker_dropdown_container.js | 82 + .../compose/containers/navigation_container.js | 11 + .../containers/privacy_dropdown_container.js | 24 + .../containers/reply_indicator_container.js | 24 + .../compose/containers/search_container.js | 35 + .../compose/containers/search_results_container.js | 8 + .../containers/sensitive_button_container.js | 71 + .../compose/containers/spoiler_button_container.js | 25 + .../compose/containers/upload_button_container.js | 18 + .../compose/containers/upload_container.js | 21 + .../compose/containers/upload_form_container.js | 8 + .../containers/upload_progress_container.js | 9 + .../compose/containers/warning_container.js | 24 + app/javascript/mastodon/features/compose/index.js | 111 + .../mastodon/features/compose/util/counter.js | 9 + .../mastodon/features/compose/util/url_regex.js | 196 + .../features/emoji/__tests__/emoji-test.js | 77 + .../features/emoji/__tests__/emoji_index-test.js | 130 + app/javascript/mastodon/features/emoji/emoji.js | 95 + .../mastodon/features/emoji/emoji_compressed.js | 93 + .../mastodon/features/emoji/emoji_map.json | 1 + .../features/emoji/emoji_mart_data_light.js | 41 + .../features/emoji/emoji_mart_search_light.js | 157 + .../mastodon/features/emoji/emoji_picker.js | 7 + .../features/emoji/emoji_unicode_mapping_light.js | 35 + .../mastodon/features/emoji/emoji_utils.js | 258 ++ .../mastodon/features/emoji/unicode_to_filename.js | 26 + .../features/emoji/unicode_to_unified_name.js | 17 + .../mastodon/features/favourited_statuses/index.js | 94 + .../mastodon/features/favourites/index.js | 60 + .../components/account_authorize.js | 49 + .../containers/account_authorize_container.js | 26 + .../mastodon/features/follow_requests/index.js | 71 + .../mastodon/features/followers/index.js | 93 + .../mastodon/features/following/index.js | 93 + .../mastodon/features/generic_not_found/index.js | 11 + .../mastodon/features/getting_started/index.js | 112 + .../mastodon/features/hashtag_timeline/index.js | 118 + .../home_timeline/components/column_settings.js | 46 + .../containers/column_settings_container.js | 21 + .../mastodon/features/home_timeline/index.js | 90 + app/javascript/mastodon/features/mutes/index.js | 70 + .../components/clear_column_button.js | 17 + .../notifications/components/column_settings.js | 86 + .../notifications/components/notification.js | 152 + .../notifications/components/setting_toggle.js | 34 + .../containers/column_settings_container.js | 44 + .../containers/notification_container.js | 22 + .../mastodon/features/notifications/index.js | 168 + .../mastodon/features/pinned_statuses/index.js | 59 + .../containers/column_settings_container.js | 17 + .../mastodon/features/public_timeline/index.js | 107 + app/javascript/mastodon/features/reblogs/index.js | 60 + .../features/report/components/status_check_box.js | 37 + .../containers/status_check_box_container.js | 19 + .../mastodon/features/standalone/compose/index.js | 20 + .../features/standalone/hashtag_timeline/index.js | 70 + .../features/standalone/public_timeline/index.js | 76 + .../features/status/components/action_bar.js | 129 + .../mastodon/features/status/components/card.js | 125 + .../features/status/components/detailed_status.js | 125 + .../features/status/containers/card_container.js | 8 + app/javascript/mastodon/features/status/index.js | 338 ++ .../ui/components/__tests__/column-test.js | 34 + .../features/ui/components/actions_modal.js | 74 + .../mastodon/features/ui/components/boost_modal.js | 84 + .../mastodon/features/ui/components/bundle.js | 102 + .../features/ui/components/bundle_column_error.js | 44 + .../features/ui/components/bundle_modal_error.js | 53 + .../mastodon/features/ui/components/column.js | 72 + .../features/ui/components/column_header.js | 35 + .../mastodon/features/ui/components/column_link.js | 32 + .../features/ui/components/column_loading.js | 30 + .../features/ui/components/column_subheading.js | 16 + .../features/ui/components/columns_area.js | 173 + .../features/ui/components/confirmation_modal.js | 53 + .../features/ui/components/drawer_loading.js | 11 + .../mastodon/features/ui/components/embed_modal.js | 84 + .../features/ui/components/image_loader.js | 152 + .../mastodon/features/ui/components/media_modal.js | 126 + .../features/ui/components/modal_loading.js | 20 + .../mastodon/features/ui/components/modal_root.js | 127 + .../mastodon/features/ui/components/mute_modal.js | 105 + .../features/ui/components/onboarding_modal.js | 318 ++ .../features/ui/components/report_modal.js | 105 + .../mastodon/features/ui/components/tabs_bar.js | 84 + .../mastodon/features/ui/components/upload_area.js | 52 + .../mastodon/features/ui/components/video_modal.js | 33 + .../features/ui/containers/bundle_container.js | 19 + .../ui/containers/columns_area_container.js | 8 + .../ui/containers/loading_bar_container.js | 8 + .../features/ui/containers/modal_container.js | 16 + .../ui/containers/notifications_container.js | 18 + .../ui/containers/status_list_container.js | 73 + app/javascript/mastodon/features/ui/index.js | 407 ++ .../mastodon/features/ui/util/async-components.js | 107 + .../mastodon/features/ui/util/fullscreen.js | 46 + .../features/ui/util/get_rect_from_entry.js | 21 + .../ui/util/intersection_observer_wrapper.js | 57 + .../mastodon/features/ui/util/optional_motion.js | 5 + .../features/ui/util/react_router_helpers.js | 64 + .../mastodon/features/ui/util/reduced_motion.js | 44 + .../features/ui/util/schedule_idle_task.js | 29 + app/javascript/mastodon/features/video/index.js | 286 ++ app/javascript/mastodon/initial_state.js | 13 + app/javascript/mastodon/is_mobile.js | 27 + app/javascript/mastodon/link_header.js | 33 + app/javascript/mastodon/load_polyfills.js | 39 + .../mastodon/locales/defaultMessages.json | 17 - app/javascript/mastodon/locales/en.json | 3 - app/javascript/mastodon/main.js | 34 + app/javascript/mastodon/middleware/errors.js | 31 + app/javascript/mastodon/middleware/loading_bar.js | 25 + app/javascript/mastodon/middleware/sounds.js | 46 + app/javascript/mastodon/performance.js | 31 + app/javascript/mastodon/ready.js | 7 + app/javascript/mastodon/reducers/accounts.js | 135 + .../mastodon/reducers/accounts_counters.js | 135 + app/javascript/mastodon/reducers/alerts.js | 25 + app/javascript/mastodon/reducers/cards.js | 14 + app/javascript/mastodon/reducers/compose.js | 276 ++ app/javascript/mastodon/reducers/contexts.js | 61 + app/javascript/mastodon/reducers/custom_emojis.js | 16 + app/javascript/mastodon/reducers/height_cache.js | 23 + app/javascript/mastodon/reducers/index.js | 52 + .../mastodon/reducers/media_attachments.js | 15 + app/javascript/mastodon/reducers/meta.js | 16 + app/javascript/mastodon/reducers/modal.js | 17 + app/javascript/mastodon/reducers/mutes.js | 29 + app/javascript/mastodon/reducers/notifications.js | 124 + .../mastodon/reducers/push_notifications.js | 51 + app/javascript/mastodon/reducers/relationships.js | 46 + app/javascript/mastodon/reducers/reports.js | 60 + app/javascript/mastodon/reducers/search.js | 42 + app/javascript/mastodon/reducers/settings.js | 112 + app/javascript/mastodon/reducers/status_lists.js | 75 + app/javascript/mastodon/reducers/statuses.js | 148 + app/javascript/mastodon/reducers/timelines.js | 149 + app/javascript/mastodon/reducers/user_lists.js | 80 + app/javascript/mastodon/rtl.js | 31 + app/javascript/mastodon/scroll.js | 30 + app/javascript/mastodon/selectors/index.js | 87 + app/javascript/mastodon/service_worker/entry.js | 10 + .../service_worker/web_push_notifications.js | 159 + app/javascript/mastodon/store/configureStore.js | 15 + app/javascript/mastodon/stream.js | 73 + app/javascript/mastodon/test_setup.js | 5 + app/javascript/mastodon/uuid.js | 3 + app/javascript/mastodon/web_push_subscription.js | 105 + app/javascript/styles/application.scss | 22 + app/javascript/styles/mastodon/_mixins.scss | 12 + app/javascript/styles/mastodon/about.scss | 824 ++++ app/javascript/styles/mastodon/accounts.scss | 549 +++ app/javascript/styles/mastodon/admin.scss | 349 ++ app/javascript/styles/mastodon/basics.scss | 122 + app/javascript/styles/mastodon/boost.scss | 18 + app/javascript/styles/mastodon/compact_header.scss | 34 + app/javascript/styles/mastodon/components.scss | 4377 ++++++++++++++++++++ app/javascript/styles/mastodon/containers.scss | 116 + app/javascript/styles/mastodon/emoji_picker.scss | 199 + app/javascript/styles/mastodon/footer.scss | 30 + app/javascript/styles/mastodon/forms.scss | 540 +++ app/javascript/styles/mastodon/landing_strip.scss | 36 + app/javascript/styles/mastodon/lists.scss | 19 + app/javascript/styles/mastodon/reset.scss | 91 + app/javascript/styles/mastodon/rtl.scss | 254 ++ app/javascript/styles/mastodon/stream_entries.scss | 339 ++ app/javascript/styles/mastodon/tables.scss | 76 + app/javascript/styles/mastodon/variables.scss | 29 + 272 files changed, 27052 insertions(+), 20 deletions(-) create mode 100644 app/javascript/mastodon/actions/accounts.js create mode 100644 app/javascript/mastodon/actions/alerts.js create mode 100644 app/javascript/mastodon/actions/blocks.js create mode 100644 app/javascript/mastodon/actions/bundles.js create mode 100644 app/javascript/mastodon/actions/cards.js create mode 100644 app/javascript/mastodon/actions/columns.js create mode 100644 app/javascript/mastodon/actions/compose.js create mode 100644 app/javascript/mastodon/actions/domain_blocks.js create mode 100644 app/javascript/mastodon/actions/emojis.js create mode 100644 app/javascript/mastodon/actions/favourites.js create mode 100644 app/javascript/mastodon/actions/height_cache.js create mode 100644 app/javascript/mastodon/actions/interactions.js create mode 100644 app/javascript/mastodon/actions/modal.js create mode 100644 app/javascript/mastodon/actions/mutes.js create mode 100644 app/javascript/mastodon/actions/notifications.js create mode 100644 app/javascript/mastodon/actions/onboarding.js create mode 100644 app/javascript/mastodon/actions/pin_statuses.js create mode 100644 app/javascript/mastodon/actions/push_notifications.js create mode 100644 app/javascript/mastodon/actions/reports.js create mode 100644 app/javascript/mastodon/actions/search.js create mode 100644 app/javascript/mastodon/actions/settings.js create mode 100644 app/javascript/mastodon/actions/statuses.js create mode 100644 app/javascript/mastodon/actions/store.js create mode 100644 app/javascript/mastodon/actions/streaming.js create mode 100644 app/javascript/mastodon/actions/timelines.js create mode 100644 app/javascript/mastodon/api.js create mode 100644 app/javascript/mastodon/base_polyfills.js create mode 100644 app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap create mode 100644 app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap create mode 100644 app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap create mode 100644 app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap create mode 100644 app/javascript/mastodon/components/__tests__/avatar-test.js create mode 100644 app/javascript/mastodon/components/__tests__/avatar_overlay-test.js create mode 100644 app/javascript/mastodon/components/__tests__/button-test.js create mode 100644 app/javascript/mastodon/components/__tests__/display_name-test.js create mode 100644 app/javascript/mastodon/components/account.js create mode 100644 app/javascript/mastodon/components/attachment_list.js create mode 100644 app/javascript/mastodon/components/autosuggest_emoji.js create mode 100644 app/javascript/mastodon/components/autosuggest_textarea.js create mode 100644 app/javascript/mastodon/components/avatar.js create mode 100644 app/javascript/mastodon/components/avatar_overlay.js create mode 100644 app/javascript/mastodon/components/button.js create mode 100644 app/javascript/mastodon/components/collapsable.js create mode 100644 app/javascript/mastodon/components/column.js create mode 100644 app/javascript/mastodon/components/column_back_button.js create mode 100644 app/javascript/mastodon/components/column_back_button_slim.js create mode 100644 app/javascript/mastodon/components/column_header.js create mode 100644 app/javascript/mastodon/components/display_name.js create mode 100644 app/javascript/mastodon/components/dropdown_menu.js create mode 100644 app/javascript/mastodon/components/extended_video_player.js create mode 100644 app/javascript/mastodon/components/icon_button.js create mode 100644 app/javascript/mastodon/components/intersection_observer_article.js create mode 100644 app/javascript/mastodon/components/load_more.js create mode 100644 app/javascript/mastodon/components/loading_indicator.js create mode 100644 app/javascript/mastodon/components/media_gallery.js create mode 100644 app/javascript/mastodon/components/missing_indicator.js create mode 100644 app/javascript/mastodon/components/permalink.js create mode 100644 app/javascript/mastodon/components/relative_timestamp.js create mode 100644 app/javascript/mastodon/components/scrollable_list.js create mode 100644 app/javascript/mastodon/components/setting_text.js create mode 100644 app/javascript/mastodon/components/status.js create mode 100644 app/javascript/mastodon/components/status_action_bar.js create mode 100644 app/javascript/mastodon/components/status_content.js create mode 100644 app/javascript/mastodon/components/status_list.js create mode 100644 app/javascript/mastodon/containers/account_container.js create mode 100644 app/javascript/mastodon/containers/card_container.js create mode 100644 app/javascript/mastodon/containers/compose_container.js create mode 100644 app/javascript/mastodon/containers/dropdown_menu_container.js create mode 100644 app/javascript/mastodon/containers/intersection_observer_article_container.js create mode 100644 app/javascript/mastodon/containers/mastodon.js create mode 100644 app/javascript/mastodon/containers/media_gallery_container.js create mode 100644 app/javascript/mastodon/containers/status_container.js create mode 100644 app/javascript/mastodon/containers/timeline_container.js create mode 100644 app/javascript/mastodon/containers/video_container.js create mode 100644 app/javascript/mastodon/extra_polyfills.js create mode 100644 app/javascript/mastodon/features/account/components/action_bar.js create mode 100644 app/javascript/mastodon/features/account/components/header.js create mode 100644 app/javascript/mastodon/features/account_gallery/components/media_item.js create mode 100644 app/javascript/mastodon/features/account_gallery/index.js create mode 100644 app/javascript/mastodon/features/account_timeline/components/header.js create mode 100644 app/javascript/mastodon/features/account_timeline/containers/header_container.js create mode 100644 app/javascript/mastodon/features/account_timeline/index.js create mode 100644 app/javascript/mastodon/features/blocks/index.js create mode 100644 app/javascript/mastodon/features/community_timeline/components/column_settings.js create mode 100644 app/javascript/mastodon/features/community_timeline/containers/column_settings_container.js create mode 100644 app/javascript/mastodon/features/community_timeline/index.js create mode 100644 app/javascript/mastodon/features/compose/components/autosuggest_account.js create mode 100644 app/javascript/mastodon/features/compose/components/character_counter.js create mode 100644 app/javascript/mastodon/features/compose/components/compose_form.js create mode 100644 app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js create mode 100644 app/javascript/mastodon/features/compose/components/navigation_bar.js create mode 100644 app/javascript/mastodon/features/compose/components/privacy_dropdown.js create mode 100644 app/javascript/mastodon/features/compose/components/reply_indicator.js create mode 100644 app/javascript/mastodon/features/compose/components/search.js create mode 100644 app/javascript/mastodon/features/compose/components/search_results.js create mode 100644 app/javascript/mastodon/features/compose/components/text_icon_button.js create mode 100644 app/javascript/mastodon/features/compose/components/upload.js create mode 100644 app/javascript/mastodon/features/compose/components/upload_button.js create mode 100644 app/javascript/mastodon/features/compose/components/upload_form.js create mode 100644 app/javascript/mastodon/features/compose/components/upload_progress.js create mode 100644 app/javascript/mastodon/features/compose/components/warning.js create mode 100644 app/javascript/mastodon/features/compose/containers/autosuggest_account_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/compose_form_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/navigation_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/reply_indicator_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/search_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/search_results_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/sensitive_button_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/spoiler_button_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/upload_button_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/upload_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/upload_form_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/upload_progress_container.js create mode 100644 app/javascript/mastodon/features/compose/containers/warning_container.js create mode 100644 app/javascript/mastodon/features/compose/index.js create mode 100644 app/javascript/mastodon/features/compose/util/counter.js create mode 100644 app/javascript/mastodon/features/compose/util/url_regex.js create mode 100644 app/javascript/mastodon/features/emoji/__tests__/emoji-test.js create mode 100644 app/javascript/mastodon/features/emoji/__tests__/emoji_index-test.js create mode 100644 app/javascript/mastodon/features/emoji/emoji.js create mode 100644 app/javascript/mastodon/features/emoji/emoji_compressed.js create mode 100644 app/javascript/mastodon/features/emoji/emoji_map.json create mode 100644 app/javascript/mastodon/features/emoji/emoji_mart_data_light.js create mode 100644 app/javascript/mastodon/features/emoji/emoji_mart_search_light.js create mode 100644 app/javascript/mastodon/features/emoji/emoji_picker.js create mode 100644 app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.js create mode 100644 app/javascript/mastodon/features/emoji/emoji_utils.js create mode 100644 app/javascript/mastodon/features/emoji/unicode_to_filename.js create mode 100644 app/javascript/mastodon/features/emoji/unicode_to_unified_name.js create mode 100644 app/javascript/mastodon/features/favourited_statuses/index.js create mode 100644 app/javascript/mastodon/features/favourites/index.js create mode 100644 app/javascript/mastodon/features/follow_requests/components/account_authorize.js create mode 100644 app/javascript/mastodon/features/follow_requests/containers/account_authorize_container.js create mode 100644 app/javascript/mastodon/features/follow_requests/index.js create mode 100644 app/javascript/mastodon/features/followers/index.js create mode 100644 app/javascript/mastodon/features/following/index.js create mode 100644 app/javascript/mastodon/features/generic_not_found/index.js create mode 100644 app/javascript/mastodon/features/getting_started/index.js create mode 100644 app/javascript/mastodon/features/hashtag_timeline/index.js create mode 100644 app/javascript/mastodon/features/home_timeline/components/column_settings.js create mode 100644 app/javascript/mastodon/features/home_timeline/containers/column_settings_container.js create mode 100644 app/javascript/mastodon/features/home_timeline/index.js create mode 100644 app/javascript/mastodon/features/mutes/index.js create mode 100644 app/javascript/mastodon/features/notifications/components/clear_column_button.js create mode 100644 app/javascript/mastodon/features/notifications/components/column_settings.js create mode 100644 app/javascript/mastodon/features/notifications/components/notification.js create mode 100644 app/javascript/mastodon/features/notifications/components/setting_toggle.js create mode 100644 app/javascript/mastodon/features/notifications/containers/column_settings_container.js create mode 100644 app/javascript/mastodon/features/notifications/containers/notification_container.js create mode 100644 app/javascript/mastodon/features/notifications/index.js create mode 100644 app/javascript/mastodon/features/pinned_statuses/index.js create mode 100644 app/javascript/mastodon/features/public_timeline/containers/column_settings_container.js create mode 100644 app/javascript/mastodon/features/public_timeline/index.js create mode 100644 app/javascript/mastodon/features/reblogs/index.js create mode 100644 app/javascript/mastodon/features/report/components/status_check_box.js create mode 100644 app/javascript/mastodon/features/report/containers/status_check_box_container.js create mode 100644 app/javascript/mastodon/features/standalone/compose/index.js create mode 100644 app/javascript/mastodon/features/standalone/hashtag_timeline/index.js create mode 100644 app/javascript/mastodon/features/standalone/public_timeline/index.js create mode 100644 app/javascript/mastodon/features/status/components/action_bar.js create mode 100644 app/javascript/mastodon/features/status/components/card.js create mode 100644 app/javascript/mastodon/features/status/components/detailed_status.js create mode 100644 app/javascript/mastodon/features/status/containers/card_container.js create mode 100644 app/javascript/mastodon/features/status/index.js create mode 100644 app/javascript/mastodon/features/ui/components/__tests__/column-test.js create mode 100644 app/javascript/mastodon/features/ui/components/actions_modal.js create mode 100644 app/javascript/mastodon/features/ui/components/boost_modal.js create mode 100644 app/javascript/mastodon/features/ui/components/bundle.js create mode 100644 app/javascript/mastodon/features/ui/components/bundle_column_error.js create mode 100644 app/javascript/mastodon/features/ui/components/bundle_modal_error.js create mode 100644 app/javascript/mastodon/features/ui/components/column.js create mode 100644 app/javascript/mastodon/features/ui/components/column_header.js create mode 100644 app/javascript/mastodon/features/ui/components/column_link.js create mode 100644 app/javascript/mastodon/features/ui/components/column_loading.js create mode 100644 app/javascript/mastodon/features/ui/components/column_subheading.js create mode 100644 app/javascript/mastodon/features/ui/components/columns_area.js create mode 100644 app/javascript/mastodon/features/ui/components/confirmation_modal.js create mode 100644 app/javascript/mastodon/features/ui/components/drawer_loading.js create mode 100644 app/javascript/mastodon/features/ui/components/embed_modal.js create mode 100644 app/javascript/mastodon/features/ui/components/image_loader.js create mode 100644 app/javascript/mastodon/features/ui/components/media_modal.js create mode 100644 app/javascript/mastodon/features/ui/components/modal_loading.js create mode 100644 app/javascript/mastodon/features/ui/components/modal_root.js create mode 100644 app/javascript/mastodon/features/ui/components/mute_modal.js create mode 100644 app/javascript/mastodon/features/ui/components/onboarding_modal.js create mode 100644 app/javascript/mastodon/features/ui/components/report_modal.js create mode 100644 app/javascript/mastodon/features/ui/components/tabs_bar.js create mode 100644 app/javascript/mastodon/features/ui/components/upload_area.js create mode 100644 app/javascript/mastodon/features/ui/components/video_modal.js create mode 100644 app/javascript/mastodon/features/ui/containers/bundle_container.js create mode 100644 app/javascript/mastodon/features/ui/containers/columns_area_container.js create mode 100644 app/javascript/mastodon/features/ui/containers/loading_bar_container.js create mode 100644 app/javascript/mastodon/features/ui/containers/modal_container.js create mode 100644 app/javascript/mastodon/features/ui/containers/notifications_container.js create mode 100644 app/javascript/mastodon/features/ui/containers/status_list_container.js create mode 100644 app/javascript/mastodon/features/ui/index.js create mode 100644 app/javascript/mastodon/features/ui/util/async-components.js create mode 100644 app/javascript/mastodon/features/ui/util/fullscreen.js create mode 100644 app/javascript/mastodon/features/ui/util/get_rect_from_entry.js create mode 100644 app/javascript/mastodon/features/ui/util/intersection_observer_wrapper.js create mode 100644 app/javascript/mastodon/features/ui/util/optional_motion.js create mode 100644 app/javascript/mastodon/features/ui/util/react_router_helpers.js create mode 100644 app/javascript/mastodon/features/ui/util/reduced_motion.js create mode 100644 app/javascript/mastodon/features/ui/util/schedule_idle_task.js create mode 100644 app/javascript/mastodon/features/video/index.js create mode 100644 app/javascript/mastodon/initial_state.js create mode 100644 app/javascript/mastodon/is_mobile.js create mode 100644 app/javascript/mastodon/link_header.js create mode 100644 app/javascript/mastodon/load_polyfills.js create mode 100644 app/javascript/mastodon/main.js create mode 100644 app/javascript/mastodon/middleware/errors.js create mode 100644 app/javascript/mastodon/middleware/loading_bar.js create mode 100644 app/javascript/mastodon/middleware/sounds.js create mode 100644 app/javascript/mastodon/performance.js create mode 100644 app/javascript/mastodon/ready.js create mode 100644 app/javascript/mastodon/reducers/accounts.js create mode 100644 app/javascript/mastodon/reducers/accounts_counters.js create mode 100644 app/javascript/mastodon/reducers/alerts.js create mode 100644 app/javascript/mastodon/reducers/cards.js create mode 100644 app/javascript/mastodon/reducers/compose.js create mode 100644 app/javascript/mastodon/reducers/contexts.js create mode 100644 app/javascript/mastodon/reducers/custom_emojis.js create mode 100644 app/javascript/mastodon/reducers/height_cache.js create mode 100644 app/javascript/mastodon/reducers/index.js create mode 100644 app/javascript/mastodon/reducers/media_attachments.js create mode 100644 app/javascript/mastodon/reducers/meta.js create mode 100644 app/javascript/mastodon/reducers/modal.js create mode 100644 app/javascript/mastodon/reducers/mutes.js create mode 100644 app/javascript/mastodon/reducers/notifications.js create mode 100644 app/javascript/mastodon/reducers/push_notifications.js create mode 100644 app/javascript/mastodon/reducers/relationships.js create mode 100644 app/javascript/mastodon/reducers/reports.js create mode 100644 app/javascript/mastodon/reducers/search.js create mode 100644 app/javascript/mastodon/reducers/settings.js create mode 100644 app/javascript/mastodon/reducers/status_lists.js create mode 100644 app/javascript/mastodon/reducers/statuses.js create mode 100644 app/javascript/mastodon/reducers/timelines.js create mode 100644 app/javascript/mastodon/reducers/user_lists.js create mode 100644 app/javascript/mastodon/rtl.js create mode 100644 app/javascript/mastodon/scroll.js create mode 100644 app/javascript/mastodon/selectors/index.js create mode 100644 app/javascript/mastodon/service_worker/entry.js create mode 100644 app/javascript/mastodon/service_worker/web_push_notifications.js create mode 100644 app/javascript/mastodon/store/configureStore.js create mode 100644 app/javascript/mastodon/stream.js create mode 100644 app/javascript/mastodon/test_setup.js create mode 100644 app/javascript/mastodon/uuid.js create mode 100644 app/javascript/mastodon/web_push_subscription.js create mode 100644 app/javascript/styles/application.scss create mode 100644 app/javascript/styles/mastodon/_mixins.scss create mode 100644 app/javascript/styles/mastodon/about.scss create mode 100644 app/javascript/styles/mastodon/accounts.scss create mode 100644 app/javascript/styles/mastodon/admin.scss create mode 100644 app/javascript/styles/mastodon/basics.scss create mode 100644 app/javascript/styles/mastodon/boost.scss create mode 100644 app/javascript/styles/mastodon/compact_header.scss create mode 100644 app/javascript/styles/mastodon/components.scss create mode 100644 app/javascript/styles/mastodon/containers.scss create mode 100644 app/javascript/styles/mastodon/emoji_picker.scss create mode 100644 app/javascript/styles/mastodon/footer.scss create mode 100644 app/javascript/styles/mastodon/forms.scss create mode 100644 app/javascript/styles/mastodon/landing_strip.scss create mode 100644 app/javascript/styles/mastodon/lists.scss create mode 100644 app/javascript/styles/mastodon/reset.scss create mode 100644 app/javascript/styles/mastodon/rtl.scss create mode 100644 app/javascript/styles/mastodon/stream_entries.scss create mode 100644 app/javascript/styles/mastodon/tables.scss create mode 100644 app/javascript/styles/mastodon/variables.scss (limited to 'app/javascript/styles') diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js new file mode 100644 index 000000000..fbaebf786 --- /dev/null +++ b/app/javascript/mastodon/actions/accounts.js @@ -0,0 +1,659 @@ +import api, { getLinks } from '../api'; + +export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST'; +export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS'; +export const ACCOUNT_FETCH_FAIL = 'ACCOUNT_FETCH_FAIL'; + +export const ACCOUNT_FOLLOW_REQUEST = 'ACCOUNT_FOLLOW_REQUEST'; +export const ACCOUNT_FOLLOW_SUCCESS = 'ACCOUNT_FOLLOW_SUCCESS'; +export const ACCOUNT_FOLLOW_FAIL = 'ACCOUNT_FOLLOW_FAIL'; + +export const ACCOUNT_UNFOLLOW_REQUEST = 'ACCOUNT_UNFOLLOW_REQUEST'; +export const ACCOUNT_UNFOLLOW_SUCCESS = 'ACCOUNT_UNFOLLOW_SUCCESS'; +export const ACCOUNT_UNFOLLOW_FAIL = 'ACCOUNT_UNFOLLOW_FAIL'; + +export const ACCOUNT_BLOCK_REQUEST = 'ACCOUNT_BLOCK_REQUEST'; +export const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS'; +export const ACCOUNT_BLOCK_FAIL = 'ACCOUNT_BLOCK_FAIL'; + +export const ACCOUNT_UNBLOCK_REQUEST = 'ACCOUNT_UNBLOCK_REQUEST'; +export const ACCOUNT_UNBLOCK_SUCCESS = 'ACCOUNT_UNBLOCK_SUCCESS'; +export const ACCOUNT_UNBLOCK_FAIL = 'ACCOUNT_UNBLOCK_FAIL'; + +export const ACCOUNT_MUTE_REQUEST = 'ACCOUNT_MUTE_REQUEST'; +export const ACCOUNT_MUTE_SUCCESS = 'ACCOUNT_MUTE_SUCCESS'; +export const ACCOUNT_MUTE_FAIL = 'ACCOUNT_MUTE_FAIL'; + +export const ACCOUNT_UNMUTE_REQUEST = 'ACCOUNT_UNMUTE_REQUEST'; +export const ACCOUNT_UNMUTE_SUCCESS = 'ACCOUNT_UNMUTE_SUCCESS'; +export const ACCOUNT_UNMUTE_FAIL = 'ACCOUNT_UNMUTE_FAIL'; + +export const FOLLOWERS_FETCH_REQUEST = 'FOLLOWERS_FETCH_REQUEST'; +export const FOLLOWERS_FETCH_SUCCESS = 'FOLLOWERS_FETCH_SUCCESS'; +export const FOLLOWERS_FETCH_FAIL = 'FOLLOWERS_FETCH_FAIL'; + +export const FOLLOWERS_EXPAND_REQUEST = 'FOLLOWERS_EXPAND_REQUEST'; +export const FOLLOWERS_EXPAND_SUCCESS = 'FOLLOWERS_EXPAND_SUCCESS'; +export const FOLLOWERS_EXPAND_FAIL = 'FOLLOWERS_EXPAND_FAIL'; + +export const FOLLOWING_FETCH_REQUEST = 'FOLLOWING_FETCH_REQUEST'; +export const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS'; +export const FOLLOWING_FETCH_FAIL = 'FOLLOWING_FETCH_FAIL'; + +export const FOLLOWING_EXPAND_REQUEST = 'FOLLOWING_EXPAND_REQUEST'; +export const FOLLOWING_EXPAND_SUCCESS = 'FOLLOWING_EXPAND_SUCCESS'; +export const FOLLOWING_EXPAND_FAIL = 'FOLLOWING_EXPAND_FAIL'; + +export const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST'; +export const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS'; +export const RELATIONSHIPS_FETCH_FAIL = 'RELATIONSHIPS_FETCH_FAIL'; + +export const FOLLOW_REQUESTS_FETCH_REQUEST = 'FOLLOW_REQUESTS_FETCH_REQUEST'; +export const FOLLOW_REQUESTS_FETCH_SUCCESS = 'FOLLOW_REQUESTS_FETCH_SUCCESS'; +export const FOLLOW_REQUESTS_FETCH_FAIL = 'FOLLOW_REQUESTS_FETCH_FAIL'; + +export const FOLLOW_REQUESTS_EXPAND_REQUEST = 'FOLLOW_REQUESTS_EXPAND_REQUEST'; +export const FOLLOW_REQUESTS_EXPAND_SUCCESS = 'FOLLOW_REQUESTS_EXPAND_SUCCESS'; +export const FOLLOW_REQUESTS_EXPAND_FAIL = 'FOLLOW_REQUESTS_EXPAND_FAIL'; + +export const FOLLOW_REQUEST_AUTHORIZE_REQUEST = 'FOLLOW_REQUEST_AUTHORIZE_REQUEST'; +export const FOLLOW_REQUEST_AUTHORIZE_SUCCESS = 'FOLLOW_REQUEST_AUTHORIZE_SUCCESS'; +export const FOLLOW_REQUEST_AUTHORIZE_FAIL = 'FOLLOW_REQUEST_AUTHORIZE_FAIL'; + +export const FOLLOW_REQUEST_REJECT_REQUEST = 'FOLLOW_REQUEST_REJECT_REQUEST'; +export const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS'; +export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL'; + +export function fetchAccount(id) { + return (dispatch, getState) => { + dispatch(fetchRelationships([id])); + + if (getState().getIn(['accounts', id], null) !== null) { + return; + } + + dispatch(fetchAccountRequest(id)); + + api(getState).get(`/api/v1/accounts/${id}`).then(response => { + dispatch(fetchAccountSuccess(response.data)); + }).catch(error => { + dispatch(fetchAccountFail(id, error)); + }); + }; +}; + +export function fetchAccountRequest(id) { + return { + type: ACCOUNT_FETCH_REQUEST, + id, + }; +}; + +export function fetchAccountSuccess(account) { + return { + type: ACCOUNT_FETCH_SUCCESS, + account, + }; +}; + +export function fetchAccountFail(id, error) { + return { + type: ACCOUNT_FETCH_FAIL, + id, + error, + skipAlert: true, + }; +}; + +export function followAccount(id) { + return (dispatch, getState) => { + dispatch(followAccountRequest(id)); + + api(getState).post(`/api/v1/accounts/${id}/follow`).then(response => { + dispatch(followAccountSuccess(response.data)); + }).catch(error => { + dispatch(followAccountFail(error)); + }); + }; +}; + +export function unfollowAccount(id) { + return (dispatch, getState) => { + dispatch(unfollowAccountRequest(id)); + + api(getState).post(`/api/v1/accounts/${id}/unfollow`).then(response => { + dispatch(unfollowAccountSuccess(response.data, getState().get('statuses'))); + }).catch(error => { + dispatch(unfollowAccountFail(error)); + }); + }; +}; + +export function followAccountRequest(id) { + return { + type: ACCOUNT_FOLLOW_REQUEST, + id, + }; +}; + +export function followAccountSuccess(relationship) { + return { + type: ACCOUNT_FOLLOW_SUCCESS, + relationship, + }; +}; + +export function followAccountFail(error) { + return { + type: ACCOUNT_FOLLOW_FAIL, + error, + }; +}; + +export function unfollowAccountRequest(id) { + return { + type: ACCOUNT_UNFOLLOW_REQUEST, + id, + }; +}; + +export function unfollowAccountSuccess(relationship, statuses) { + return { + type: ACCOUNT_UNFOLLOW_SUCCESS, + relationship, + statuses, + }; +}; + +export function unfollowAccountFail(error) { + return { + type: ACCOUNT_UNFOLLOW_FAIL, + error, + }; +}; + +export function blockAccount(id) { + return (dispatch, getState) => { + dispatch(blockAccountRequest(id)); + + api(getState).post(`/api/v1/accounts/${id}/block`).then(response => { + // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers + dispatch(blockAccountSuccess(response.data, getState().get('statuses'))); + }).catch(error => { + dispatch(blockAccountFail(id, error)); + }); + }; +}; + +export function unblockAccount(id) { + return (dispatch, getState) => { + dispatch(unblockAccountRequest(id)); + + api(getState).post(`/api/v1/accounts/${id}/unblock`).then(response => { + dispatch(unblockAccountSuccess(response.data)); + }).catch(error => { + dispatch(unblockAccountFail(id, error)); + }); + }; +}; + +export function blockAccountRequest(id) { + return { + type: ACCOUNT_BLOCK_REQUEST, + id, + }; +}; + +export function blockAccountSuccess(relationship, statuses) { + return { + type: ACCOUNT_BLOCK_SUCCESS, + relationship, + statuses, + }; +}; + +export function blockAccountFail(error) { + return { + type: ACCOUNT_BLOCK_FAIL, + error, + }; +}; + +export function unblockAccountRequest(id) { + return { + type: ACCOUNT_UNBLOCK_REQUEST, + id, + }; +}; + +export function unblockAccountSuccess(relationship) { + return { + type: ACCOUNT_UNBLOCK_SUCCESS, + relationship, + }; +}; + +export function unblockAccountFail(error) { + return { + type: ACCOUNT_UNBLOCK_FAIL, + error, + }; +}; + + +export function muteAccount(id, notifications) { + return (dispatch, getState) => { + dispatch(muteAccountRequest(id)); + + api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications }).then(response => { + // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers + dispatch(muteAccountSuccess(response.data, getState().get('statuses'))); + }).catch(error => { + dispatch(muteAccountFail(id, error)); + }); + }; +}; + +export function unmuteAccount(id) { + return (dispatch, getState) => { + dispatch(unmuteAccountRequest(id)); + + api(getState).post(`/api/v1/accounts/${id}/unmute`).then(response => { + dispatch(unmuteAccountSuccess(response.data)); + }).catch(error => { + dispatch(unmuteAccountFail(id, error)); + }); + }; +}; + +export function muteAccountRequest(id) { + return { + type: ACCOUNT_MUTE_REQUEST, + id, + }; +}; + +export function muteAccountSuccess(relationship, statuses) { + return { + type: ACCOUNT_MUTE_SUCCESS, + relationship, + statuses, + }; +}; + +export function muteAccountFail(error) { + return { + type: ACCOUNT_MUTE_FAIL, + error, + }; +}; + +export function unmuteAccountRequest(id) { + return { + type: ACCOUNT_UNMUTE_REQUEST, + id, + }; +}; + +export function unmuteAccountSuccess(relationship) { + return { + type: ACCOUNT_UNMUTE_SUCCESS, + relationship, + }; +}; + +export function unmuteAccountFail(error) { + return { + type: ACCOUNT_UNMUTE_FAIL, + error, + }; +}; + + +export function fetchFollowers(id) { + return (dispatch, getState) => { + dispatch(fetchFollowersRequest(id)); + + api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + + dispatch(fetchFollowersSuccess(id, response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => { + dispatch(fetchFollowersFail(id, error)); + }); + }; +}; + +export function fetchFollowersRequest(id) { + return { + type: FOLLOWERS_FETCH_REQUEST, + id, + }; +}; + +export function fetchFollowersSuccess(id, accounts, next) { + return { + type: FOLLOWERS_FETCH_SUCCESS, + id, + accounts, + next, + }; +}; + +export function fetchFollowersFail(id, error) { + return { + type: FOLLOWERS_FETCH_FAIL, + id, + error, + }; +}; + +export function expandFollowers(id) { + return (dispatch, getState) => { + const url = getState().getIn(['user_lists', 'followers', id, 'next']); + + if (url === null) { + return; + } + + dispatch(expandFollowersRequest(id)); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + + dispatch(expandFollowersSuccess(id, response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => { + dispatch(expandFollowersFail(id, error)); + }); + }; +}; + +export function expandFollowersRequest(id) { + return { + type: FOLLOWERS_EXPAND_REQUEST, + id, + }; +}; + +export function expandFollowersSuccess(id, accounts, next) { + return { + type: FOLLOWERS_EXPAND_SUCCESS, + id, + accounts, + next, + }; +}; + +export function expandFollowersFail(id, error) { + return { + type: FOLLOWERS_EXPAND_FAIL, + id, + error, + }; +}; + +export function fetchFollowing(id) { + return (dispatch, getState) => { + dispatch(fetchFollowingRequest(id)); + + api(getState).get(`/api/v1/accounts/${id}/following`).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + + dispatch(fetchFollowingSuccess(id, response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => { + dispatch(fetchFollowingFail(id, error)); + }); + }; +}; + +export function fetchFollowingRequest(id) { + return { + type: FOLLOWING_FETCH_REQUEST, + id, + }; +}; + +export function fetchFollowingSuccess(id, accounts, next) { + return { + type: FOLLOWING_FETCH_SUCCESS, + id, + accounts, + next, + }; +}; + +export function fetchFollowingFail(id, error) { + return { + type: FOLLOWING_FETCH_FAIL, + id, + error, + }; +}; + +export function expandFollowing(id) { + return (dispatch, getState) => { + const url = getState().getIn(['user_lists', 'following', id, 'next']); + + if (url === null) { + return; + } + + dispatch(expandFollowingRequest(id)); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + + dispatch(expandFollowingSuccess(id, response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => { + dispatch(expandFollowingFail(id, error)); + }); + }; +}; + +export function expandFollowingRequest(id) { + return { + type: FOLLOWING_EXPAND_REQUEST, + id, + }; +}; + +export function expandFollowingSuccess(id, accounts, next) { + return { + type: FOLLOWING_EXPAND_SUCCESS, + id, + accounts, + next, + }; +}; + +export function expandFollowingFail(id, error) { + return { + type: FOLLOWING_EXPAND_FAIL, + id, + error, + }; +}; + +export function fetchRelationships(accountIds) { + return (dispatch, getState) => { + const loadedRelationships = getState().get('relationships'); + const newAccountIds = accountIds.filter(id => loadedRelationships.get(id, null) === null); + + if (newAccountIds.length === 0) { + return; + } + + dispatch(fetchRelationshipsRequest(newAccountIds)); + + api(getState).get(`/api/v1/accounts/relationships?${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => { + dispatch(fetchRelationshipsSuccess(response.data)); + }).catch(error => { + dispatch(fetchRelationshipsFail(error)); + }); + }; +}; + +export function fetchRelationshipsRequest(ids) { + return { + type: RELATIONSHIPS_FETCH_REQUEST, + ids, + skipLoading: true, + }; +}; + +export function fetchRelationshipsSuccess(relationships) { + return { + type: RELATIONSHIPS_FETCH_SUCCESS, + relationships, + skipLoading: true, + }; +}; + +export function fetchRelationshipsFail(error) { + return { + type: RELATIONSHIPS_FETCH_FAIL, + error, + skipLoading: true, + }; +}; + +export function fetchFollowRequests() { + return (dispatch, getState) => { + dispatch(fetchFollowRequestsRequest()); + + api(getState).get('/api/v1/follow_requests').then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null)); + }).catch(error => dispatch(fetchFollowRequestsFail(error))); + }; +}; + +export function fetchFollowRequestsRequest() { + return { + type: FOLLOW_REQUESTS_FETCH_REQUEST, + }; +}; + +export function fetchFollowRequestsSuccess(accounts, next) { + return { + type: FOLLOW_REQUESTS_FETCH_SUCCESS, + accounts, + next, + }; +}; + +export function fetchFollowRequestsFail(error) { + return { + type: FOLLOW_REQUESTS_FETCH_FAIL, + error, + }; +}; + +export function expandFollowRequests() { + return (dispatch, getState) => { + const url = getState().getIn(['user_lists', 'follow_requests', 'next']); + + if (url === null) { + return; + } + + dispatch(expandFollowRequestsRequest()); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null)); + }).catch(error => dispatch(expandFollowRequestsFail(error))); + }; +}; + +export function expandFollowRequestsRequest() { + return { + type: FOLLOW_REQUESTS_EXPAND_REQUEST, + }; +}; + +export function expandFollowRequestsSuccess(accounts, next) { + return { + type: FOLLOW_REQUESTS_EXPAND_SUCCESS, + accounts, + next, + }; +}; + +export function expandFollowRequestsFail(error) { + return { + type: FOLLOW_REQUESTS_EXPAND_FAIL, + error, + }; +}; + +export function authorizeFollowRequest(id) { + return (dispatch, getState) => { + dispatch(authorizeFollowRequestRequest(id)); + + api(getState) + .post(`/api/v1/follow_requests/${id}/authorize`) + .then(() => dispatch(authorizeFollowRequestSuccess(id))) + .catch(error => dispatch(authorizeFollowRequestFail(id, error))); + }; +}; + +export function authorizeFollowRequestRequest(id) { + return { + type: FOLLOW_REQUEST_AUTHORIZE_REQUEST, + id, + }; +}; + +export function authorizeFollowRequestSuccess(id) { + return { + type: FOLLOW_REQUEST_AUTHORIZE_SUCCESS, + id, + }; +}; + +export function authorizeFollowRequestFail(id, error) { + return { + type: FOLLOW_REQUEST_AUTHORIZE_FAIL, + id, + error, + }; +}; + + +export function rejectFollowRequest(id) { + return (dispatch, getState) => { + dispatch(rejectFollowRequestRequest(id)); + + api(getState) + .post(`/api/v1/follow_requests/${id}/reject`) + .then(() => dispatch(rejectFollowRequestSuccess(id))) + .catch(error => dispatch(rejectFollowRequestFail(id, error))); + }; +}; + +export function rejectFollowRequestRequest(id) { + return { + type: FOLLOW_REQUEST_REJECT_REQUEST, + id, + }; +}; + +export function rejectFollowRequestSuccess(id) { + return { + type: FOLLOW_REQUEST_REJECT_SUCCESS, + id, + }; +}; + +export function rejectFollowRequestFail(id, error) { + return { + type: FOLLOW_REQUEST_REJECT_FAIL, + id, + error, + }; +}; diff --git a/app/javascript/mastodon/actions/alerts.js b/app/javascript/mastodon/actions/alerts.js new file mode 100644 index 000000000..f37fdeeb6 --- /dev/null +++ b/app/javascript/mastodon/actions/alerts.js @@ -0,0 +1,24 @@ +export const ALERT_SHOW = 'ALERT_SHOW'; +export const ALERT_DISMISS = 'ALERT_DISMISS'; +export const ALERT_CLEAR = 'ALERT_CLEAR'; + +export function dismissAlert(alert) { + return { + type: ALERT_DISMISS, + alert, + }; +}; + +export function clearAlert() { + return { + type: ALERT_CLEAR, + }; +}; + +export function showAlert(title, message) { + return { + type: ALERT_SHOW, + title, + message, + }; +}; diff --git a/app/javascript/mastodon/actions/blocks.js b/app/javascript/mastodon/actions/blocks.js new file mode 100644 index 000000000..553283a71 --- /dev/null +++ b/app/javascript/mastodon/actions/blocks.js @@ -0,0 +1,82 @@ +import api, { getLinks } from '../api'; +import { fetchRelationships } from './accounts'; + +export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST'; +export const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS'; +export const BLOCKS_FETCH_FAIL = 'BLOCKS_FETCH_FAIL'; + +export const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST'; +export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS'; +export const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL'; + +export function fetchBlocks() { + return (dispatch, getState) => { + dispatch(fetchBlocksRequest()); + + api(getState).get('/api/v1/blocks').then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => dispatch(fetchBlocksFail(error))); + }; +}; + +export function fetchBlocksRequest() { + return { + type: BLOCKS_FETCH_REQUEST, + }; +}; + +export function fetchBlocksSuccess(accounts, next) { + return { + type: BLOCKS_FETCH_SUCCESS, + accounts, + next, + }; +}; + +export function fetchBlocksFail(error) { + return { + type: BLOCKS_FETCH_FAIL, + error, + }; +}; + +export function expandBlocks() { + return (dispatch, getState) => { + const url = getState().getIn(['user_lists', 'blocks', 'next']); + + if (url === null) { + return; + } + + dispatch(expandBlocksRequest()); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(expandBlocksSuccess(response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => dispatch(expandBlocksFail(error))); + }; +}; + +export function expandBlocksRequest() { + return { + type: BLOCKS_EXPAND_REQUEST, + }; +}; + +export function expandBlocksSuccess(accounts, next) { + return { + type: BLOCKS_EXPAND_SUCCESS, + accounts, + next, + }; +}; + +export function expandBlocksFail(error) { + return { + type: BLOCKS_EXPAND_FAIL, + error, + }; +}; diff --git a/app/javascript/mastodon/actions/bundles.js b/app/javascript/mastodon/actions/bundles.js new file mode 100644 index 000000000..ecc9c8f7d --- /dev/null +++ b/app/javascript/mastodon/actions/bundles.js @@ -0,0 +1,25 @@ +export const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST'; +export const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS'; +export const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL'; + +export function fetchBundleRequest(skipLoading) { + return { + type: BUNDLE_FETCH_REQUEST, + skipLoading, + }; +} + +export function fetchBundleSuccess(skipLoading) { + return { + type: BUNDLE_FETCH_SUCCESS, + skipLoading, + }; +} + +export function fetchBundleFail(error, skipLoading) { + return { + type: BUNDLE_FETCH_FAIL, + error, + skipLoading, + }; +} diff --git a/app/javascript/mastodon/actions/cards.js b/app/javascript/mastodon/actions/cards.js new file mode 100644 index 000000000..baf04833a --- /dev/null +++ b/app/javascript/mastodon/actions/cards.js @@ -0,0 +1,52 @@ +import api from '../api'; + +export const STATUS_CARD_FETCH_REQUEST = 'STATUS_CARD_FETCH_REQUEST'; +export const STATUS_CARD_FETCH_SUCCESS = 'STATUS_CARD_FETCH_SUCCESS'; +export const STATUS_CARD_FETCH_FAIL = 'STATUS_CARD_FETCH_FAIL'; + +export function fetchStatusCard(id) { + return (dispatch, getState) => { + if (getState().getIn(['cards', id], null) !== null) { + return; + } + + dispatch(fetchStatusCardRequest(id)); + + api(getState).get(`/api/v1/statuses/${id}/card`).then(response => { + if (!response.data.url) { + return; + } + + dispatch(fetchStatusCardSuccess(id, response.data)); + }).catch(error => { + dispatch(fetchStatusCardFail(id, error)); + }); + }; +}; + +export function fetchStatusCardRequest(id) { + return { + type: STATUS_CARD_FETCH_REQUEST, + id, + skipLoading: true, + }; +}; + +export function fetchStatusCardSuccess(id, card) { + return { + type: STATUS_CARD_FETCH_SUCCESS, + id, + card, + skipLoading: true, + }; +}; + +export function fetchStatusCardFail(id, error) { + return { + type: STATUS_CARD_FETCH_FAIL, + id, + error, + skipLoading: true, + skipAlert: true, + }; +}; diff --git a/app/javascript/mastodon/actions/columns.js b/app/javascript/mastodon/actions/columns.js new file mode 100644 index 000000000..bcb0cdf98 --- /dev/null +++ b/app/javascript/mastodon/actions/columns.js @@ -0,0 +1,40 @@ +import { saveSettings } from './settings'; + +export const COLUMN_ADD = 'COLUMN_ADD'; +export const COLUMN_REMOVE = 'COLUMN_REMOVE'; +export const COLUMN_MOVE = 'COLUMN_MOVE'; + +export function addColumn(id, params) { + return dispatch => { + dispatch({ + type: COLUMN_ADD, + id, + params, + }); + + dispatch(saveSettings()); + }; +}; + +export function removeColumn(uuid) { + return dispatch => { + dispatch({ + type: COLUMN_REMOVE, + uuid, + }); + + dispatch(saveSettings()); + }; +}; + +export function moveColumn(uuid, direction) { + return dispatch => { + dispatch({ + type: COLUMN_MOVE, + uuid, + direction, + }); + + dispatch(saveSettings()); + }; +}; diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js new file mode 100644 index 000000000..8a35049b3 --- /dev/null +++ b/app/javascript/mastodon/actions/compose.js @@ -0,0 +1,376 @@ +import api from '../api'; +import { throttle } from 'lodash'; +import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light'; +import { useEmoji } from './emojis'; + +import { + updateTimeline, + refreshHomeTimeline, + refreshCommunityTimeline, + refreshPublicTimeline, +} from './timelines'; + +export const COMPOSE_CHANGE = 'COMPOSE_CHANGE'; +export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST'; +export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS'; +export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL'; +export const COMPOSE_REPLY = 'COMPOSE_REPLY'; +export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL'; +export const COMPOSE_MENTION = 'COMPOSE_MENTION'; +export const COMPOSE_RESET = 'COMPOSE_RESET'; +export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST'; +export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS'; +export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL'; +export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS'; +export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO'; + +export const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR'; +export const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY'; +export const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT'; + +export const COMPOSE_MOUNT = 'COMPOSE_MOUNT'; +export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT'; + +export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE'; +export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE'; +export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE'; +export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE'; +export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE'; +export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE'; + +export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT'; + +export const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST'; +export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS'; +export const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL'; + +export function changeCompose(text) { + return { + type: COMPOSE_CHANGE, + text: text, + }; +}; + +export function replyCompose(status, router) { + return (dispatch, getState) => { + dispatch({ + type: COMPOSE_REPLY, + status: status, + }); + + if (!getState().getIn(['compose', 'mounted'])) { + router.push('/statuses/new'); + } + }; +}; + +export function cancelReplyCompose() { + return { + type: COMPOSE_REPLY_CANCEL, + }; +}; + +export function resetCompose() { + return { + type: COMPOSE_RESET, + }; +}; + +export function mentionCompose(account, router) { + return (dispatch, getState) => { + dispatch({ + type: COMPOSE_MENTION, + account: account, + }); + + if (!getState().getIn(['compose', 'mounted'])) { + router.push('/statuses/new'); + } + }; +}; + +export function submitCompose() { + return function (dispatch, getState) { + const status = getState().getIn(['compose', 'text'], ''); + + if (!status || !status.length) { + return; + } + + dispatch(submitComposeRequest()); + + api(getState).post('/api/v1/statuses', { + status, + in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null), + media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')), + sensitive: getState().getIn(['compose', 'sensitive']), + spoiler_text: getState().getIn(['compose', 'spoiler_text'], ''), + visibility: getState().getIn(['compose', 'privacy']), + }, { + headers: { + 'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']), + }, + }).then(function (response) { + dispatch(submitComposeSuccess({ ...response.data })); + + // To make the app more responsive, immediately get the status into the columns + + const insertOrRefresh = (timelineId, refreshAction) => { + if (getState().getIn(['timelines', timelineId, 'online'])) { + dispatch(updateTimeline(timelineId, { ...response.data })); + } else if (getState().getIn(['timelines', timelineId, 'loaded'])) { + dispatch(refreshAction()); + } + }; + + insertOrRefresh('home', refreshHomeTimeline); + + if (response.data.in_reply_to_id === null && response.data.visibility === 'public') { + insertOrRefresh('community', refreshCommunityTimeline); + insertOrRefresh('public', refreshPublicTimeline); + } + }).catch(function (error) { + dispatch(submitComposeFail(error)); + }); + }; +}; + +export function submitComposeRequest() { + return { + type: COMPOSE_SUBMIT_REQUEST, + }; +}; + +export function submitComposeSuccess(status) { + return { + type: COMPOSE_SUBMIT_SUCCESS, + status: status, + }; +}; + +export function submitComposeFail(error) { + return { + type: COMPOSE_SUBMIT_FAIL, + error: error, + }; +}; + +export function uploadCompose(files) { + return function (dispatch, getState) { + if (getState().getIn(['compose', 'media_attachments']).size > 3) { + return; + } + + dispatch(uploadComposeRequest()); + + let data = new FormData(); + data.append('file', files[0]); + + api(getState).post('/api/v1/media', data, { + onUploadProgress: function (e) { + dispatch(uploadComposeProgress(e.loaded, e.total)); + }, + }).then(function (response) { + dispatch(uploadComposeSuccess(response.data)); + }).catch(function (error) { + dispatch(uploadComposeFail(error)); + }); + }; +}; + +export function changeUploadCompose(id, description) { + return (dispatch, getState) => { + dispatch(changeUploadComposeRequest()); + + api(getState).put(`/api/v1/media/${id}`, { description }).then(response => { + dispatch(changeUploadComposeSuccess(response.data)); + }).catch(error => { + dispatch(changeUploadComposeFail(id, error)); + }); + }; +}; + +export function changeUploadComposeRequest() { + return { + type: COMPOSE_UPLOAD_CHANGE_REQUEST, + skipLoading: true, + }; +}; +export function changeUploadComposeSuccess(media) { + return { + type: COMPOSE_UPLOAD_CHANGE_SUCCESS, + media: media, + skipLoading: true, + }; +}; + +export function changeUploadComposeFail(error) { + return { + type: COMPOSE_UPLOAD_CHANGE_FAIL, + error: error, + skipLoading: true, + }; +}; + +export function uploadComposeRequest() { + return { + type: COMPOSE_UPLOAD_REQUEST, + skipLoading: true, + }; +}; + +export function uploadComposeProgress(loaded, total) { + return { + type: COMPOSE_UPLOAD_PROGRESS, + loaded: loaded, + total: total, + }; +}; + +export function uploadComposeSuccess(media) { + return { + type: COMPOSE_UPLOAD_SUCCESS, + media: media, + skipLoading: true, + }; +}; + +export function uploadComposeFail(error) { + return { + type: COMPOSE_UPLOAD_FAIL, + error: error, + skipLoading: true, + }; +}; + +export function undoUploadCompose(media_id) { + return { + type: COMPOSE_UPLOAD_UNDO, + media_id: media_id, + }; +}; + +export function clearComposeSuggestions() { + return { + type: COMPOSE_SUGGESTIONS_CLEAR, + }; +}; + +const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => { + api(getState).get('/api/v1/accounts/search', { + params: { + q: token.slice(1), + resolve: false, + limit: 4, + }, + }).then(response => { + dispatch(readyComposeSuggestionsAccounts(token, response.data)); + }); +}, 200, { leading: true, trailing: true }); + +const fetchComposeSuggestionsEmojis = (dispatch, getState, token) => { + const results = emojiSearch(token.replace(':', ''), { maxResults: 5 }); + dispatch(readyComposeSuggestionsEmojis(token, results)); +}; + +export function fetchComposeSuggestions(token) { + return (dispatch, getState) => { + if (token[0] === ':') { + fetchComposeSuggestionsEmojis(dispatch, getState, token); + } else { + fetchComposeSuggestionsAccounts(dispatch, getState, token); + } + }; +}; + +export function readyComposeSuggestionsEmojis(token, emojis) { + return { + type: COMPOSE_SUGGESTIONS_READY, + token, + emojis, + }; +}; + +export function readyComposeSuggestionsAccounts(token, accounts) { + return { + type: COMPOSE_SUGGESTIONS_READY, + token, + accounts, + }; +}; + +export function selectComposeSuggestion(position, token, suggestion) { + return (dispatch, getState) => { + let completion, startPosition; + + if (typeof suggestion === 'object' && suggestion.id) { + completion = suggestion.native || suggestion.colons; + startPosition = position - 1; + + dispatch(useEmoji(suggestion)); + } else { + completion = getState().getIn(['accounts', suggestion, 'acct']); + startPosition = position; + } + + dispatch({ + type: COMPOSE_SUGGESTION_SELECT, + position: startPosition, + token, + completion, + }); + }; +}; + +export function mountCompose() { + return { + type: COMPOSE_MOUNT, + }; +}; + +export function unmountCompose() { + return { + type: COMPOSE_UNMOUNT, + }; +}; + +export function changeComposeSensitivity() { + return { + type: COMPOSE_SENSITIVITY_CHANGE, + }; +}; + +export function changeComposeSpoilerness() { + return { + type: COMPOSE_SPOILERNESS_CHANGE, + }; +}; + +export function changeComposeSpoilerText(text) { + return { + type: COMPOSE_SPOILER_TEXT_CHANGE, + text, + }; +}; + +export function changeComposeVisibility(value) { + return { + type: COMPOSE_VISIBILITY_CHANGE, + value, + }; +}; + +export function insertEmojiCompose(position, emoji) { + return { + type: COMPOSE_EMOJI_INSERT, + position, + emoji, + }; +}; + +export function changeComposing(value) { + return { + type: COMPOSE_COMPOSING_CHANGE, + value, + }; +} diff --git a/app/javascript/mastodon/actions/domain_blocks.js b/app/javascript/mastodon/actions/domain_blocks.js new file mode 100644 index 000000000..44363697a --- /dev/null +++ b/app/javascript/mastodon/actions/domain_blocks.js @@ -0,0 +1,117 @@ +import api, { getLinks } from '../api'; + +export const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST'; +export const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS'; +export const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL'; + +export const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST'; +export const DOMAIN_UNBLOCK_SUCCESS = 'DOMAIN_UNBLOCK_SUCCESS'; +export const DOMAIN_UNBLOCK_FAIL = 'DOMAIN_UNBLOCK_FAIL'; + +export const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST'; +export const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS'; +export const DOMAIN_BLOCKS_FETCH_FAIL = 'DOMAIN_BLOCKS_FETCH_FAIL'; + +export function blockDomain(domain, accountId) { + return (dispatch, getState) => { + dispatch(blockDomainRequest(domain)); + + api(getState).post('/api/v1/domain_blocks', { domain }).then(() => { + dispatch(blockDomainSuccess(domain, accountId)); + }).catch(err => { + dispatch(blockDomainFail(domain, err)); + }); + }; +}; + +export function blockDomainRequest(domain) { + return { + type: DOMAIN_BLOCK_REQUEST, + domain, + }; +}; + +export function blockDomainSuccess(domain, accountId) { + return { + type: DOMAIN_BLOCK_SUCCESS, + domain, + accountId, + }; +}; + +export function blockDomainFail(domain, error) { + return { + type: DOMAIN_BLOCK_FAIL, + domain, + error, + }; +}; + +export function unblockDomain(domain, accountId) { + return (dispatch, getState) => { + dispatch(unblockDomainRequest(domain)); + + api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(() => { + dispatch(unblockDomainSuccess(domain, accountId)); + }).catch(err => { + dispatch(unblockDomainFail(domain, err)); + }); + }; +}; + +export function unblockDomainRequest(domain) { + return { + type: DOMAIN_UNBLOCK_REQUEST, + domain, + }; +}; + +export function unblockDomainSuccess(domain, accountId) { + return { + type: DOMAIN_UNBLOCK_SUCCESS, + domain, + accountId, + }; +}; + +export function unblockDomainFail(domain, error) { + return { + type: DOMAIN_UNBLOCK_FAIL, + domain, + error, + }; +}; + +export function fetchDomainBlocks() { + return (dispatch, getState) => { + dispatch(fetchDomainBlocksRequest()); + + api(getState).get().then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null)); + }).catch(err => { + dispatch(fetchDomainBlocksFail(err)); + }); + }; +}; + +export function fetchDomainBlocksRequest() { + return { + type: DOMAIN_BLOCKS_FETCH_REQUEST, + }; +}; + +export function fetchDomainBlocksSuccess(domains, next) { + return { + type: DOMAIN_BLOCKS_FETCH_SUCCESS, + domains, + next, + }; +}; + +export function fetchDomainBlocksFail(error) { + return { + type: DOMAIN_BLOCKS_FETCH_FAIL, + error, + }; +}; diff --git a/app/javascript/mastodon/actions/emojis.js b/app/javascript/mastodon/actions/emojis.js new file mode 100644 index 000000000..7cd9d4b7b --- /dev/null +++ b/app/javascript/mastodon/actions/emojis.js @@ -0,0 +1,14 @@ +import { saveSettings } from './settings'; + +export const EMOJI_USE = 'EMOJI_USE'; + +export function useEmoji(emoji) { + return dispatch => { + dispatch({ + type: EMOJI_USE, + emoji, + }); + + dispatch(saveSettings()); + }; +}; diff --git a/app/javascript/mastodon/actions/favourites.js b/app/javascript/mastodon/actions/favourites.js new file mode 100644 index 000000000..09ce51fce --- /dev/null +++ b/app/javascript/mastodon/actions/favourites.js @@ -0,0 +1,83 @@ +import api, { getLinks } from '../api'; + +export const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST'; +export const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS'; +export const FAVOURITED_STATUSES_FETCH_FAIL = 'FAVOURITED_STATUSES_FETCH_FAIL'; + +export const FAVOURITED_STATUSES_EXPAND_REQUEST = 'FAVOURITED_STATUSES_EXPAND_REQUEST'; +export const FAVOURITED_STATUSES_EXPAND_SUCCESS = 'FAVOURITED_STATUSES_EXPAND_SUCCESS'; +export const FAVOURITED_STATUSES_EXPAND_FAIL = 'FAVOURITED_STATUSES_EXPAND_FAIL'; + +export function fetchFavouritedStatuses() { + return (dispatch, getState) => { + dispatch(fetchFavouritedStatusesRequest()); + + api(getState).get('/api/v1/favourites').then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null)); + }).catch(error => { + dispatch(fetchFavouritedStatusesFail(error)); + }); + }; +}; + +export function fetchFavouritedStatusesRequest() { + return { + type: FAVOURITED_STATUSES_FETCH_REQUEST, + }; +}; + +export function fetchFavouritedStatusesSuccess(statuses, next) { + return { + type: FAVOURITED_STATUSES_FETCH_SUCCESS, + statuses, + next, + }; +}; + +export function fetchFavouritedStatusesFail(error) { + return { + type: FAVOURITED_STATUSES_FETCH_FAIL, + error, + }; +}; + +export function expandFavouritedStatuses() { + return (dispatch, getState) => { + const url = getState().getIn(['status_lists', 'favourites', 'next'], null); + + if (url === null) { + return; + } + + dispatch(expandFavouritedStatusesRequest()); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null)); + }).catch(error => { + dispatch(expandFavouritedStatusesFail(error)); + }); + }; +}; + +export function expandFavouritedStatusesRequest() { + return { + type: FAVOURITED_STATUSES_EXPAND_REQUEST, + }; +}; + +export function expandFavouritedStatusesSuccess(statuses, next) { + return { + type: FAVOURITED_STATUSES_EXPAND_SUCCESS, + statuses, + next, + }; +}; + +export function expandFavouritedStatusesFail(error) { + return { + type: FAVOURITED_STATUSES_EXPAND_FAIL, + error, + }; +}; diff --git a/app/javascript/mastodon/actions/height_cache.js b/app/javascript/mastodon/actions/height_cache.js new file mode 100644 index 000000000..4c752993f --- /dev/null +++ b/app/javascript/mastodon/actions/height_cache.js @@ -0,0 +1,17 @@ +export const HEIGHT_CACHE_SET = 'HEIGHT_CACHE_SET'; +export const HEIGHT_CACHE_CLEAR = 'HEIGHT_CACHE_CLEAR'; + +export function setHeight (key, id, height) { + return { + type: HEIGHT_CACHE_SET, + key, + id, + height, + }; +}; + +export function clearHeight () { + return { + type: HEIGHT_CACHE_CLEAR, + }; +}; diff --git a/app/javascript/mastodon/actions/interactions.js b/app/javascript/mastodon/actions/interactions.js new file mode 100644 index 000000000..7b5f4bd9c --- /dev/null +++ b/app/javascript/mastodon/actions/interactions.js @@ -0,0 +1,313 @@ +import api from '../api'; + +export const REBLOG_REQUEST = 'REBLOG_REQUEST'; +export const REBLOG_SUCCESS = 'REBLOG_SUCCESS'; +export const REBLOG_FAIL = 'REBLOG_FAIL'; + +export const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST'; +export const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS'; +export const FAVOURITE_FAIL = 'FAVOURITE_FAIL'; + +export const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST'; +export const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS'; +export const UNREBLOG_FAIL = 'UNREBLOG_FAIL'; + +export const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST'; +export const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS'; +export const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL'; + +export const REBLOGS_FETCH_REQUEST = 'REBLOGS_FETCH_REQUEST'; +export const REBLOGS_FETCH_SUCCESS = 'REBLOGS_FETCH_SUCCESS'; +export const REBLOGS_FETCH_FAIL = 'REBLOGS_FETCH_FAIL'; + +export const FAVOURITES_FETCH_REQUEST = 'FAVOURITES_FETCH_REQUEST'; +export const FAVOURITES_FETCH_SUCCESS = 'FAVOURITES_FETCH_SUCCESS'; +export const FAVOURITES_FETCH_FAIL = 'FAVOURITES_FETCH_FAIL'; + +export const PIN_REQUEST = 'PIN_REQUEST'; +export const PIN_SUCCESS = 'PIN_SUCCESS'; +export const PIN_FAIL = 'PIN_FAIL'; + +export const UNPIN_REQUEST = 'UNPIN_REQUEST'; +export const UNPIN_SUCCESS = 'UNPIN_SUCCESS'; +export const UNPIN_FAIL = 'UNPIN_FAIL'; + +export function reblog(status) { + return function (dispatch, getState) { + dispatch(reblogRequest(status)); + + api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function (response) { + // The reblog API method returns a new status wrapped around the original. In this case we are only + // interested in how the original is modified, hence passing it skipping the wrapper + dispatch(reblogSuccess(status, response.data.reblog)); + }).catch(function (error) { + dispatch(reblogFail(status, error)); + }); + }; +}; + +export function unreblog(status) { + return (dispatch, getState) => { + dispatch(unreblogRequest(status)); + + api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { + dispatch(unreblogSuccess(status, response.data)); + }).catch(error => { + dispatch(unreblogFail(status, error)); + }); + }; +}; + +export function reblogRequest(status) { + return { + type: REBLOG_REQUEST, + status: status, + }; +}; + +export function reblogSuccess(status, response) { + return { + type: REBLOG_SUCCESS, + status: status, + response: response, + }; +}; + +export function reblogFail(status, error) { + return { + type: REBLOG_FAIL, + status: status, + error: error, + }; +}; + +export function unreblogRequest(status) { + return { + type: UNREBLOG_REQUEST, + status: status, + }; +}; + +export function unreblogSuccess(status, response) { + return { + type: UNREBLOG_SUCCESS, + status: status, + response: response, + }; +}; + +export function unreblogFail(status, error) { + return { + type: UNREBLOG_FAIL, + status: status, + error: error, + }; +}; + +export function favourite(status) { + return function (dispatch, getState) { + dispatch(favouriteRequest(status)); + + api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) { + dispatch(favouriteSuccess(status, response.data)); + }).catch(function (error) { + dispatch(favouriteFail(status, error)); + }); + }; +}; + +export function unfavourite(status) { + return (dispatch, getState) => { + dispatch(unfavouriteRequest(status)); + + api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => { + dispatch(unfavouriteSuccess(status, response.data)); + }).catch(error => { + dispatch(unfavouriteFail(status, error)); + }); + }; +}; + +export function favouriteRequest(status) { + return { + type: FAVOURITE_REQUEST, + status: status, + }; +}; + +export function favouriteSuccess(status, response) { + return { + type: FAVOURITE_SUCCESS, + status: status, + response: response, + }; +}; + +export function favouriteFail(status, error) { + return { + type: FAVOURITE_FAIL, + status: status, + error: error, + }; +}; + +export function unfavouriteRequest(status) { + return { + type: UNFAVOURITE_REQUEST, + status: status, + }; +}; + +export function unfavouriteSuccess(status, response) { + return { + type: UNFAVOURITE_SUCCESS, + status: status, + response: response, + }; +}; + +export function unfavouriteFail(status, error) { + return { + type: UNFAVOURITE_FAIL, + status: status, + error: error, + }; +}; + +export function fetchReblogs(id) { + return (dispatch, getState) => { + dispatch(fetchReblogsRequest(id)); + + api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => { + dispatch(fetchReblogsSuccess(id, response.data)); + }).catch(error => { + dispatch(fetchReblogsFail(id, error)); + }); + }; +}; + +export function fetchReblogsRequest(id) { + return { + type: REBLOGS_FETCH_REQUEST, + id, + }; +}; + +export function fetchReblogsSuccess(id, accounts) { + return { + type: REBLOGS_FETCH_SUCCESS, + id, + accounts, + }; +}; + +export function fetchReblogsFail(id, error) { + return { + type: REBLOGS_FETCH_FAIL, + error, + }; +}; + +export function fetchFavourites(id) { + return (dispatch, getState) => { + dispatch(fetchFavouritesRequest(id)); + + api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => { + dispatch(fetchFavouritesSuccess(id, response.data)); + }).catch(error => { + dispatch(fetchFavouritesFail(id, error)); + }); + }; +}; + +export function fetchFavouritesRequest(id) { + return { + type: FAVOURITES_FETCH_REQUEST, + id, + }; +}; + +export function fetchFavouritesSuccess(id, accounts) { + return { + type: FAVOURITES_FETCH_SUCCESS, + id, + accounts, + }; +}; + +export function fetchFavouritesFail(id, error) { + return { + type: FAVOURITES_FETCH_FAIL, + error, + }; +}; + +export function pin(status) { + return (dispatch, getState) => { + dispatch(pinRequest(status)); + + api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => { + dispatch(pinSuccess(status, response.data)); + }).catch(error => { + dispatch(pinFail(status, error)); + }); + }; +}; + +export function pinRequest(status) { + return { + type: PIN_REQUEST, + status, + }; +}; + +export function pinSuccess(status, response) { + return { + type: PIN_SUCCESS, + status, + response, + }; +}; + +export function pinFail(status, error) { + return { + type: PIN_FAIL, + status, + error, + }; +}; + +export function unpin (status) { + return (dispatch, getState) => { + dispatch(unpinRequest(status)); + + api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => { + dispatch(unpinSuccess(status, response.data)); + }).catch(error => { + dispatch(unpinFail(status, error)); + }); + }; +}; + +export function unpinRequest(status) { + return { + type: UNPIN_REQUEST, + status, + }; +}; + +export function unpinSuccess(status, response) { + return { + type: UNPIN_SUCCESS, + status, + response, + }; +}; + +export function unpinFail(status, error) { + return { + type: UNPIN_FAIL, + status, + error, + }; +}; diff --git a/app/javascript/mastodon/actions/modal.js b/app/javascript/mastodon/actions/modal.js new file mode 100644 index 000000000..80e15c28e --- /dev/null +++ b/app/javascript/mastodon/actions/modal.js @@ -0,0 +1,16 @@ +export const MODAL_OPEN = 'MODAL_OPEN'; +export const MODAL_CLOSE = 'MODAL_CLOSE'; + +export function openModal(type, props) { + return { + type: MODAL_OPEN, + modalType: type, + modalProps: props, + }; +}; + +export function closeModal() { + return { + type: MODAL_CLOSE, + }; +}; diff --git a/app/javascript/mastodon/actions/mutes.js b/app/javascript/mastodon/actions/mutes.js new file mode 100644 index 000000000..3474250fe --- /dev/null +++ b/app/javascript/mastodon/actions/mutes.js @@ -0,0 +1,103 @@ +import api, { getLinks } from '../api'; +import { fetchRelationships } from './accounts'; +import { openModal } from '../../mastodon/actions/modal'; + +export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST'; +export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS'; +export const MUTES_FETCH_FAIL = 'MUTES_FETCH_FAIL'; + +export const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST'; +export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS'; +export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL'; + +export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL'; +export const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS'; + +export function fetchMutes() { + return (dispatch, getState) => { + dispatch(fetchMutesRequest()); + + api(getState).get('/api/v1/mutes').then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(fetchMutesSuccess(response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => dispatch(fetchMutesFail(error))); + }; +}; + +export function fetchMutesRequest() { + return { + type: MUTES_FETCH_REQUEST, + }; +}; + +export function fetchMutesSuccess(accounts, next) { + return { + type: MUTES_FETCH_SUCCESS, + accounts, + next, + }; +}; + +export function fetchMutesFail(error) { + return { + type: MUTES_FETCH_FAIL, + error, + }; +}; + +export function expandMutes() { + return (dispatch, getState) => { + const url = getState().getIn(['user_lists', 'mutes', 'next']); + + if (url === null) { + return; + } + + dispatch(expandMutesRequest()); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(expandMutesSuccess(response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => dispatch(expandMutesFail(error))); + }; +}; + +export function expandMutesRequest() { + return { + type: MUTES_EXPAND_REQUEST, + }; +}; + +export function expandMutesSuccess(accounts, next) { + return { + type: MUTES_EXPAND_SUCCESS, + accounts, + next, + }; +}; + +export function expandMutesFail(error) { + return { + type: MUTES_EXPAND_FAIL, + error, + }; +}; + +export function initMuteModal(account) { + return dispatch => { + dispatch({ + type: MUTES_INIT_MODAL, + account, + }); + + dispatch(openModal('MUTE')); + }; +} + +export function toggleHideNotifications() { + return dispatch => { + dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS }); + }; +} \ No newline at end of file diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js new file mode 100644 index 000000000..b24ac8b73 --- /dev/null +++ b/app/javascript/mastodon/actions/notifications.js @@ -0,0 +1,190 @@ +import api, { getLinks } from '../api'; +import { List as ImmutableList } from 'immutable'; +import IntlMessageFormat from 'intl-messageformat'; +import { fetchRelationships } from './accounts'; +import { defineMessages } from 'react-intl'; + +export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE'; + +export const NOTIFICATIONS_REFRESH_REQUEST = 'NOTIFICATIONS_REFRESH_REQUEST'; +export const NOTIFICATIONS_REFRESH_SUCCESS = 'NOTIFICATIONS_REFRESH_SUCCESS'; +export const NOTIFICATIONS_REFRESH_FAIL = 'NOTIFICATIONS_REFRESH_FAIL'; + +export const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST'; +export const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS'; +export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL'; + +export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR'; +export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP'; + +defineMessages({ + mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' }, +}); + +const fetchRelatedRelationships = (dispatch, notifications) => { + const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id); + + if (accountIds > 0) { + dispatch(fetchRelationships(accountIds)); + } +}; + +const unescapeHTML = (html) => { + const wrapper = document.createElement('div'); + html = html.replace(/
|
|\n/, ' '); + wrapper.innerHTML = html; + return wrapper.textContent; +}; + +export function updateNotifications(notification, intlMessages, intlLocale) { + return (dispatch, getState) => { + const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true); + const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true); + + dispatch({ + type: NOTIFICATIONS_UPDATE, + notification, + account: notification.account, + status: notification.status, + meta: playSound ? { sound: 'boop' } : undefined, + }); + + fetchRelatedRelationships(dispatch, [notification]); + + // Desktop notifications + if (typeof window.Notification !== 'undefined' && showAlert) { + const title = new IntlMessageFormat(intlMessages[`notification.${notification.type}`], intlLocale).format({ name: notification.account.display_name.length > 0 ? notification.account.display_name : notification.account.username }); + const body = (notification.status && notification.status.spoiler_text.length > 0) ? notification.status.spoiler_text : unescapeHTML(notification.status ? notification.status.content : ''); + + const notify = new Notification(title, { body, icon: notification.account.avatar, tag: notification.id }); + notify.addEventListener('click', () => { + window.focus(); + notify.close(); + }); + } + }; +}; + +const excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS(); + +export function refreshNotifications() { + return (dispatch, getState) => { + const params = {}; + const ids = getState().getIn(['notifications', 'items']); + + let skipLoading = false; + + if (ids.size > 0) { + params.since_id = ids.first().get('id'); + } + + if (getState().getIn(['notifications', 'loaded'])) { + skipLoading = true; + } + + params.exclude_types = excludeTypesFromSettings(getState()); + + dispatch(refreshNotificationsRequest(skipLoading)); + + api(getState).get('/api/v1/notifications', { params }).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + + dispatch(refreshNotificationsSuccess(response.data, skipLoading, next ? next.uri : null)); + fetchRelatedRelationships(dispatch, response.data); + }).catch(error => { + dispatch(refreshNotificationsFail(error, skipLoading)); + }); + }; +}; + +export function refreshNotificationsRequest(skipLoading) { + return { + type: NOTIFICATIONS_REFRESH_REQUEST, + skipLoading, + }; +}; + +export function refreshNotificationsSuccess(notifications, skipLoading, next) { + return { + type: NOTIFICATIONS_REFRESH_SUCCESS, + notifications, + accounts: notifications.map(item => item.account), + statuses: notifications.map(item => item.status).filter(status => !!status), + skipLoading, + next, + }; +}; + +export function refreshNotificationsFail(error, skipLoading) { + return { + type: NOTIFICATIONS_REFRESH_FAIL, + error, + skipLoading, + }; +}; + +export function expandNotifications() { + return (dispatch, getState) => { + const items = getState().getIn(['notifications', 'items'], ImmutableList()); + + if (getState().getIn(['notifications', 'isLoading']) || items.size === 0) { + return; + } + + const params = { + max_id: items.last().get('id'), + limit: 20, + exclude_types: excludeTypesFromSettings(getState()), + }; + + dispatch(expandNotificationsRequest()); + + api(getState).get('/api/v1/notifications', { params }).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null)); + fetchRelatedRelationships(dispatch, response.data); + }).catch(error => { + dispatch(expandNotificationsFail(error)); + }); + }; +}; + +export function expandNotificationsRequest() { + return { + type: NOTIFICATIONS_EXPAND_REQUEST, + }; +}; + +export function expandNotificationsSuccess(notifications, next) { + return { + type: NOTIFICATIONS_EXPAND_SUCCESS, + notifications, + accounts: notifications.map(item => item.account), + statuses: notifications.map(item => item.status).filter(status => !!status), + next, + }; +}; + +export function expandNotificationsFail(error) { + return { + type: NOTIFICATIONS_EXPAND_FAIL, + error, + }; +}; + +export function clearNotifications() { + return (dispatch, getState) => { + dispatch({ + type: NOTIFICATIONS_CLEAR, + }); + + api(getState).post('/api/v1/notifications/clear'); + }; +}; + +export function scrollTopNotifications(top) { + return { + type: NOTIFICATIONS_SCROLL_TOP, + top, + }; +}; diff --git a/app/javascript/mastodon/actions/onboarding.js b/app/javascript/mastodon/actions/onboarding.js new file mode 100644 index 000000000..a161c50ef --- /dev/null +++ b/app/javascript/mastodon/actions/onboarding.js @@ -0,0 +1,14 @@ +import { openModal } from './modal'; +import { changeSetting, saveSettings } from './settings'; + +export function showOnboardingOnce() { + return (dispatch, getState) => { + const alreadySeen = getState().getIn(['settings', 'onboarded']); + + if (!alreadySeen) { + dispatch(openModal('ONBOARDING')); + dispatch(changeSetting(['onboarded'], true)); + dispatch(saveSettings()); + } + }; +}; diff --git a/app/javascript/mastodon/actions/pin_statuses.js b/app/javascript/mastodon/actions/pin_statuses.js new file mode 100644 index 000000000..3f40f6c2d --- /dev/null +++ b/app/javascript/mastodon/actions/pin_statuses.js @@ -0,0 +1,40 @@ +import api from '../api'; + +export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST'; +export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS'; +export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL'; + +import { me } from '../initial_state'; + +export function fetchPinnedStatuses() { + return (dispatch, getState) => { + dispatch(fetchPinnedStatusesRequest()); + + api(getState).get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => { + dispatch(fetchPinnedStatusesSuccess(response.data, null)); + }).catch(error => { + dispatch(fetchPinnedStatusesFail(error)); + }); + }; +}; + +export function fetchPinnedStatusesRequest() { + return { + type: PINNED_STATUSES_FETCH_REQUEST, + }; +}; + +export function fetchPinnedStatusesSuccess(statuses, next) { + return { + type: PINNED_STATUSES_FETCH_SUCCESS, + statuses, + next, + }; +}; + +export function fetchPinnedStatusesFail(error) { + return { + type: PINNED_STATUSES_FETCH_FAIL, + error, + }; +}; diff --git a/app/javascript/mastodon/actions/push_notifications.js b/app/javascript/mastodon/actions/push_notifications.js new file mode 100644 index 000000000..55661d2b0 --- /dev/null +++ b/app/javascript/mastodon/actions/push_notifications.js @@ -0,0 +1,52 @@ +import axios from 'axios'; + +export const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT'; +export const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION'; +export const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION'; +export const ALERTS_CHANGE = 'PUSH_NOTIFICATIONS_ALERTS_CHANGE'; + +export function setBrowserSupport (value) { + return { + type: SET_BROWSER_SUPPORT, + value, + }; +} + +export function setSubscription (subscription) { + return { + type: SET_SUBSCRIPTION, + subscription, + }; +} + +export function clearSubscription () { + return { + type: CLEAR_SUBSCRIPTION, + }; +} + +export function changeAlerts(key, value) { + return dispatch => { + dispatch({ + type: ALERTS_CHANGE, + key, + value, + }); + + dispatch(saveSettings()); + }; +} + +export function saveSettings() { + return (_, getState) => { + const state = getState().get('push_notifications'); + const subscription = state.get('subscription'); + const alerts = state.get('alerts'); + + axios.put(`/api/web/push_subscriptions/${subscription.get('id')}`, { + data: { + alerts, + }, + }); + }; +} diff --git a/app/javascript/mastodon/actions/reports.js b/app/javascript/mastodon/actions/reports.js new file mode 100644 index 000000000..b19a07285 --- /dev/null +++ b/app/javascript/mastodon/actions/reports.js @@ -0,0 +1,80 @@ +import api from '../api'; +import { openModal, closeModal } from './modal'; + +export const REPORT_INIT = 'REPORT_INIT'; +export const REPORT_CANCEL = 'REPORT_CANCEL'; + +export const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST'; +export const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS'; +export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL'; + +export const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE'; +export const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE'; + +export function initReport(account, status) { + return dispatch => { + dispatch({ + type: REPORT_INIT, + account, + status, + }); + + dispatch(openModal('REPORT')); + }; +}; + +export function cancelReport() { + return { + type: REPORT_CANCEL, + }; +}; + +export function toggleStatusReport(statusId, checked) { + return { + type: REPORT_STATUS_TOGGLE, + statusId, + checked, + }; +}; + +export function submitReport() { + return (dispatch, getState) => { + dispatch(submitReportRequest()); + + api(getState).post('/api/v1/reports', { + account_id: getState().getIn(['reports', 'new', 'account_id']), + status_ids: getState().getIn(['reports', 'new', 'status_ids']), + comment: getState().getIn(['reports', 'new', 'comment']), + }).then(response => { + dispatch(closeModal()); + dispatch(submitReportSuccess(response.data)); + }).catch(error => dispatch(submitReportFail(error))); + }; +}; + +export function submitReportRequest() { + return { + type: REPORT_SUBMIT_REQUEST, + }; +}; + +export function submitReportSuccess(report) { + return { + type: REPORT_SUBMIT_SUCCESS, + report, + }; +}; + +export function submitReportFail(error) { + return { + type: REPORT_SUBMIT_FAIL, + error, + }; +}; + +export function changeReportComment(comment) { + return { + type: REPORT_COMMENT_CHANGE, + comment, + }; +}; diff --git a/app/javascript/mastodon/actions/search.js b/app/javascript/mastodon/actions/search.js new file mode 100644 index 000000000..78c6109f7 --- /dev/null +++ b/app/javascript/mastodon/actions/search.js @@ -0,0 +1,73 @@ +import api from '../api'; + +export const SEARCH_CHANGE = 'SEARCH_CHANGE'; +export const SEARCH_CLEAR = 'SEARCH_CLEAR'; +export const SEARCH_SHOW = 'SEARCH_SHOW'; + +export const SEARCH_FETCH_REQUEST = 'SEARCH_FETCH_REQUEST'; +export const SEARCH_FETCH_SUCCESS = 'SEARCH_FETCH_SUCCESS'; +export const SEARCH_FETCH_FAIL = 'SEARCH_FETCH_FAIL'; + +export function changeSearch(value) { + return { + type: SEARCH_CHANGE, + value, + }; +}; + +export function clearSearch() { + return { + type: SEARCH_CLEAR, + }; +}; + +export function submitSearch() { + return (dispatch, getState) => { + const value = getState().getIn(['search', 'value']); + + if (value.length === 0) { + return; + } + + dispatch(fetchSearchRequest()); + + api(getState).get('/api/v1/search', { + params: { + q: value, + resolve: true, + }, + }).then(response => { + dispatch(fetchSearchSuccess(response.data)); + }).catch(error => { + dispatch(fetchSearchFail(error)); + }); + }; +}; + +export function fetchSearchRequest() { + return { + type: SEARCH_FETCH_REQUEST, + }; +}; + +export function fetchSearchSuccess(results) { + return { + type: SEARCH_FETCH_SUCCESS, + results, + accounts: results.accounts, + statuses: results.statuses, + }; +}; + +export function fetchSearchFail(error) { + return { + type: SEARCH_FETCH_FAIL, + error, + }; +}; + +export function showSearch() { + return { + type: SEARCH_SHOW, + }; +}; diff --git a/app/javascript/mastodon/actions/settings.js b/app/javascript/mastodon/actions/settings.js new file mode 100644 index 000000000..79adca18c --- /dev/null +++ b/app/javascript/mastodon/actions/settings.js @@ -0,0 +1,31 @@ +import axios from 'axios'; +import { debounce } from 'lodash'; + +export const SETTING_CHANGE = 'SETTING_CHANGE'; +export const SETTING_SAVE = 'SETTING_SAVE'; + +export function changeSetting(key, value) { + return dispatch => { + dispatch({ + type: SETTING_CHANGE, + key, + value, + }); + + dispatch(saveSettings()); + }; +}; + +const debouncedSave = debounce((dispatch, getState) => { + if (getState().getIn(['settings', 'saved'])) { + return; + } + + const data = getState().get('settings').filter((_, key) => key !== 'saved').toJS(); + + axios.put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE })); +}, 5000, { trailing: true }); + +export function saveSettings() { + return (dispatch, getState) => debouncedSave(dispatch, getState); +}; diff --git a/app/javascript/mastodon/actions/statuses.js b/app/javascript/mastodon/actions/statuses.js new file mode 100644 index 000000000..2204e0b14 --- /dev/null +++ b/app/javascript/mastodon/actions/statuses.js @@ -0,0 +1,217 @@ +import api from '../api'; + +import { deleteFromTimelines } from './timelines'; +import { fetchStatusCard } from './cards'; + +export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; +export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'; +export const STATUS_FETCH_FAIL = 'STATUS_FETCH_FAIL'; + +export const STATUS_DELETE_REQUEST = 'STATUS_DELETE_REQUEST'; +export const STATUS_DELETE_SUCCESS = 'STATUS_DELETE_SUCCESS'; +export const STATUS_DELETE_FAIL = 'STATUS_DELETE_FAIL'; + +export const CONTEXT_FETCH_REQUEST = 'CONTEXT_FETCH_REQUEST'; +export const CONTEXT_FETCH_SUCCESS = 'CONTEXT_FETCH_SUCCESS'; +export const CONTEXT_FETCH_FAIL = 'CONTEXT_FETCH_FAIL'; + +export const STATUS_MUTE_REQUEST = 'STATUS_MUTE_REQUEST'; +export const STATUS_MUTE_SUCCESS = 'STATUS_MUTE_SUCCESS'; +export const STATUS_MUTE_FAIL = 'STATUS_MUTE_FAIL'; + +export const STATUS_UNMUTE_REQUEST = 'STATUS_UNMUTE_REQUEST'; +export const STATUS_UNMUTE_SUCCESS = 'STATUS_UNMUTE_SUCCESS'; +export const STATUS_UNMUTE_FAIL = 'STATUS_UNMUTE_FAIL'; + +export function fetchStatusRequest(id, skipLoading) { + return { + type: STATUS_FETCH_REQUEST, + id, + skipLoading, + }; +}; + +export function fetchStatus(id) { + return (dispatch, getState) => { + const skipLoading = getState().getIn(['statuses', id], null) !== null; + + dispatch(fetchContext(id)); + dispatch(fetchStatusCard(id)); + + if (skipLoading) { + return; + } + + dispatch(fetchStatusRequest(id, skipLoading)); + + api(getState).get(`/api/v1/statuses/${id}`).then(response => { + dispatch(fetchStatusSuccess(response.data, skipLoading)); + }).catch(error => { + dispatch(fetchStatusFail(id, error, skipLoading)); + }); + }; +}; + +export function fetchStatusSuccess(status, skipLoading) { + return { + type: STATUS_FETCH_SUCCESS, + status, + skipLoading, + }; +}; + +export function fetchStatusFail(id, error, skipLoading) { + return { + type: STATUS_FETCH_FAIL, + id, + error, + skipLoading, + skipAlert: true, + }; +}; + +export function deleteStatus(id) { + return (dispatch, getState) => { + dispatch(deleteStatusRequest(id)); + + api(getState).delete(`/api/v1/statuses/${id}`).then(() => { + dispatch(deleteStatusSuccess(id)); + dispatch(deleteFromTimelines(id)); + }).catch(error => { + dispatch(deleteStatusFail(id, error)); + }); + }; +}; + +export function deleteStatusRequest(id) { + return { + type: STATUS_DELETE_REQUEST, + id: id, + }; +}; + +export function deleteStatusSuccess(id) { + return { + type: STATUS_DELETE_SUCCESS, + id: id, + }; +}; + +export function deleteStatusFail(id, error) { + return { + type: STATUS_DELETE_FAIL, + id: id, + error: error, + }; +}; + +export function fetchContext(id) { + return (dispatch, getState) => { + dispatch(fetchContextRequest(id)); + + api(getState).get(`/api/v1/statuses/${id}/context`).then(response => { + dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants)); + + }).catch(error => { + if (error.response && error.response.status === 404) { + dispatch(deleteFromTimelines(id)); + } + + dispatch(fetchContextFail(id, error)); + }); + }; +}; + +export function fetchContextRequest(id) { + return { + type: CONTEXT_FETCH_REQUEST, + id, + }; +}; + +export function fetchContextSuccess(id, ancestors, descendants) { + return { + type: CONTEXT_FETCH_SUCCESS, + id, + ancestors, + descendants, + statuses: ancestors.concat(descendants), + }; +}; + +export function fetchContextFail(id, error) { + return { + type: CONTEXT_FETCH_FAIL, + id, + error, + skipAlert: true, + }; +}; + +export function muteStatus(id) { + return (dispatch, getState) => { + dispatch(muteStatusRequest(id)); + + api(getState).post(`/api/v1/statuses/${id}/mute`).then(() => { + dispatch(muteStatusSuccess(id)); + }).catch(error => { + dispatch(muteStatusFail(id, error)); + }); + }; +}; + +export function muteStatusRequest(id) { + return { + type: STATUS_MUTE_REQUEST, + id, + }; +}; + +export function muteStatusSuccess(id) { + return { + type: STATUS_MUTE_SUCCESS, + id, + }; +}; + +export function muteStatusFail(id, error) { + return { + type: STATUS_MUTE_FAIL, + id, + error, + }; +}; + +export function unmuteStatus(id) { + return (dispatch, getState) => { + dispatch(unmuteStatusRequest(id)); + + api(getState).post(`/api/v1/statuses/${id}/unmute`).then(() => { + dispatch(unmuteStatusSuccess(id)); + }).catch(error => { + dispatch(unmuteStatusFail(id, error)); + }); + }; +}; + +export function unmuteStatusRequest(id) { + return { + type: STATUS_UNMUTE_REQUEST, + id, + }; +}; + +export function unmuteStatusSuccess(id) { + return { + type: STATUS_UNMUTE_SUCCESS, + id, + }; +}; + +export function unmuteStatusFail(id, error) { + return { + type: STATUS_UNMUTE_FAIL, + id, + error, + }; +}; diff --git a/app/javascript/mastodon/actions/store.js b/app/javascript/mastodon/actions/store.js new file mode 100644 index 000000000..a1db0fdd5 --- /dev/null +++ b/app/javascript/mastodon/actions/store.js @@ -0,0 +1,17 @@ +import { Iterable, fromJS } from 'immutable'; + +export const STORE_HYDRATE = 'STORE_HYDRATE'; +export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY'; + +const convertState = rawState => + fromJS(rawState, (k, v) => + Iterable.isIndexed(v) ? v.toList() : v.toMap()); + +export function hydrateStore(rawState) { + const state = convertState(rawState); + + return { + type: STORE_HYDRATE, + state, + }; +}; diff --git a/app/javascript/mastodon/actions/streaming.js b/app/javascript/mastodon/actions/streaming.js new file mode 100644 index 000000000..dcce048ca --- /dev/null +++ b/app/javascript/mastodon/actions/streaming.js @@ -0,0 +1,53 @@ +import { connectStream } from '../stream'; +import { + updateTimeline, + deleteFromTimelines, + refreshHomeTimeline, + connectTimeline, + disconnectTimeline, +} from './timelines'; +import { updateNotifications, refreshNotifications } from './notifications'; +import { getLocale } from '../locales'; + +const { messages } = getLocale(); + +export function connectTimelineStream (timelineId, path, pollingRefresh = null) { + + return connectStream (path, pollingRefresh, (dispatch, getState) => { + const locale = getState().getIn(['meta', 'locale']); + return { + onConnect() { + dispatch(connectTimeline(timelineId)); + }, + + onDisconnect() { + dispatch(disconnectTimeline(timelineId)); + }, + + onReceive (data) { + switch(data.event) { + case 'update': + dispatch(updateTimeline(timelineId, JSON.parse(data.payload))); + break; + case 'delete': + dispatch(deleteFromTimelines(data.payload)); + break; + case 'notification': + dispatch(updateNotifications(JSON.parse(data.payload), messages, locale)); + break; + } + }, + }; + }); +} + +function refreshHomeTimelineAndNotification (dispatch) { + dispatch(refreshHomeTimeline()); + dispatch(refreshNotifications()); +} + +export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); +export const connectCommunityStream = () => connectTimelineStream('community', 'public:local'); +export const connectMediaStream = () => connectTimelineStream('community', 'public:local'); +export const connectPublicStream = () => connectTimelineStream('public', 'public'); +export const connectHashtagStream = (tag) => connectTimelineStream(`hashtag:${tag}`, `hashtag&tag=${tag}`); diff --git a/app/javascript/mastodon/actions/timelines.js b/app/javascript/mastodon/actions/timelines.js new file mode 100644 index 000000000..09abe2702 --- /dev/null +++ b/app/javascript/mastodon/actions/timelines.js @@ -0,0 +1,206 @@ +import api, { getLinks } from '../api'; +import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; + +export const TIMELINE_UPDATE = 'TIMELINE_UPDATE'; +export const TIMELINE_DELETE = 'TIMELINE_DELETE'; + +export const TIMELINE_REFRESH_REQUEST = 'TIMELINE_REFRESH_REQUEST'; +export const TIMELINE_REFRESH_SUCCESS = 'TIMELINE_REFRESH_SUCCESS'; +export const TIMELINE_REFRESH_FAIL = 'TIMELINE_REFRESH_FAIL'; + +export const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST'; +export const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS'; +export const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL'; + +export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP'; + +export const TIMELINE_CONNECT = 'TIMELINE_CONNECT'; +export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'; + +export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE'; + +export function refreshTimelineSuccess(timeline, statuses, skipLoading, next) { + return { + type: TIMELINE_REFRESH_SUCCESS, + timeline, + statuses, + skipLoading, + next, + }; +}; + +export function updateTimeline(timeline, status) { + return (dispatch, getState) => { + const references = status.reblog ? getState().get('statuses').filter((item, itemId) => (itemId === status.reblog.id || item.get('reblog') === status.reblog.id)).map((_, itemId) => itemId) : []; + const parents = []; + + if (status.in_reply_to_id) { + let parent = getState().getIn(['statuses', status.in_reply_to_id]); + + while (parent && parent.get('in_reply_to_id')) { + parents.push(parent.get('id')); + parent = getState().getIn(['statuses', parent.get('in_reply_to_id')]); + } + } + + dispatch({ + type: TIMELINE_UPDATE, + timeline, + status, + references, + }); + + if (parents.length > 0) { + dispatch({ + type: TIMELINE_CONTEXT_UPDATE, + status, + references: parents, + }); + } + }; +}; + +export function deleteFromTimelines(id) { + return (dispatch, getState) => { + const accountId = getState().getIn(['statuses', id, 'account']); + const references = getState().get('statuses').filter(status => status.get('reblog') === id).map(status => [status.get('id'), status.get('account')]); + const reblogOf = getState().getIn(['statuses', id, 'reblog'], null); + + dispatch({ + type: TIMELINE_DELETE, + id, + accountId, + references, + reblogOf, + }); + }; +}; + +export function refreshTimelineRequest(timeline, skipLoading) { + return { + type: TIMELINE_REFRESH_REQUEST, + timeline, + skipLoading, + }; +}; + +export function refreshTimeline(timelineId, path, params = {}) { + return function (dispatch, getState) { + const timeline = getState().getIn(['timelines', timelineId], ImmutableMap()); + + if (timeline.get('isLoading') || timeline.get('online')) { + return; + } + + const ids = timeline.get('items', ImmutableList()); + const newestId = ids.size > 0 ? ids.first() : null; + + let skipLoading = timeline.get('loaded'); + + if (newestId !== null) { + params.since_id = newestId; + } + + dispatch(refreshTimelineRequest(timelineId, skipLoading)); + + api(getState).get(path, { params }).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(refreshTimelineSuccess(timelineId, response.data, skipLoading, next ? next.uri : null)); + }).catch(error => { + dispatch(refreshTimelineFail(timelineId, error, skipLoading)); + }); + }; +}; + +export const refreshHomeTimeline = () => refreshTimeline('home', '/api/v1/timelines/home'); +export const refreshPublicTimeline = () => refreshTimeline('public', '/api/v1/timelines/public'); +export const refreshCommunityTimeline = () => refreshTimeline('community', '/api/v1/timelines/public', { local: true }); +export const refreshAccountTimeline = accountId => refreshTimeline(`account:${accountId}`, `/api/v1/accounts/${accountId}/statuses`); +export const refreshAccountMediaTimeline = accountId => refreshTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { only_media: true }); +export const refreshHashtagTimeline = hashtag => refreshTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`); + +export function refreshTimelineFail(timeline, error, skipLoading) { + return { + type: TIMELINE_REFRESH_FAIL, + timeline, + error, + skipLoading, + skipAlert: error.response && error.response.status === 404, + }; +}; + +export function expandTimeline(timelineId, path, params = {}) { + return (dispatch, getState) => { + const timeline = getState().getIn(['timelines', timelineId], ImmutableMap()); + const ids = timeline.get('items', ImmutableList()); + + if (timeline.get('isLoading') || ids.size === 0) { + return; + } + + params.max_id = ids.last(); + params.limit = 10; + + dispatch(expandTimelineRequest(timelineId)); + + api(getState).get(path, { params }).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null)); + }).catch(error => { + dispatch(expandTimelineFail(timelineId, error)); + }); + }; +}; + +export const expandHomeTimeline = () => expandTimeline('home', '/api/v1/timelines/home'); +export const expandPublicTimeline = () => expandTimeline('public', '/api/v1/timelines/public'); +export const expandCommunityTimeline = () => expandTimeline('community', '/api/v1/timelines/public', { local: true }); +export const expandAccountTimeline = accountId => expandTimeline(`account:${accountId}`, `/api/v1/accounts/${accountId}/statuses`); +export const expandAccountMediaTimeline = accountId => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { only_media: true }); +export const expandHashtagTimeline = hashtag => expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`); + +export function expandTimelineRequest(timeline) { + return { + type: TIMELINE_EXPAND_REQUEST, + timeline, + }; +}; + +export function expandTimelineSuccess(timeline, statuses, next) { + return { + type: TIMELINE_EXPAND_SUCCESS, + timeline, + statuses, + next, + }; +}; + +export function expandTimelineFail(timeline, error) { + return { + type: TIMELINE_EXPAND_FAIL, + timeline, + error, + }; +}; + +export function scrollTopTimeline(timeline, top) { + return { + type: TIMELINE_SCROLL_TOP, + timeline, + top, + }; +}; + +export function connectTimeline(timeline) { + return { + type: TIMELINE_CONNECT, + timeline, + }; +}; + +export function disconnectTimeline(timeline) { + return { + type: TIMELINE_DISCONNECT, + timeline, + }; +}; diff --git a/app/javascript/mastodon/api.js b/app/javascript/mastodon/api.js new file mode 100644 index 000000000..ecc703c0a --- /dev/null +++ b/app/javascript/mastodon/api.js @@ -0,0 +1,26 @@ +import axios from 'axios'; +import LinkHeader from './link_header'; + +export const getLinks = response => { + const value = response.headers.link; + + if (!value) { + return { refs: [] }; + } + + return LinkHeader.parse(value); +}; + +export default getState => axios.create({ + headers: { + 'Authorization': `Bearer ${getState().getIn(['meta', 'access_token'], '')}`, + }, + + transformResponse: [function (data) { + try { + return JSON.parse(data); + } catch(Exception) { + return data; + } + }], +}); diff --git a/app/javascript/mastodon/base_polyfills.js b/app/javascript/mastodon/base_polyfills.js new file mode 100644 index 000000000..7856b26f9 --- /dev/null +++ b/app/javascript/mastodon/base_polyfills.js @@ -0,0 +1,18 @@ +import 'intl'; +import 'intl/locale-data/jsonp/en'; +import 'es6-symbol/implement'; +import includes from 'array-includes'; +import assign from 'object-assign'; +import isNaN from 'is-nan'; + +if (!Array.prototype.includes) { + includes.shim(); +} + +if (!Object.assign) { + Object.assign = assign; +} + +if (!Number.isNaN) { + Number.isNaN = isNaN; +} diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap new file mode 100644 index 000000000..76ab3374a --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` Autoplay renders a animated avatar 1`] = ` +
+`; + +exports[` Still renders a still avatar 1`] = ` +
+`; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap new file mode 100644 index 000000000..d59fee42f --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap @@ -0,0 +1,24 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` +
+
+
+`; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap new file mode 100644 index 000000000..c3f018d90 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap @@ -0,0 +1,114 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` +`; + +exports[` +`; + +exports[` +`; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap new file mode 100644 index 000000000..533359ffe --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders display name + account name 1`] = ` + + Foo

", + } + } + /> + + + @ + bar@baz + +
+`; diff --git a/app/javascript/mastodon/components/__tests__/avatar-test.js b/app/javascript/mastodon/components/__tests__/avatar-test.js new file mode 100644 index 000000000..dd3f7b7d2 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/avatar-test.js @@ -0,0 +1,36 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { fromJS } from 'immutable'; +import Avatar from '../avatar'; + +describe('', () => { + const account = fromJS({ + username: 'alice', + acct: 'alice', + display_name: 'Alice', + avatar: '/animated/alice.gif', + avatar_static: '/static/alice.jpg', + }); + + const size = 100; + + describe('Autoplay', () => { + it('renders a animated avatar', () => { + const component = renderer.create(); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + }); + + describe('Still', () => { + it('renders a still avatar', () => { + const component = renderer.create(); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + }); + + // TODO add autoplay test if possible +}); diff --git a/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js b/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js new file mode 100644 index 000000000..44addea83 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js @@ -0,0 +1,29 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { fromJS } from 'immutable'; +import AvatarOverlay from '../avatar_overlay'; + +describe(' { + const account = fromJS({ + username: 'alice', + acct: 'alice', + display_name: 'Alice', + avatar: '/animated/alice.gif', + avatar_static: '/static/alice.jpg', + }); + + const friend = fromJS({ + username: 'eve', + acct: 'eve@blackhat.lair', + display_name: 'Evelyn', + avatar: '/animated/eve.gif', + avatar_static: '/static/eve.jpg', + }); + + it('renders a overlay avatar', () => { + const component = renderer.create(); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/app/javascript/mastodon/components/__tests__/button-test.js b/app/javascript/mastodon/components/__tests__/button-test.js new file mode 100644 index 000000000..160cd3cbc --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/button-test.js @@ -0,0 +1,75 @@ +import { shallow } from 'enzyme'; +import React from 'react'; +import renderer from 'react-test-renderer'; +import Button from '../button'; + +describe('); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('renders the props.text instead of children', () => { + const text = 'foo'; + const children =

children

; + const component = renderer.create(); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('renders class="button--block" if props.block given', () => { + const component = renderer.create(