diff options
63 files changed, 2810 insertions, 1637 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1bfe3179..3673b8b7 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,6 +4,7 @@ Contributors of this project. - Coco Snuss (cocosnuss@social.heldscal.la): Code - wakarimasen (wakarimasen@shitposter.club): NSFW hiding image - dtluna (dtluna@social.heldscal.la): Code -- sonyam (sonyam@social.heldscal.la): Default background image +- sonyam (sonyam@social.heldscal.la): Background images - hakui (hakui@freezepeach.xyz): CSS and styling -- shpuld (shpuld@shitposter.club): CSS and styling
\ No newline at end of file +- shpuld (shpuld@shitposter.club): CSS and styling +- Vincent Guth (https://unsplash.com/photos/XrwVIFy6rTw): Background images. diff --git a/src/App.scss b/src/App.scss index 95a653ce..a8601220 100644 --- a/src/App.scss +++ b/src/App.scss @@ -1,10 +1,13 @@ @import './_variables.scss'; + #app { - background-size: cover; - background-attachment: fixed; - background-repeat: no-repeat; - background-position: 0 50px; - min-height: 100vh; + background-size: cover; + background-attachment: fixed; + background-repeat: no-repeat; + background-position: 0 50px; + min-height: 100vh; + max-width: 100%; + overflow: hidden; } i { @@ -12,7 +15,7 @@ i { } h4 { - margin: 0; + margin: 0; } #content { @@ -26,154 +29,286 @@ h4 { } .text-center { - text-align: center; + text-align: center; } body { - font-family: sans-serif; - font-size: 14px; - margin: 0; + font-family: sans-serif; + font-size: 14px; + margin: 0; + color: $fallback--fg; + color: var(--fg, $fallback--fg); + max-width: 100vw; + overflow-x: hidden; } a { - text-decoration: none; + text-decoration: none; + color: $fallback--link; + color: var(--link, $fallback--link); } button{ - user-select: none; + user-select: none; + color: $fallback--fg; + color: var(--fg, $fallback--fg); + background-color: $fallback--btn; + background-color: var(--btn, $fallback--btn); + border: none; + border-radius: $fallback--btnRadius; + border-radius: var(--btnRadius, $fallback--btnRadius); + cursor: pointer; + border-top: 1px solid rgba(255, 255, 255, 0.2); + border-bottom: 1px solid rgba(0, 0, 0, 0.2); + box-shadow: 0px 0px 2px black; + font-size: 14px; + font-family: sans-serif; + + &:hover { + box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3); + } + + &:disabled { + cursor: not-allowed; + opacity: 0.5; + } + + &.pressed { + color: $fallback--faint; + color: var(--faint, $fallback--faint); + background-color: $fallback--bg; + background-color: var(--bg, $fallback--bg) + } +} + +label.select { + padding: 0; + +} + +input, textarea, .select { + border: none; + border-radius: $fallback--btnRadius; + border-radius: var(--btnRadius, $fallback--btnRadius); + border-bottom: 1px solid rgba(255, 255, 255, 0.2); + border-top: 1px solid rgba(0, 0, 0, 0.2); + box-shadow: 0px 0px 2px black inset; + background-color: $fallback--lightBg; + background-color: var(--lightBg, $fallback--lightBg); + color: $fallback--lightFg; + color: var(--lightFg, $fallback--lightFg); + font-family: sans-serif; + font-size: 14px; + padding: 8px 7px; + box-sizing: border-box; + display: inline-block; + position: relative; + height: 29px; + line-height: 16px; + + .icon-down-open { + position: absolute; + top: 0; + bottom: 0; + right: 5px; + height: 100%; + color: $fallback--fg; + color: var(--fg, $fallback--fg); + line-height: 29px; + z-index: 0; + pointer-events: none; + } + + select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: transparent; border: none; - border-radius: 5px; - cursor: pointer; - border-top: 1px solid rgba(255, 255, 255, 0.2); - border-bottom: 1px solid rgba(0, 0, 0, 0.2); - box-shadow: 0px 0px 2px black; - font-size: 14px; - font-family: sans-serif; - - &:hover { - box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3); - } + margin: 0; + color: $fallback--fg; + color: var(--fg, $fallback--fg); + padding: 4px 2em 3px 3px; + width: 100%; + z-index: 1; + height: 29px; + line-height: 16px; + } - &:disabled { - cursor: not-allowed; - opacity: 0.5; + &[type=radio], + &[type=checkbox] { + display: none; + &:checked + label::before { + color: $fallback--fg; + color: var(--fg, $fallback--fg); } + + label::before { + display: inline-block; + content: '✔'; + transition: color 200ms; + width: 1.1em; + height: 1.1em; + border-radius: $fallback--checkBoxRadius; + border-radius: var(--checkBoxRadius, $fallback--checkBoxRadius); + border-bottom: 1px solid rgba(255, 255, 255, 0.2); + border-top: 1px solid rgba(0, 0, 0, 0.2); + box-shadow: 0px 0px 2px black inset; + margin-right: .5em; + background-color: $fallback--btn; + background-color: var(--btn, $fallback--btn); + vertical-align: top; + text-align: center; + line-height: 1.1em; + font-size: 1.1em; + box-sizing: border-box; + color: transparent; + overflow: hidden; + box-sizing: border-box; + } + } } +i[class*=icon-] { + color: $fallback--icon; + color: var(--icon, $fallback--icon) +} + + .container { - display: flex; - flex-wrap: wrap; - margin: 0; - padding: 0 10px 0 10px; + display: flex; + flex-wrap: wrap; + margin: 0; + padding: 0 10px 0 10px; } .gaps { - margin: -1em 0 0 -1em; + margin: -1em 0 0 -1em; } .item { - flex: 1; - line-height: 21px; - height: 21px; - overflow: hidden; + flex: 1; + line-height: 50px; + height: 50px; + overflow: hidden; - .nav-icon { - font-size: 1.1em; - margin-left: 0.4em; - } + .nav-icon { + font-size: 1.1em; + margin-left: 0.4em; + } } .gaps > .item { - padding: 1em 0 0 1em; + padding: 1em 0 0 1em; } .auto-size { - flex: 1 + flex: 1 } nav { - width: 100%; + width: 100%; + align-items: center; + position: fixed; + height: 50px; + + .inner-nav { + padding-left: 20px; + padding-right: 20px; + display: flex; align-items: center; - position: fixed; + flex-basis: 970px; + margin: auto; height: 50px; + background-repeat: no-repeat; + background-position: center; + background-size: auto 80%; - .inner-nav { - padding-left: 20px; - padding-right: 20px; - display: flex; - align-items: center; - flex-basis: 970px; - margin: auto; - height: 50px; - background-repeat: no-repeat; - background-position: center; - background-size: contain; + a i { + color: $fallback--link; + color: var(--link, $fallback--link); } + } } main-router { - flex: 1; + flex: 1; } .status.compact { - color: rgba(0, 0, 0, 0.42); - font-weight: 300; + color: rgba(0, 0, 0, 0.42); + font-weight: 300; - p { - margin: 0; - font-size: 0.8em - } + p { + margin: 0; + font-size: 0.8em + } } /* Panel */ .panel { - display: flex; - flex-direction: column; - margin: 0.5em; + display: flex; + flex-direction: column; + margin: 0.5em; - border-radius: 10px; - box-shadow: 1px 1px 4px rgba(0,0,0,.6); - overflow: hidden; + background-color: $fallback--bg; + background-color: var(--bg, $fallback--bg); + + border-radius: $fallback--panelRadius; + border-radius: var(--panelRadius, $fallback--panelRadius); + box-shadow: 1px 1px 4px rgba(0,0,0,.6); } .panel-body:empty::before { - content: "¯\\_(ツ)_/¯"; // Could use words but it'd require translations - display: block; - margin: 1em; - text-align: center; + content: "¯\\_(ツ)_/¯"; // Could use words but it'd require translations + display: block; + margin: 1em; + text-align: center; } .panel-heading { - border-radius: 10px 10px 0 0; - background-size: cover; - padding: 0.6em 1.0em; - text-align: left; - font-size: 1.3em; - line-height: 24px; + border-radius: $fallback--panelRadius $fallback--panelRadius 0 0; + border-radius: var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius) 0 0; + background-size: cover; + padding: 0.6em 1.0em; + text-align: left; + font-size: 1.3em; + line-height: 24px; + background-color: $fallback--btn; + background-color: var(--btn, $fallback--btn); +} + +.panel-heading.stub { + border-radius: $fallback--panelRadius; + border-radius: var(--panelRadius, $fallback--panelRadius); } .panel-footer { - border-radius: 0 0 10px 10px; + border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius; + border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); } .panel-body > p { - line-height: 18px; - padding: 1em; - margin: 0; + line-height: 18px; + padding: 1em; + margin: 0; } .container > * { - min-width: 0px; + min-width: 0px; } .fa { - color: grey; + color: grey; } nav { - z-index: 1000; - box-shadow: 0px 0px 4px rgba(0,0,0,.6); + z-index: 1000; + background-color: $fallback--btn; + background-color: var(--btn, $fallback--btn); + color: $fallback--faint; + color: var(--faint, $fallback--faint); + box-shadow: 0px 0px 4px rgba(0,0,0,.6); } .fade-enter-active, .fade-leave-active { @@ -184,9 +319,9 @@ nav { } .main { - flex-basis: 60%; - flex-grow: 1; - flex-shrink: 1; + flex-basis: 60%; + flex-grow: 1; + flex-shrink: 1; } .sidebar-bounds { @@ -201,20 +336,20 @@ nav { } .mobile-shown { - display: none; + display: none; } .panel-switcher { - display: none; - width: 100%; - height: 46px; - button { - display: block; - flex: 1; - max-height: 32px; - margin: 0.5em; - padding: 0.5em; - } + display: none; + width: 100%; + height: 46px; + button { + display: block; + flex: 1; + max-height: 32px; + margin: 0.5em; + padding: 0.5em; + } } @media all and (min-width: 960px) { @@ -248,25 +383,46 @@ nav { } } +.alert { + margin: 0.35em; + padding: 0.25em; + border-radius: $fallback--tooltipRadius; + border-radius: var(--tooltipRadius, $fallback--tooltipRadius); + color: $fallback--faint; + color: var(--faint, $fallback--faint); + min-height: 28px; + line-height: 28px; + + &.error { + background-color: $fallback--cAlertRed; + background-color: var(--cAlertRed, $fallback--cAlertRed); + } +} + +.faint { + color: $fallback--faint; + color: var(--faint, $fallback--faint); +} + @media all and (max-width: 959px) { - .mobile-hidden { - display: none; - } + .mobile-hidden { + display: none; + } - .panel-switcher { - display: flex; - } + .panel-switcher { + display: flex; + } - .container { - padding: 0 0 0 0; - } + .container { + padding: 0 0 0 0; + } - .panel { - margin: 0.5em 0 0.5em 0; - } + .panel { + margin: 0.5em 0 0.5em 0; + } } .item.right { - text-align: right; - padding-right: 20px; + text-align: right; + padding-right: 20px; } diff --git a/src/App.vue b/src/App.vue index 1d8dd6c8..923d411b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,6 +1,6 @@ <template> - <div id="app" v-bind:style="style" class="base02-background"> - <nav class='container base02-background base05' @click="scrollToTop()" id="nav"> + <div id="app" v-bind:style="style"> + <nav class='container' @click="scrollToTop()" id="nav"> <div class='inner-nav' :style="logoStyle"> <div class='item'> <router-link :to="{ name: 'root'}">{{sitename}}</router-link> @@ -14,8 +14,8 @@ </nav> <div class="container" id="content"> <div class="panel-switcher"> - <button @click="activatePanel('sidebar')" class="base02-background base05">Sidebar</button> - <button @click="activatePanel('timeline')" class="base02-background base05">Timeline</button> + <button @click="activatePanel('sidebar')">Sidebar</button> + <button @click="activatePanel('timeline')">Timeline</button> </div> <div class="sidebar-flexer" :class="{ 'mobile-hidden': mobileActivePanel != 'sidebar'}"> <div class="sidebar-bounds"> @@ -25,7 +25,6 @@ <nav-panel></nav-panel> <instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel> <who-to-follow-panel v-if="currentUser && showWhoToFollowPanel"></who-to-follow-panel> - <chat-panel v-if="currentUser && chat"></chat-panel> <notifications v-if="currentUser"></notifications> </div> </div> @@ -37,6 +36,7 @@ </transition> </div> </div> + <chat-panel v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel> </div> </template> diff --git a/src/_variables.scss b/src/_variables.scss index d2b7065d..d90a1d48 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -1,7 +1,27 @@ $main-color: #f58d2c; $main-background: white; $darkened-background: whitesmoke; -$green: #0fa00f; -$blue: #0095ff; -$red: #ff0000; +$fallback--bg: #121a24; +$fallback--btn: #182230; +$fallback--faint: #999; +$fallback--fg: #b9b9ba; +$fallback--link: #d8a070; +$fallback--icon: #666; +$fallback--lightBg: rgb(21, 30, 42); +$fallback--lightFg: #b9b9ba; +$fallback--border: #222; +$fallback--cRed: #ff0000; +$fallback--cBlue: #0095ff; +$fallback--cGreen: #0fa00f; +$fallback--cOrange: orange; + +$fallback--cAlertRed: rgba(211,16,20,.5); + +$fallback--panelRadius: 10px; +$fallback--checkBoxRadius: 2px; +$fallback--btnRadius: 4px; +$fallback--tooltipRadius: 5px; +$fallback--avatarRadius: 4px; +$fallback--avatarAltRadius: 10px; +$fallback--attachmentRadius: 10px; diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js index 8a2a3826..d9bc4477 100644 --- a/src/components/attachment/attachment.js +++ b/src/components/attachment/attachment.js @@ -1,3 +1,4 @@ +import StillImage from '../still-image/still-image.vue' import nsfwImage from '../../assets/nsfw.png' import fileTypeService from '../../services/file_type/file_type.service.js' @@ -5,7 +6,8 @@ const Attachment = { props: [ 'attachment', 'nsfw', - 'statusId' + 'statusId', + 'size' ], data () { return { @@ -16,6 +18,9 @@ const Attachment = { img: document.createElement('img') } }, + components: { + StillImage + }, computed: { type () { return fileTypeService.fileType(this.attachment.mimetype) @@ -25,6 +30,12 @@ const Attachment = { }, isEmpty () { return (this.type === 'html' && !this.attachment.oembed) || this.type === 'unknown' + }, + isSmall () { + return this.size === 'small' + }, + fullwidth () { + return fileTypeService.fileType(this.attachment.mimetype) === 'html' } }, methods: { diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue index d6a51ffd..b2f63668 100644 --- a/src/components/attachment/attachment.vue +++ b/src/components/attachment/attachment.vue @@ -1,5 +1,8 @@ <template> - <div class="attachment base03-border" :class="{[type]: true, loading}" v-show="!isEmpty"> + <div v-if="size==='hide'"> + <a class="placeholder" v-if="type !== 'html'" target="_blank" :href="attachment.url">[{{nsfw ? "NSFW/" : ""}}{{type.toUpperCase()}}]</a> + </div> + <div v-else class="attachment" :class="{[type]: true, loading, 'small-attachment': isSmall, 'fullwidth': fullwidth}" v-show="!isEmpty"> <a class="image-attachment" v-if="hidden" @click.prevent="toggleHidden()"> <img :key="nsfwImage" :src="nsfwImage"/> </a> @@ -8,10 +11,10 @@ </div> <a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank"> - <img class="base03-border" referrerpolicy="no-referrer" :src="attachment.large_thumb_url || attachment.url"/> + <StillImage :class="{'small': isSmall}" referrerpolicy="no-referrer" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/> </a> - <video class="base03" v-if="type === 'video' && !hidden" :src="attachment.url" controls loop></video> + <video :class="{'small': isSmall}" v-if="type === 'video' && !hidden" :src="attachment.url" controls loop></video> <audio v-if="type === 'audio'" :src="attachment.url" controls></audio> @@ -30,110 +33,145 @@ <script src="./attachment.js"></script> <style lang="scss"> - .attachments { - display: flex; - flex-wrap: wrap; - margin-right: -0.7em; - - .attachment.media-upload-container { - flex: 0 0 auto; - max-height: 300px; - max-width: 100%; +@import '../../_variables.scss'; + +.attachments { + display: flex; + flex-wrap: wrap; + margin-right: -0.7em; + + .attachment.media-upload-container { + flex: 0 0 auto; + max-height: 300px; + max-width: 100%; + } + + .placeholder { + margin-right: 0.5em; + } + + .small-attachment { + &.image, &.video { + max-width: 35%; + } + max-height: 100px; + } + + .attachment { + flex: 1 0 30%; + margin: 0.5em 0.7em 0.6em 0.0em; + align-self: flex-start; + line-height: 0; + + border-style: solid; + border-width: 1px; + border-radius: $fallback--attachmentRadius; + border-radius: var(--attachmentRadius, $fallback--attachmentRadius); + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + overflow: hidden; + } + .fullwidth { + flex-basis: 100%; + } + // fixes small gap below video + &.video { + line-height: 0; + } + + &.html { + flex-basis: 90%; + width: 100%; + display: flex; + } + + &.loading { + cursor: progress; + } + + .hider { + position: absolute; + margin: 10px; + padding: 5px; + background: rgba(230,230,230,0.6); + font-weight: bold; + z-index: 4; + } + + .small { + max-height: 100px; + } + video { + max-height: 500px; + height: 100%; + width: 100%; + z-index: 0; + } + + audio { + width: 100%; + } + + img.media-upload { + line-height: 0; + max-height: 300px; + max-width: 100%; + } + + .oembed { + line-height: 1.2em; + flex: 1 0 100%; + width: 100%; + margin-right: 15px; + display: flex; + + img { + width: 100%; + } + + .image { + flex: 1; + img { + border: 0px; + border-radius: 5px; + height: 100%; + object-fit: cover; + } + } + + .text { + flex: 2; + margin: 8px; + word-break: break-all; + h1 { + font-size: 14px; + margin: 0px; } - - .attachment { - flex: 1 0 30%; - margin: 0.5em 0.7em 0.6em 0.0em; - align-self: flex-start; - - border-style: solid; - border-width: 1px; - border-radius: 5px; - overflow: hidden; - - // fixes small gap below video - &.video { - line-height: 0; - } - - &.html { - flex-basis: 90%; - width: 100%; - display: flex; - } - - &.loading { - cursor: progress; - } - - .hider { - position: absolute; - margin: 10px; - padding: 5px; - background: rgba(230,230,230,0.6); - font-weight: bold; - z-index: 4; - } - - video { - max-height: 500px; - height: 100%; - width: 100%; - z-index: 0; - } - - audio { - width: 100%; - } - - img.media-upload { - margin-bottom: -2px; - max-height: 300px; - max-width: 100%; - } - - .oembed { - width: 100%; - margin-right: 15px; - display: flex; - - img { - width: 100%; - } - - .image { - flex: 1; - img { - border: 0px; - border-radius: 5px; - height: 100%; - object-fit: cover; - } - } - - .text { - flex: 2; - margin: 8px; - word-break: break-all; - h1 { - font-size: 14px; - margin: 0px; - } - } - } - - a.image-attachment { - display: flex; - flex: 1; - - img { - object-fit: contain; - width: 100%; - height: 100%; /* If this isn't here, chrome will stretch the images */ - max-height: 500px; - image-orientation: from-image; - } - } + } + } + + .image-attachment { + display: flex; + flex: 1; + + .still-image { + width: 100%; + height: 100%; + } + + .small { + img { + max-height: 100px; } - } + } + + img { + object-fit: contain; + width: 100%; + height: 100%; /* If this isn't here, chrome will stretch the images */ + max-height: 500px; + image-orientation: from-image; + } + } +} </style> diff --git a/src/components/chat_panel/chat_panel.js b/src/components/chat_panel/chat_panel.js index b146c5d9..d528d0a1 100644 --- a/src/components/chat_panel/chat_panel.js +++ b/src/components/chat_panel/chat_panel.js @@ -2,7 +2,8 @@ const chatPanel = { data () { return { currentMessage: '', - channel: null + channel: null, + collapsed: false } }, computed: { @@ -14,6 +15,9 @@ const chatPanel = { submit (message) { this.$store.state.chat.channel.push('new_msg', {text: message}, 10000) this.currentMessage = '' + }, + togglePanel () { + this.collapsed = !this.collapsed } } } diff --git a/src/components/chat_panel/chat_panel.vue b/src/components/chat_panel/chat_panel.vue index ec379db5..30070d3e 100644 --- a/src/components/chat_panel/chat_panel.vue +++ b/src/components/chat_panel/chat_panel.vue @@ -1,26 +1,40 @@ <template> - <div class="chat-panel"> - <div class="panel panel-default base01-background"> - <div class="panel-heading timeline-heading base02-background base04"> + <div class="chat-panel" v-if="!this.collapsed"> + <div class="panel panel-default"> + <div class="panel-heading timeline-heading chat-heading" @click.stop.prevent="togglePanel"> <div class="title"> {{$t('chat.title')}} + <i class="icon-cancel" style="float: right;"></i> </div> </div> <div class="chat-window" v-chat-scroll> <div class="chat-message" v-for="message in messages" :key="message.id"> <span class="chat-avatar"> <img :src="message.author.avatar" /> - {{message.author.username}}: - </span> - <span class="chat-text"> - {{message.text}} </span> + <div class="chat-content"> + <router-link class="chat-name" :to="{ name: 'user-profile', params: { id: message.author.id } }"> + {{message.author.username}} + </router-link> + <br> + <span class="chat-text"> + {{message.text}} + </span> + </div> </div> </div> <div class="chat-input"> - <form @submit.prevent="submit(currentMessage)"> - <input v-model="currentMessage" type="text" > - </form> + <textarea @keyup.enter="submit(currentMessage)" v-model="currentMessage" class="chat-input-textarea" rows="1"></textarea> + </div> + </div> + </div> + <div v-else class="chat-panel"> + <div class="panel panel-default"> + <div class="panel-heading stub timeline-heading chat-heading" @click.stop.prevent="togglePanel"> + <div class="title"> + <i class="icon-comment-empty"></i> + {{$t('chat.title')}} + </div> </div> </div> </div> @@ -29,30 +43,56 @@ <script src="./chat_panel.js"></script> <style lang="scss"> - .chat-window { - max-height: 200px; - overflow-y: auto; - overflow-x: hidden; - } - .chat-message { - padding: 0.2em 0.5em - } - .chat-avatar { - img { - height: 32px; - width: 32px; - border-radius: 5px; - margin-right: 0.5em; - } - } - .chat-input { - display: flex; - form { - flex: auto; - input { - margin: 0.5em; - width: fill-available; - } - } - } +@import '../../_variables.scss'; + +.floating-chat { + position: fixed; + right: 0px; + bottom: 0px; + z-index: 1000; +} + +.chat-heading { + cursor: pointer; + .icon-comment-empty { + color: $fallback--fg; + color: var(--fg, $fallback--fg); + } +} + +.chat-window { + width: 345px; + max-height: 40vh; + overflow-y: auto; + overflow-x: hidden; +} + +.chat-name { +} + +.chat-message { + display: flex; + padding: 0.2em 0.5em +} + +.chat-avatar { + img { + height: 24px; + width: 24px; + border-radius: $fallback--avatarRadius; + border-radius: var(--avatarRadius, $fallback--avatarRadius); + margin-right: 0.5em; + margin-top: 0.25em; + } +} + +.chat-input { + display: flex; + textarea { + flex: 1; + margin: 0.6em; + min-height: 3.5em; + resize: none; + } +} </style> diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 60d43fff..308e5e7d 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -1,6 +1,6 @@ <template> <div class="timeline panel panel-default"> - <div class="panel-heading base02-background base04 base03-border conversation-heading"> + <div class="panel-heading conversation-heading"> {{ $t('timeline.conversation') }} <span v-if="collapsable" style="float:right;"> <small><a href="#" @click.prevent="$emit('toggleExpanded')">Collapse</a></small> @@ -8,7 +8,16 @@ </div> <div class="panel-body"> <div class="timeline"> - <status v-for="status in conversation" @goto="setHighlight" :key="status.id" :statusoid="status" :expandable='false' :focused="focused(status.id)" :inConversation='true' :highlight="highlight" :replies="getReplies(status.id)"></status> + <status + v-for="status in conversation" + @goto="setHighlight" :key="status.id" + :inlineExpanded="collapsable" :statusoid="status" + :expandable='false' :focused="focused(status.id)" + :inConversation='true' + :highlight="highlight" + :replies="getReplies(status.id)" + class="status-fadein"> + </status> </div> </div> </div> diff --git a/src/components/delete_button/delete_button.js b/src/components/delete_button/delete_button.js index 77da1b87..f2920666 100644 --- a/src/components/delete_button/delete_button.js +++ b/src/components/delete_button/delete_button.js @@ -10,7 +10,7 @@ const DeleteButton = { }, computed: { currentUser () { return this.$store.state.users.currentUser }, - canDelete () { return this.currentUser.rights.delete_others_notice || this.status.user.id === this.currentUser.id } + canDelete () { return this.currentUser && this.currentUser.rights.delete_others_notice || this.status.user.id === this.currentUser.id } } } diff --git a/src/components/delete_button/delete_button.vue b/src/components/delete_button/delete_button.vue index 845ac777..d13547e2 100644 --- a/src/components/delete_button/delete_button.vue +++ b/src/components/delete_button/delete_button.vue @@ -1,20 +1,21 @@ <template> <div v-if="canDelete"> <a href="#" v-on:click.prevent="deleteStatus()"> - <i class='base09 icon-cancel delete-status'></i> + <i class='icon-cancel delete-status'></i> </a> </div> </template> <script src="./delete_button.js" ></script> -<style lang='scss'> - @import '../../_variables.scss'; +<style lang="scss"> +@import '../../_variables.scss'; - .icon-cancel,.delete-status { - cursor: pointer; - &:hover { - color: $red; - } +.icon-cancel,.delete-status { + cursor: pointer; + &:hover { + color: var(--cRed, $fallback--cRed); + color: $fallback--cRed; } +} </style> diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue index 65d368c7..1e1a6970 100644 --- a/src/components/favorite_button/favorite_button.vue +++ b/src/components/favorite_button/favorite_button.vue @@ -1,26 +1,31 @@ <template> <div v-if="loggedIn"> - <i :class='classes' class='favorite-button fav-active base09' @click.prevent='favorite()'/> + <i :class='classes' class='favorite-button fav-active' @click.prevent='favorite()'/> <span v-if='status.fave_num > 0'>{{status.fave_num}}</span> </div> <div v-else> - <i :class='classes' class='favorite-button base09'/> + <i :class='classes' class='favorite-button'/> <span v-if='status.fave_num > 0'>{{status.fave_num}}</span> </div> </template> <script src="./favorite_button.js" ></script> -<style lang='scss'> - .fav-active { - cursor: pointer; - animation-duration: 0.6s; - &:hover { - color: orange; - } - } - .favorite-button.icon-star { - color: orange; +<style lang="scss"> +@import '../../_variables.scss'; + +.fav-active { + cursor: pointer; + animation-duration: 0.6s; + + &:hover { + color: $fallback--cOrange; + color: var(--cOrange, $fallback--cOrange); } +} +.favorite-button.icon-star { + color: $fallback--cOrange; + color: var(--cOrange, $fallback--cOrange); +} </style> diff --git a/src/components/instance_specific_panel/instance_specific_panel.vue b/src/components/instance_specific_panel/instance_specific_panel.vue index b3ea019d..ca8e00c0 100644 --- a/src/components/instance_specific_panel/instance_specific_panel.vue +++ b/src/components/instance_specific_panel/instance_specific_panel.vue @@ -1,6 +1,6 @@ <template> <div class="instance-specific-panel"> - <div class="panel panel-default base01-background"> + <div class="panel panel-default"> <div class="panel-body"> <div v-html="instanceSpecificPanelContent"> </div> diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue index c293d611..67fa95a8 100644 --- a/src/components/login_form/login_form.vue +++ b/src/components/login_form/login_form.vue @@ -1,7 +1,7 @@ <template> - <div class="login panel panel-default base00-background"> + <div class="login panel panel-default"> <!-- Default panel contents --> - <div class="panel-heading base02-background base04"> + <div class="panel-heading"> {{$t('login.login')}} </div> <div class="panel-body"> @@ -17,11 +17,11 @@ <div class='form-group'> <div class='login-bottom'> <div><router-link :to="{name: 'registration'}" v-if='registrationOpen' class='register'>{{$t('login.register')}}</router-link></div> - <button :disabled="loggingIn" type='submit' class='btn btn-default base04 base02-background'>{{$t('login.login')}}</button> + <button :disabled="loggingIn" type='submit' class='btn btn-default'>{{$t('login.login')}}</button> </div> </div> <div v-if="authError" class='form-group'> - <div class='error base05'>{{authError}}</div> + <div class='alert error'>{{authError}}</div> </div> </form> </div> @@ -31,27 +31,16 @@ <script src="./login_form.js" ></script> <style lang="scss"> +@import '../../_variables.scss'; .login-form { - input { - border-width: 1px; - border-style: solid; - border-color: silver; - border-radius: 5px; - padding: 0.1em 0.2em 0.2em 0.2em; - } - .btn { min-height: 28px; width: 10em; } .error { - border-radius: 5px; text-align: center; - background-color: rgba(255, 48, 16, 0.65); - min-height: 28px; - line-height: 28px; } .register { @@ -66,5 +55,4 @@ justify-content: space-between; } } - </style> diff --git a/src/components/media_upload/media_upload.vue b/src/components/media_upload/media_upload.vue index 9e6ad608..8b931d2d 100644 --- a/src/components/media_upload/media_upload.vue +++ b/src/components/media_upload/media_upload.vue @@ -1,8 +1,8 @@ <template> <div class="media-upload" @drop.prevent @dragover.prevent="fileDrag" @drop="fileDrop"> <label class="btn btn-default"> - <i class="base09 icon-spin4 animate-spin" v-if="uploading"></i> - <i class="base09 icon-upload" v-if="!uploading"></i> + <i class="icon-spin4 animate-spin" v-if="uploading"></i> + <i class="icon-upload" v-if="!uploading"></i> <input type=file style="position: fixed; top: -100em"></input> </label> </div> diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue index aea841e9..6f949afb 100644 --- a/src/components/nav_panel/nav_panel.vue +++ b/src/components/nav_panel/nav_panel.vue @@ -1,24 +1,24 @@ <template> <div class="nav-panel"> - <div class="panel panel-default base01-background"> - <ul class="base03-border"> + <div class="panel panel-default"> + <ul> <li v-if='currentUser'> - <router-link class="base00-background" to='/main/friends'> + <router-link to='/main/friends'> {{ $t("nav.timeline") }} </router-link> </li> <li v-if='currentUser'> - <router-link class="base00-background" :to="{ name: 'mentions', params: { username: currentUser.screen_name } }"> + <router-link :to="{ name: 'mentions', params: { username: currentUser.screen_name } }"> {{ $t("nav.mentions") }} </router-link> </li> <li> - <router-link class="base00-background" to='/main/public'> + <router-link to='/main/public'> {{ $t("nav.public_tl") }} </router-link> </li> <li> - <router-link class="base00-background" to='/main/all'> + <router-link to='/main/all'> {{ $t("nav.twkn") }} </router-link> </li> @@ -30,43 +30,61 @@ <script src="./nav_panel.js" ></script> <style lang="scss"> - .nav-panel ul { - list-style: none; - margin: 0; - padding: 0; - } +@import '../../_variables.scss'; - .nav-panel li { - border-bottom: 1px solid; - border-color: inherit; - padding: 0; - &:first-child a { - border-top-right-radius: 10px; - border-top-left-radius: 10px; - } - &:last-child a { - border-bottom-right-radius: 10px; - border-bottom-left-radius: 10px; - } - } +.nav-panel .panel { + overflow: hidden; +} +.nav-panel ul { + list-style: none; + margin: 0; + padding: 0; +} - .nav-panel li:last-child { - border: none; - } +.nav-panel li { + border-bottom: 1px solid; + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + background-color: $fallback--bg; + background-color: var(--bg, $fallback--bg); + padding: 0; - .nav-panel a { - display: block; - padding: 0.8em 0.85em; - &:hover { - background-color: transparent; - } - &.router-link-active { - font-weight: bolder; - background-color: transparent; - &:hover { - text-decoration: underline; - } - } - } + &:first-child a { + border-top-right-radius: $fallback--panelRadius; + border-top-right-radius: var(--panelRadius, $fallback--panelRadius); + border-top-left-radius: $fallback--panelRadius; + border-top-left-radius: var(--panelRadius, $fallback--panelRadius); + } + &:last-child a { + border-bottom-right-radius: $fallback--panelRadius; + border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius); + border-bottom-left-radius: $fallback--panelRadius; + border-bottom-left-radius: var(--panelRadius, $fallback--panelRadius); + } +} + +.nav-panel li:last-child { + border: none; +} + +.nav-panel a { + display: block; + padding: 0.8em 0.85em; + + &:hover { + background-color: $fallback--lightBg; + background-color: var(--lightBg, $fallback--lightBg); + } + + &.router-link-active { + font-weight: bolder; + background-color: $fallback--lightBg; + background-color: var(--lightBg, $fallback--lightBg); + + &:hover { + text-decoration: underline; + } + } +} </style> diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js new file mode 100644 index 00000000..3a274374 --- /dev/null +++ b/src/components/notification/notification.js @@ -0,0 +1,24 @@ +import Status from '../status/status.vue' +import StillImage from '../still-image/still-image.vue' +import UserCardContent from '../user_card_content/user_card_content.vue' + +const Notification = { + data () { + return { + userExpanded: false + } + }, + props: [ + 'notification' + ], + components: { + Status, StillImage, UserCardContent + }, + methods: { + toggleUserExpanded () { + this.userExpanded = !this.userExpanded + } + } +} + +export default Notification diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue new file mode 100644 index 00000000..eed598a8 --- /dev/null +++ b/src/components/notification/notification.vue @@ -0,0 +1,37 @@ +<template> + <status v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status> + <div class="non-mention" v-else> + <a class='avatar-container' :href="notification.action.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded"> + <StillImage class='avatar-compact' :src="notification.action.user.profile_image_url_original"/> + </a> + <div class='notification-right'> + <div class="usercard notification-usercard" v-if="userExpanded"> + <user-card-content :user="notification.action.user" :switcher="false"></user-card-content> + </div> + <span class="notification-details"> + <div class="name-and-action"> + <span class="username" :title="'@'+notification.action.user.screen_name">{{ notification.action.user.name }}</span> + <span v-if="notification.type === 'favorite'"> + <i class="fa icon-star lit"></i> + <small>{{$t('notifications.favorited_you')}}</small> + </span> + <span v-if="notification.type === 'repeat'"> + <i class="fa icon-retweet lit"></i> + <small>{{$t('notifications.repeated_you')}}</small> + </span> + <span v-if="notification.type === 'follow'"> + <i class="fa icon-user-plus lit"></i> + <small>{{$t('notifications.followed_you')}}</small> + </span> + </div> + <small class="timeago"><router-link :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small> + </span> + <div class="follow-text" v-if="notification.type === 'follow'"> + <router-link :to="{ name: 'user-profile', params: { id: notification.action.user.id } }">@{{notification.action.user.screen_name}}</router-link> + </div> + <status v-else class="faint" :compact="true" :statusoid="notification.status" :noHeading="true"></status> + </div> + </div> +</template> + +<script src="./notification.js"></script> diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 5f0d7f26..f8314bfc 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -1,11 +1,11 @@ -import Status from '../status/status.vue' +import Notification from '../notification/notification.vue' import { sortBy, take, filter } from 'lodash' const Notifications = { data () { return { - visibleNotificationCount: 10 + visibleNotificationCount: 20 } }, computed: { @@ -23,15 +23,10 @@ const Notifications = { }, unseenCount () { return this.unseenNotifications.length - }, - hiderStyle () { - return { - background: `linear-gradient(to bottom, rgba(0, 0, 0, 0), ${this.$store.state.config.colors['base00']} 80%)` - } } }, components: { - Status + Notification }, watch: { unseenCount (count) { diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 241f10b4..9cbb1226 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -4,10 +4,24 @@ // a bit of a hack to allow scrolling below notifications padding-bottom: 15em; + .panel { + background: $fallback--bg; + background: var(--bg, $fallback--bg) + } + + .panel-body { + border-color: $fallback--border; + border-color: var(--border, $fallback--border) + } + .panel-heading { // force the text to stay centered, while keeping // the button in the right side of the panel heading position: relative; + background: $fallback--btn; + background: var(--btn, $fallback--btn); + color: $fallback--fg; + color: var(--fg, $fallback--fg); .read-button { position: absolute; right: 0.7em; @@ -18,7 +32,8 @@ .unseen-count { display: inline-block; - background-color: rgba(255, 16, 8, 0.8); + background-color: $fallback--cRed; + background-color: var(--cRed, $fallback--cRed); text-shadow: 0px 0px 3px rgba(0, 0, 0, 0.5); min-width: 1.3em; border-radius: 1.3em; @@ -29,92 +44,167 @@ line-height: 1.3em; } - .notification { - // Will have to use pixels here to ensure consistent distance with - // pad alone and pad + border, browsers bad at rounding this with em, - // they love to give a 1 pixel ghost offset with 0.7em vs 0.3em + 0.4em, - // which does not happen with 10px vs 4px + 6px. - padding: 0.4em 0 0 10px; - display: flex; - border-bottom: 1px solid; - border-bottom-color: inherit; + .unseen { + border-left: 4px solid $fallback--cRed; + border-left: 4px solid var(--cRed, $fallback--cRed); + padding-left: 0; + } +} +.notification { + box-sizing: border-box; + display: flex; + border-bottom: 1px solid; + border-bottom-color: inherit; + padding-left: 4px; + + .avatar-compact { + width: 32px; + height: 32px; + border-radius: $fallback--avatarAltRadius; + border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + overflow: hidden; + line-height: 0; + + &.animated::before { + display: none; + } + } - .text { - min-width: 0px; - word-wrap: break-word; - line-height:18px; - position: relative; - overflow: hidden; + &:hover .animated.avatar { + canvas { + display: none; + } + img { + visibility: visible; + } + } - .icon-retweet.lit { - color: $green; - } + .notification-usercard { + margin: 0; + } - .icon-user-plus.lit { - color: $blue; + .non-mention { + display: flex; + flex: 1; + flex-wrap: nowrap; + padding: 0.6em; + min-width: 0; + .avatar-container { + width: 32px; + height: 32px; + } + .status-el { + .status { + padding: 0.25em 0; + color: $fallback--faint; + color: var($fallback--faint, --faint); } - - .icon-reply.lit { - color: $blue; + padding: 0; + .media-body { + margin: 0; } + } + } - .icon-star.lit { - color: orange; - } + .follow-text { + padding: 0.5em 0; + } - .status-content { - margin: 0; - max-height: 300px; - } + .status-el { + flex: 1; + } - h1 { - word-break: break-all; - margin: 0 0 0.3em; - padding: 0; - font-size: 1em; - line-height:20px; - small { - font-weight: lighter; - } - } + time { + white-space: nowrap; + } - padding: 0.3em 0.8em 0.5em; - p { - margin: 0; - margin-top: 0; - margin-bottom: 0.3em; - } + .notification-right { + flex: 1; + padding-left: 0.8em; + min-width: 0; + } + + .notification-details { + min-width: 0px; + word-wrap: break-word; + line-height:18px; + position: relative; + overflow: hidden; + width: 100%; + flex: 1 1 0; + display: flex; + flex-wrap: nowrap; + + .name-and-action { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; } - .avatar { - padding-top: 0.3em; - width: 32px; - height: 32px; - border-radius: 50%; + .username { + font-weight: bolder; + max-width: 100%; + text-overflow: ellipsis; + white-space: nowrap; + } + .timeago { + float: right; + font-size: 12px; } - &:last-child { - border-bottom: none; - border-radius: 0 0 10px 10px; + .icon-retweet.lit { + color: $fallback--cGreen; + color: var(--cGreen, $fallback--cGreen); } - } - .notification-content { - max-height: 12em; - overflow-y: hidden; - //text-overflow: ellipsis; - } + .icon-user-plus.lit { + color: $fallback--cBlue; + color: var(--cBlue, $fallback--cBlue); + } - .notification-gradient { - position: absolute; - width: 100%; - height: 4em; - margin-top:8em; + .icon-reply.lit { + color: $fallback--cBlue; + color: var(--cBlue, $fallback--cBlue); + } + + .icon-star.lit { + color: orange; + color: $fallback--cOrange; + color: var(--cOrange, $fallback--cOrange); + } + + .status-content { + margin: 0; + max-height: 300px; + } + + h1 { + word-break: break-all; + margin: 0 0 0.3em; + padding: 0; + font-size: 1em; + line-height:20px; + small { + font-weight: lighter; + } + } + + p { + margin: 0; + margin-top: 0; + margin-bottom: 0.3em; + } } - .unseen { - border-left: 4px solid rgba(255, 16, 8, 0.75); - padding-left: 6px; + // ugly as heck + &:last-child { + border-bottom: none; + border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius; + border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); + .status-el { + border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius; + border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); + } } } diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index b341fcef..4fa6e925 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -1,55 +1,14 @@ <template> <div class="notifications"> - <div class="panel panel-default base00-background"> - <div class="panel-heading base02-background base04"> + <div class="panel panel-default"> + <div class="panel-heading"> <span class="unseen-count" v-if="unseenCount">{{unseenCount}}</span> {{$t('notifications.notifications')}} - <button v-if="unseenCount" @click.prevent="markAsSeen" class="base04 base02-background read-button">{{$t('notifications.read')}}</button> + <button v-if="unseenCount" @click.prevent="markAsSeen" class="read-button">{{$t('notifications.read')}}</button> </div> - <div class="panel-body base03-border"> - <div v-for="notification in visibleNotifications" :key="notification" class="notification" :class='{"unseen": !notification.seen}'> - <div> - <a :href="notification.action.user.statusnet_profile_url" target="_blank"> - <img class='avatar' :src="notification.action.user.profile_image_url_original"> - </a> - </div> - <div class='text' style="width: 100%;"> - <div v-if="notification.type === 'favorite'"> - <h1> - <span :title="'@'+notification.action.user.screen_name">{{ notification.action.user.name }}</span> - <i class="fa icon-star lit"></i> - <small><router-link :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small> - </h1> - <div class="notification-gradient" :style="hiderStyle"></div> - <div class="notification-content" v-html="notification.status.statusnet_html"></div> - </div> - <div v-if="notification.type === 'repeat'"> - <h1> - <span :title="'@'+notification.action.user.screen_name">{{ notification.action.user.name }}</span> - <i class="fa icon-retweet lit"></i> - <small><router-link :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small> - </h1> - <div class="notification-gradient" :style="hiderStyle"></div> - <div class="notification-content" v-html="notification.status.statusnet_html"></div> - </div> - <div v-if="notification.type === 'mention'"> - <h1> - <span :title="'@'+notification.action.user.screen_name">{{ notification.action.user.name }}</span> - <i class="fa icon-reply lit"></i> - <small><router-link :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small> - </h1> - <status :compact="true" :statusoid="notification.status"></status> - </div> - <div v-if="notification.type === 'follow'"> - <h1> - <span :title="'@'+notification.action.user.screen_name">{{ notification.action.user.name }}</span> - <i class="fa icon-user-plus lit"></i> - </h1> - <div> - <router-link :to="{ name: 'user-profile', params: { id: notification.action.user.id } }">@{{ notification.action.user.screen_name }}</router-link> {{$t('notifications.followed_you')}} - </div> - </div> - </div> + <div class="panel-body"> + <div v-for="notification in visibleNotifications" :key="notification.action.id" class="notification" :class='{"unseen": !notification.seen}'> + <notification :notification="notification"></notification> </div> </div> </div> diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index 999aa732..6c95873c 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -28,6 +28,9 @@ const PostStatusForm = { components: { MediaUpload }, + mounted () { + this.resize(this.$refs.textarea) + }, data () { let statusText = '' @@ -53,7 +56,8 @@ const PostStatusForm = { candidates () { const firstchar = this.textAtCaret.charAt(0) if (firstchar === '@') { - const matchedUsers = filter(this.users, (user) => (String(user.name + user.screen_name)).match(this.textAtCaret.slice(1))) + const matchedUsers = filter(this.users, (user) => (String(user.name + user.screen_name)).toUpperCase() + .match(this.textAtCaret.slice(1).toUpperCase())) if (matchedUsers.length <= 0) { return false } @@ -234,10 +238,14 @@ const PostStatusForm = { e.dataTransfer.dropEffect = 'copy' }, resize (e) { - e.target.style.height = 'auto' - e.target.style.height = `${e.target.scrollHeight - 10}px` - if (e.target.value === '') { - e.target.style.height = '16px' + const target = e.target || e + target.style.height = 'auto' + const heightPx = target.scrollHeight - 10 + if (heightPx > 54) { + target.style.height = `${target.scrollHeight - 10}px` + } + if (target.value === '') { + target.style.height = '16px' } }, clearError () { diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index 4871bcae..88627e3a 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -1,21 +1,36 @@ <template> - <div class="post-status-form"> - <form @submit.prevent="postStatus(newStatus)"> - <div class="form-group base03-border" > - <textarea @click="setCaret" @keyup="setCaret" v-model="newStatus.status" :placeholder="$t('post_status.default')" rows="1" class="form-control" @keydown.down="cycleForward" @keydown.up="cycleBackward" @keydown.shift.tab="cycleBackward" @keydown.tab="cycleForward" @keydown.enter="replaceCandidate" @keydown.meta.enter="postStatus(newStatus)" @keyup.ctrl.enter="postStatus(newStatus)" @drop="fileDrop" @dragover.prevent="fileDrag" @input="resize" @paste="paste"></textarea> - </div> - <div style="position:relative;" v-if="candidates"> - <div class="autocomplete-panel base05-background"> +<div class="post-status-form"> + <form @submit.prevent="postStatus(newStatus)"> + <div class="form-group" > + <textarea + ref="textarea" + @click="setCaret" + @keyup="setCaret" v-model="newStatus.status" :placeholder="$t('post_status.default')" rows="1" class="form-control" + @keydown.down="cycleForward" + @keydown.up="cycleBackward" + @keydown.shift.tab="cycleBackward" + @keydown.tab="cycleForward" + @keydown.enter="replaceCandidate" + @keydown.meta.enter="postStatus(newStatus)" + @keyup.ctrl.enter="postStatus(newStatus)" + @drop="fileDrop" + @dragover.prevent="fileDrag" + @input="resize" + @paste="paste"> + </textarea> + </div> + <div style="position:relative;" v-if="candidates"> + <div class="autocomplete-panel"> <div v-for="candidate in candidates" @click="replace(candidate.utf || (candidate.screen_name + ' '))"> - <div v-if="candidate.highlighted" class="autocomplete base02"> + <div v-if="candidate.highlighted" class="autocomplete"> <span v-if="candidate.img"><img :src="candidate.img"></span> <span v-else>{{candidate.utf}}</span> - <span>{{candidate.screen_name}}<small class="base02">{{candidate.name}}</small></span> + <span>{{candidate.screen_name}}<small>{{candidate.name}}</small></span> </div> - <div v-else class="autocomplete base04"> + <div v-else class="autocomplete"> <span v-if="candidate.img"><img :src="candidate.img"></img></span> <span v-else>{{candidate.utf}}</span> - <span>{{candidate.screen_name}}<small class="base02">{{candidate.name}}</small></span> + <span>{{candidate.screen_name}}<small>{{candidate.name}}</small></span> </div> </div> </div> @@ -24,18 +39,18 @@ <media-upload @uploading="disableSubmit" @uploaded="addMediaFile" @upload-failed="enableSubmit" :drop-files="dropFiles"></media-upload> <p v-if="isOverLengthLimit" class="error">{{ charactersLeft }}</p> - <p v-else-if="hasStatusLengthLimit" class="base04">{{ charactersLeft }}</p> + <p class="faint" v-else-if="hasStatusLengthLimit">{{ charactersLeft }}</p> - <button v-if="posting" disabled class="btn btn-default base05 base02-background">{{$t('post_status.posting')}}</button> - <button v-else-if="isOverLengthLimit" disabled class="btn btn-default base05 base02-background">{{$t('general.submit')}}</button> - <button v-else :disabled="submitDisabled" type="submit" class="btn btn-default base05 base02-background">{{$t('general.submit')}}</button> + <button v-if="posting" disabled class="btn btn-default">{{$t('post_status.posting')}}</button> + <button v-else-if="isOverLengthLimit" disabled class="btn btn-default">{{$t('general.submit')}}</button> + <button v-else :disabled="submitDisabled" type="submit" class="btn btn-default">{{$t('general.submit')}}</button> </div> - <div class='error' v-if="error"> + <div class='alert error' v-if="error"> Error: {{ error }} <i class="icon-cancel" @click="clearError"></i> </div> <div class="attachments"> - <div class="media-upload-container attachment base03-border" v-for="file in newStatus.files"> + <div class="media-upload-container attachment" v-for="file in newStatus.files"> <i class="fa icon-cancel" @click="removeMediaFile(file)"></i> <img class="thumbnail media-upload" :src="file.image" v-if="type(file) === 'image'"></img> <video v-if="type(file) === 'video'" :src="file.image" controls></video> @@ -50,147 +65,157 @@ <script src="./post_status_form.js"></script> <style lang="scss"> - - .tribute-container { - ul { - padding: 0px; - li { - display: flex; - align-items: center; - } - } - img { - padding: 3px; - width: 16px; - height: 16px; - border-radius: 50%; - } - } - - .post-status-form, .login { - .form-bottom { - display: flex; - padding: 0.5em; - height: 32px; - - button { - width: 10em; - } - - p { - margin: 0.35em; - padding: 0.35em; - display: flex; - } - } - .error { - border-radius: 5px; - text-align: center; - background-color: rgba(255, 48, 16, 0.65); - padding: 0.25em; - margin: 0.35em; - display: flex; - } - - .attachments { - padding: 0 0.5em; - - .attachment { - position: relative; - margin: 0.5em 0.8em 0.2em 0; - } - - i { - position: absolute; - margin: 10px; - padding: 5px; - background: rgba(230,230,230,0.6); - border-radius: 5px; - font-weight: bold; - } - } - - - .btn { - cursor: pointer; - } - - .btn[disabled] { - cursor: not-allowed; - } - - .icon-cancel { - cursor: pointer; - } - form { - display: flex; - flex-direction: column; - padding: 0.6em; - } - - .form-group { - display: flex; - flex-direction: column; - padding: 0.3em 0.5em 0.6em; - line-height:24px; - } - - form textarea { - border: solid; - border-width: 1px; - border-color: inherit; - border-radius: 5px; - line-height:16px; - padding: 5px; - resize: none; - overflow: hidden; - } - - form textarea:focus { - min-height: 48px; - } - - .btn { - cursor: pointer; - } - - .btn[disabled] { - cursor: not-allowed; - } - - .icon-cancel { - cursor: pointer; - z-index: 4; - } - - .autocomplete-panel { - margin: 0 0.5em 0 0.5em; - border-radius: 5px; - position: absolute; - z-index: 1; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5); - min-width: 75%; - } - - .autocomplete { - cursor: pointer; - padding: 0.2em 0.4em 0.2em 0.4em; - border-bottom: 1px solid rgba(0, 0, 0, 0.4); - display: flex; - img { - width: 24px; - height: 24px; - border-radius: 2px; - object-fit: contain; - } - span { - line-height: 24px; - margin: 0 0.1em 0 0.2em; - } - small { - font-style: italic; - } - } - } - +@import '../../_variables.scss'; + +.tribute-container { + ul { + padding: 0px; + li { + display: flex; + align-items: center; + } + } + img { + padding: 3px; + width: 16px; + height: 16px; + border-radius: $fallback--avatarAltRadius; + border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + } +} + +.post-status-form, .login { + .form-bottom { + display: flex; + padding: 0.5em; + height: 32px; + + button { + width: 10em; + } + + p { + margin: 0.35em; + padding: 0.35em; + display: flex; + } + } + + .error { + text-align: center; + } + + .attachments { + padding: 0 0.5em; + + .attachment { + position: relative; + border: 1px solid $fallback--border; + border: 1px solid var(--border, $fallback--border); + margin: 0.5em 0.8em 0.2em 0; + } + + i { + position: absolute; + margin: 10px; + padding: 5px; + background: rgba(230,230,230,0.6); + border-radius: $fallback--attachmentRadius; + border-radius: var(--attachmentRadius, $fallback--attachmentRadius); + font-weight: bold; + } + } + + + .btn { + cursor: pointer; + } + + .btn[disabled] { + cursor: not-allowed; + } + + .icon-cancel { + cursor: pointer; + } + + form { + display: flex; + flex-direction: column; + padding: 0.6em; + } + + .form-group { + display: flex; + flex-direction: column; + padding: 0.3em 0.5em 0.6em; + line-height:24px; + } + + form textarea { + line-height:16px; + resize: none; + overflow: hidden; + transition: min-height 200ms 100ms; + min-height: 1px; + box-sizing: content-box; + } + + form textarea:focus { + min-height: 48px; + } + + .btn { + cursor: pointer; + } + + .btn[disabled] { + cursor: not-allowed; + } + + .icon-cancel { + cursor: pointer; + z-index: 4; + } + + .autocomplete-panel { + margin: 0 0.5em 0 0.5em; + border-radius: $fallback--tooltipRadius; + border-radius: var(--tooltipRadius, $fallback--tooltipRadius); + position: absolute; + z-index: 1; + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5); + min-width: 75%; + background: $fallback--btn; + background: var(--btn, $fallback--btn); + color: $fallback--lightFg; + color: var(--lightFg, $fallback--lightFg); + } + + .autocomplete { + cursor: pointer; + padding: 0.2em 0.4em 0.2em 0.4em; + border-bottom: 1px solid rgba(0, 0, 0, 0.4); + display: flex; + + img { + width: 24px; + height: 24px; + border-radius: $fallback--avatarRadius; + border-radius: var(--avatarRadius, $fallback--avatarRadius); + object-fit: contain; + } + + span { + line-height: 24px; + margin: 0 0.1em 0 0.2em; + } + + small { + margin-left: .5em; + color: $fallback--faint; + color: var(--faint, $fallback--faint); + } + } +} </style> diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue index adc751a3..00f665af 100644 --- a/src/components/registration/registration.vue +++ b/src/components/registration/registration.vue @@ -1,6 +1,6 @@ <template> - <div class="settings panel panel-default base00-background"> - <div class="panel-heading base02-background base04"> + <div class="settings panel panel-default"> + <div class="panel-heading"> {{$t('registration.registration')}} </div> <div class="panel-body"> @@ -39,14 +39,14 @@ </div> --> <div class='form-group'> - <button :disabled="registering" type='submit' class='btn btn-default base05 base02-background'>{{$t('general.submit')}}</button> + <button :disabled="registering" type='submit' class='btn btn-default'>{{$t('general.submit')}}</button> </div> </div> <div class='terms-of-service' v-html="termsofservice"> </div> </div> <div v-if="error" class='form-group'> - <div class='error base05'>{{error}}</div> + <div class='alert error'>{{error}}</div> </div> </form> </div> @@ -55,6 +55,7 @@ <script src="./registration.js"></script> <style lang="scss"> +@import '../../_variables.scss'; .registration-form { display: flex; @@ -87,23 +88,10 @@ } form textarea { - border: solid; - border-width: 1px; - border-color: silver; - border-radius: 5px; line-height:16px; - padding: 5px; resize: vertical; } - input { - border-width: 1px; - border-style: solid; - border-color: silver; - border-radius: 5px; - padding: 0.1em 0.2em 0.2em 0.2em; - } - .captcha { max-width: 350px; margin-bottom: 0.4em; @@ -117,12 +105,7 @@ } .error { - border-radius: 5px; text-align: center; - margin: 0.5em 0.6em 0; - background-color: rgba(255, 48, 16, 0.65); - min-height: 28px; - line-height: 28px; } } diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue index 7a7ea763..1bee3d08 100644 --- a/src/components/retweet_button/retweet_button.vue +++ b/src/components/retweet_button/retweet_button.vue @@ -1,26 +1,28 @@ <template> <div v-if="loggedIn"> - <i :class='classes' class='icon-retweet rt-active base09' v-on:click.prevent='retweet()'></i> + <i :class='classes' class='icon-retweet rt-active' v-on:click.prevent='retweet()'></i> <span v-if='status.repeat_num > 0'>{{status.repeat_num}}</span> </div> <div v-else> - <i :class='classes' class='icon-retweet base09'></i> + <i :class='classes' class='icon-retweet'></i> <span v-if='status.repeat_num > 0'>{{status.repeat_num}}</span> </div> </template> <script src="./retweet_button.js" ></script> -<style lang='scss'> - @import '../../_variables.scss'; - .rt-active { - cursor: pointer; - animation-duration: 0.6s; - &:hover { - color: $green; - } - } - .icon-retweet.retweeted { - color: $green; +<style lang="scss"> +@import '../../_variables.scss'; +.rt-active { + cursor: pointer; + animation-duration: 0.6s; + &:hover { + color: $fallback--cGreen; + color: var(--cGreen, $fallback--cGreen); } +} +.icon-retweet.retweeted { + color: $fallback--cGreen; + color: var(--cGreen, $fallback--cGreen); +} </style> diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js index b88937bb..a26111d6 100644 --- a/src/components/settings/settings.js +++ b/src/components/settings/settings.js @@ -10,7 +10,8 @@ const settings = { muteWordsString: this.$store.state.config.muteWords.join('\n'), autoLoadLocal: this.$store.state.config.autoLoad, streamingLocal: this.$store.state.config.streaming, - hoverPreviewLocal: this.$store.state.config.hoverPreview + hoverPreviewLocal: this.$store.state.config.hoverPreview, + stopGifs: this.$store.state.config.stopGifs } }, components: { @@ -43,6 +44,9 @@ const settings = { muteWordsString (value) { value = filter(value.split('\n'), (word) => trim(word).length > 0) this.$store.dispatch('setOption', { name: 'muteWords', value }) + }, + stopGifs (value) { + this.$store.dispatch('setOption', { name: 'stopGifs', value }) } } } diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index 8fdd09de..b4514ba1 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -1,6 +1,6 @@ <template> - <div class="settings panel panel-default base00-background"> - <div class="panel-heading base02-background base04"> + <div class="settings panel panel-default"> + <div class="panel-heading"> {{$t('settings.settings')}} </div> <div class="panel-body"> @@ -29,8 +29,8 @@ <label for="hideNsfw">{{$t('settings.nsfw_clickthrough')}}</label> </li> <li> - <input type="checkbox" id="autoLoad" v-model="autoLoadLocal"> - <label for="autoLoad">{{$t('settings.autoload')}}</label> + <input type="checkbox" id="autoload" v-model="autoLoadLocal"> + <label for="autoload">{{$t('settings.autoload')}}</label> </li> <li> <input type="checkbox" id="streaming" v-model="streamingLocal"> @@ -40,6 +40,10 @@ <input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal"> <label for="hoverPreview">{{$t('settings.reply_link_preview')}}</label> </li> + <li> + <input type="checkbox" id="stopGifs" v-model="stopGifs"> + <label for="stopGifs">{{$t('settings.stop_gifs')}}</label> + </li> </ul> </div> </div> @@ -50,32 +54,40 @@ </script> <style lang="scss"> - .setting-item { - margin: 1em 1em 1.4em; - textarea { - width: 100%; - height: 100px; - } +@import '../../_variables.scss'; + +.setting-item { + margin: 1em 1em 1.4em; + + textarea { + width: 100%; + height: 100px; + } - .old-avatar { - width: 128px; - border-radius: 5px; - } + .old-avatar { + width: 128px; + border-radius: $fallback--avatarRadius; + border-radius: var(--avatarRadius, $fallback--avatarRadius); + } - .new-avatar { - object-fit: cover; - width: 128px; - height: 128px; - border-radius: 5px; - } + .new-avatar { + object-fit: cover; + width: 128px; + height: 128px; + border-radius: $fallback--avatarRadius; + border-radius: var(--avatarRadius, $fallback--avatarRadius); + } - .btn { - margin-top: 1em; - min-height: 28px; - width: 10em; - } - } - .setting-list { - list-style-type: none; - } + .btn { + margin-top: 1em; + min-height: 28px; + width: 10em; + } +} +.setting-list { + list-style-type: none; + li { + margin-bottom: 0.5em; + } +} </style> diff --git a/src/components/status/status.js b/src/components/status/status.js index 12f3bb25..73f4a7aa 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -4,9 +4,11 @@ import RetweetButton from '../retweet_button/retweet_button.vue' import DeleteButton from '../delete_button/delete_button.vue' import PostStatusForm from '../post_status_form/post_status_form.vue' import UserCardContent from '../user_card_content/user_card_content.vue' +import StillImage from '../still-image/still-image.vue' import { filter, find } from 'lodash' const Status = { + name: 'Status', props: [ 'statusoid', 'expandable', @@ -14,7 +16,10 @@ const Status = { 'focused', 'highlight', 'compact', - 'replies' + 'replies', + 'noReplyLinks', + 'noHeading', + 'inlineExpanded' ], data: () => ({ replying: false, @@ -22,7 +27,8 @@ const Status = { unmuted: false, userExpanded: false, preview: null, - showPreview: false + showPreview: false, + showingTall: false }), computed: { muteWords () { @@ -54,11 +60,6 @@ const Status = { }, muted () { return !this.unmuted && (this.status.user.muted || this.muteWordHits.length > 0) }, isReply () { return !!this.status.in_reply_to_status_id }, - borderColor () { - return { - borderBottomColor: this.$store.state.config.colors['base02'] - } - }, isFocused () { // retweet or root of an expanded conversation if (this.focused) { @@ -68,6 +69,29 @@ const Status = { } // use conversation highlight only when in conversation return this.status.id === this.highlight + }, + // This is a bit hacky, but we want to approximate post height before rendering + // so we count newlines (masto uses <p> for paragraphs, GS uses <br> between them) + // as well as approximate line count by counting characters and approximating ~80 + // per line. + // + // Using max-height + overflow: auto for status components resulted in false positives + // very often with japanese characters, and it was very annoying. + hideTallStatus () { + if (this.showingTall) { + return false + } + const lengthScore = this.status.statusnet_html.split(/<p|<br/).length + this.status.text.length / 80 + return lengthScore > 20 + }, + attachmentSize () { + if ((this.$store.state.config.hideAttachments && !this.inConversation) || + (this.$store.state.config.hideAttachmentsInConv && this.inConversation)) { + return 'hide' + } else if (this.compact) { + return 'small' + } + return 'normal' } }, components: { @@ -76,7 +100,8 @@ const Status = { RetweetButton, DeleteButton, PostStatusForm, - UserCardContent + UserCardContent, + StillImage }, methods: { linkClicked ({target}) { @@ -105,6 +130,9 @@ const Status = { toggleUserExpanded () { this.userExpanded = !this.userExpanded }, + toggleShowTall () { + this.showingTall = !this.showingTall + }, replyEnter (id, event) { this.showPreview = true const targetId = Number(id) diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 28272b0b..f1163fd9 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -1,123 +1,99 @@ <template> - <div class="status-el base00-background" v-if="compact"> - <div @click.prevent="linkClicked" class="status-content" v-html="status.statusnet_html"></div> - <div v-if="loggedIn"> - <div class='status-actions'> - <div> - <a href="#" v-on:click.prevent="toggleReplying"> - <i class="base09 icon-reply" :class="{'icon-reply-active': replying}"></i> - </a> - </div> - <retweet-button :loggedIn="loggedIn" :status=status></retweet-button> - <favorite-button :loggedIn="loggedIn" :status=status></favorite-button> - </div> - </div> - <post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" v-on:posted="toggleReplying" v-if="replying"/> - </div> - <div class="status-el base00-background base03-border status-fadein" v-else-if="!status.deleted" v-bind:class="[{ 'base01-background': isFocused }, { 'status-conversation': inConversation }]" > - <template v-if="muted"> + <div class="status-el" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"> + <template v-if="muted && !noReplyLinks"> <div class="media status container muted"> <small><router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small> <small class="muteWords">{{muteWordHits.join(', ')}}</small> - <a href="#" class="unmute" @click.prevent="toggleMute"><i class="base09 icon-eye-off"></i></a> + <a href="#" class="unmute" @click.prevent="toggleMute"><i class="icon-eye-off"></i></a> </div> </template> - <template v-if="!muted"> - <div v-if="retweet" class="media container retweet-info"> - <div class="media-left"> + <template v-else> + <div v-if="retweet && !noHeading" class="media container retweet-info"> + <StillImage v-if="retweet" class='avatar' :src="statusoid.user.profile_image_url_original"/> + <div class="media-body faint"> + <a :href="statusoid.user.statusnet_profile_url" style="font-weight: bold;" :title="'@'+statusoid.user.screen_name">{{retweeter}}</a> <i class='fa icon-retweet retweeted'></i> - </div> - <div class="media-body"> - Repeated by <a :href="statusoid.user.statusnet_profile_url" style="font-weight: bold;" :title="'@'+statusoid.user.screen_name">{{retweeter}}</a> + {{$t('timeline.repeated')}} </div> </div> - <div class="media status container"> - <div class="media-left"> - <a :href="status.user.statusnet_profile_url"> - <img @click.prevent="toggleUserExpanded" :class="{retweeted: retweet}" class='avatar' :src="status.user.profile_image_url_original"> - <img v-if="retweet" class='avatar-retweeter' :src="statusoid.user.profile_image_url_original"></img> + + <div class="media status"> + <div v-if="!noHeading" class="media-left"> + <a :href="status.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded"> + <StillImage class='avatar' :class="{'avatar-compact': compact}" :src="status.user.profile_image_url_original"/> </a> </div> - <div class="media-body"> - <div class="base03-border usercard" v-if="userExpanded"> + <div class="status-body"> + <div class="usercard media-body" v-if="userExpanded"> <user-card-content :user="status.user" :switcher="false"></user-card-content> </div> - <div class="user-content"> - <div class="media-heading"> + <div v-if="!noHeading" class="media-body container media-heading"> + <div class="media-heading-left"> <div class="name-and-links"> <h4 class="user-name">{{status.user.name}}</h4> - <div class="links"> - <h4> - <small><router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small> - <small v-if="status.in_reply_to_screen_name"> > + <span class="links"> + <router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link> + <span v-if="status.in_reply_to_screen_name" class="faint reply-info"> + <i class="icon-right-open"></i> <router-link :to="{ name: 'user-profile', params: { id: status.in_reply_to_user_id } }"> {{status.in_reply_to_screen_name}} </router-link> - </small> - <template v-if="isReply"> - <small> - <a href="#" @click.prevent="gotoOriginal(status.in_reply_to_status_id)"><i class="icon-reply" @mouseenter="replyEnter(status.in_reply_to_status_id, $event)" @mouseout="replyLeave()"></i></a> - </small> - </template> - - - <small> - <router-link :to="{ name: 'conversation', params: { id: status.id } }"> - <timeago :since="status.created_at" :auto-update="60"></timeago> - </router-link> - </small> - </h4> - </div> - <h4 class="replies" v-if="inConversation"> - <small v-if="replies.length">Replies:</small> - <small v-for="reply in replies"> - <a href="#" @click.prevent="gotoOriginal(reply.id)" @mouseenter="replyEnter(reply.id, $event)" @mouseout="replyLeave()">{{reply.name}} </a> - </small> - </h4> - </div> - <div class="heading-icons"> - <a href="#" @click.prevent="toggleMute" v-if="unmuted"><i class="base09 icon-eye-off"></i></a> - <a :href="status.external_url" target="_blank" v-if="!status.is_local" class="source_url"><i class="base09 icon-binoculars"></i></a> - <template v-if="expandable"> - <a href="#" @click.prevent="toggleExpanded" class="expand"><i class="base09 icon-plus-squared"></i></a> - </template> + </span> + <a v-if="isReply && !noReplyLinks" href="#" @click.prevent="gotoOriginal(status.in_reply_to_status_id)"> + <i class="icon-reply" @mouseenter="replyEnter(status.in_reply_to_status_id, $event)" @mouseout="replyLeave()"></i> + </a> + </span> </div> + <h4 class="replies" v-if="inConversation && !noReplyLinks"> + <small v-if="replies.length">Replies:</small> + <small class="reply-link" v-for="reply in replies"> + <a href="#" @click.prevent="gotoOriginal(reply.id)" @mouseenter="replyEnter(reply.id, $event)" @mouseout="replyLeave()">{{reply.name}} </a> + </small> + </h4> </div> - - <div class="status-preview base00-background base03-border" v-if="showPreview && preview"> - <img class="avatar" :src="preview.user.profile_image_url_original"> - <div class="text"> - <h4> - {{ preview.user.name }} - <small><a>{{ preview.user.screen_name}}</a></small> - </h4> - <div @click.prevent="linkClicked" class="status-content" v-html="preview.statusnet_html"></div> - </div> + <div class="media-heading-right"> + <router-link class="timeago" :to="{ name: 'conversation', params: { id: status.id } }"> + <timeago :since="status.created_at" :auto-update="60"></timeago> + </router-link> + <a :href="status.external_url" target="_blank" v-if="!status.is_local" class="source_url"><i class="icon-link-ext"></i></a> + <template v-if="expandable"> + <a href="#" @click.prevent="toggleExpanded"><i class="icon-plus-squared"></i></a> + </template> + <a href="#" @click.prevent="toggleMute" v-if="unmuted"><i class="icon-eye-off"></i></a> </div> - <div class="status-preview status-preview-loading base00-background base03-border" v-else-if="showPreview"> - <i class="base09 icon-spin4 animate-spin"></i> + </div> + + <div v-if="showPreview" class="status-preview-container"> + <status class="status-preview" v-if="preview" :noReplyLinks="true" :statusoid="preview" :compact=true></status> + <div class="status-preview status-preview-loading" v-else> + <i class="icon-spin4 animate-spin"></i> </div> + </div> - <div @click.prevent="linkClicked" class="status-content" v-html="status.statusnet_html"></div> + <div :class="{'tall-status': hideTallStatus}" class="status-content-wrapper"> + <a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="hideTallStatus" href="#" @click.prevent="toggleShowTall">Show more</a> + <div @click.prevent="linkClicked" class="status-content media-body" v-html="status.statusnet_html"></div> + <a v-if="showingTall" href="#" class="tall-status-unhider" @click.prevent="toggleShowTall">Show less</a> + </div> - <div v-if='status.attachments' class='attachments'> - <attachment v-if="!hideAttachments" :status-id="status.id" :nsfw="status.nsfw" :attachment="attachment" v-for="attachment in status.attachments" :key="attachment.id"> - </attachment> - </div> + <div v-if='status.attachments' class='attachments media-body'> + <attachment :size="attachmentSize" :status-id="status.id" :nsfw="status.nsfw" :attachment="attachment" v-for="attachment in status.attachments" :key="attachment.id"> + </attachment> </div> - <div class='status-actions'> + <div v-if="!noHeading && !noReplyLinks" class='status-actions media-body'> <div v-if="loggedIn"> <a href="#" v-on:click.prevent="toggleReplying"> - <i class="base09 icon-reply" :class="{'icon-reply-active': replying}"></i> + <i class="icon-reply" :class="{'icon-reply-active': replying}"></i> </a> </div> - <retweet-button :loggedIn="loggedIn" :status=status></retweet-button> - <favorite-button :loggedIn="loggedIn" :status=status></favorite-button> - <delete-button :status=status></delete-button> + <retweet-button :loggedIn='loggedIn' :status='status'></retweet-button> + <favorite-button :loggedIn='loggedIn' :status='status'></favorite-button> + <delete-button :status='status'></delete-button> </div> </div> </div> - <div class="status base00-background container" v-if="replying"> + <div class="container" v-if="replying"> <div class="reply-left"/> <post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" v-on:posted="toggleReplying"/> </div> @@ -126,300 +102,387 @@ </template> <script src="./status.js" ></script> - <style lang="scss"> - @import '../../_variables.scss'; +@import '../../_variables.scss'; + +.status-body { + flex: 1; + min-width: 0; +} + +.status-preview.status-el { + border-style: solid; + border-width: 1px; + border-color: $fallback--border; + border-color: var(--border, $fallback--border); +} + +.status-preview-container { + position: relative; + max-width: 100%; +} + +.status-preview { + position: absolute; + max-width: 95%; + display: flex; + background-color: $fallback--bg; + background-color: var(--bg, $fallback--bg); + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + border-style: solid; + border-width: 1px; + border-radius: $fallback--tooltipRadius; + border-radius: var(--tooltipRadius, $fallback--tooltipRadius); + box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5); + margin-top: 0.25em; + margin-left: 0.5em; + z-index: 50; + .status { + flex: 1; + border: 0; + min-width: 15em; + } +} + +.status-preview-loading { + display: block; + min-width: 15em; + padding: 1em; + text-align: center; + border-width: 1px; + border-style: solid; + i { + font-size: 2em; + } +} + +.status-el { + hyphens: auto; + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-word; + border-left-width: 0px; + line-height: 18px; + min-width: 0; + background-color: $fallback--bg; + background-color: var(--bg, $fallback--bg); + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + + border-left: 4px $fallback--cRed; + border-left: 4px var(--cRed, $fallback--cRed); + + &_focused { + background-color: $fallback--lightBg; + background-color: var(--lightBg, $fallback--lightBg); + } - status-text-container { - display: block; + .timeline & { + border-bottom-width: 1px; + border-bottom-style: solid; } - .status-preview { - position: absolute; - max-width: 34em; - padding: 0.5em; + .media-body { + flex: 1; + padding: 0; + margin: 0 0 0.25em 0.8em; + } + + .media-heading { + flex-wrap: nowrap; + } + + .media-heading-left { + padding: 0; + vertical-align: bottom; + flex-basis: 100%; + + small { + font-weight: lighter; + } + h4 { + white-space: nowrap; + font-size: 14px; + margin-right: 0.25em; + overflow: hidden; + text-overflow: ellipsis; + } + .name-and-links { + padding: 0; + flex: 1 0; + display: flex; + flex-wrap: wrap; + align-content: center; + } + .links { + display: flex; + padding-top: 1px; + margin-left: 0.2em; + font-size: 12px; + color: $fallback--link; + color: var(--link, $fallback--link); + max-width: 100%; + a { + max-width: 100%; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } + .reply-info { + display: flex; + } + .replies { + line-height: 16px; + } + .reply-link { + margin-right: 0.2em; + } + } + + .media-heading-right { + flex-shrink: 0; display: flex; - border-color: inherit; - border-style: solid; - border-width: 1px; - border-radius: 4px; - box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5); - margin-top: 0.5em; - margin-left: 1em; + flex-wrap: nowrap; + max-height: 1.5em; + margin-left: 0.25em; + .timeago { + margin-right: 0.2em; + font-size: 12px; + padding-top: 1px; + } + i { + margin-left: 0.2em; + } + } + a { + display: inline-block; + word-break: break-all; + } + + .tall-status { + position: relative; + height: 220px; + overflow-x: hidden; + overflow-y: hidden; + } + + .tall-status-hider { + position: absolute; + height: 70px; + margin-top: 150px; + width: 100%; + text-align: center; + line-height: 110px; + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%); + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%); + &_focused { + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--lightBg 80%); + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--lightBg, $fallback--lightBg) 80%); + } + } + + .tall-status-unhider { + width: 100%; + text-align: center; + } + + .status-content { + margin-right: 0.5em; + img, video { + max-width: 100%; + max-height: 400px; + vertical-align: middle; + object-fit: contain; + } + + blockquote { + margin: 0.2em 0 0.2em 2em; + font-style: italic; + } + + p { + margin: 0; + margin-top: 0.2em; + margin-bottom: 0.5em; + } + } + + .retweet-info { + padding: 0.4em 0.6em 0 0.6em; + margin: 0 0 -0.5em 0; .avatar { - flex-shrink: 0; - width: 32px; - height: 32px; - border-radius: 50%; + border-radius: $fallback--avatarAltRadius; + border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + margin-left: 28px; + width: 20px; + height: 20px; } - .text { - h4 { - margin-bottom: 0.4em; - small { - font-weight: lighter; - } + + .media-body { + font-size: 1em; + line-height: 22px; + + display: flex; + align-content: center; + flex-wrap: wrap; + i { + padding: 0 0.2em; + } + a { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } - padding: 0 0.5em 0.5em 0.5em; } } +} - .status-preview-loading { - display: block; - font-size: 2em; - min-width: 8em; - text-align: center; +.status-fadein { + animation-duration: 0.4s; + animation-name: fadein; +} + +@keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.greentext { + color: green; +} + +.status-conversation { + border-left-style: solid; +} + +.status-actions { + width: 100%; + display: flex; + + div, favorite-button { + padding-top: 0.25em; + max-width: 6em; + flex: 1; + } +} + +.icon-reply:hover { + color: $fallback--cBlue; + color: var(--cBlue, $fallback--cBlue); +} + +.icon-reply.icon-reply-active { + color: $fallback--cBlue; + color: var(--cBlue, $fallback--cBlue); +} + +.status .avatar-compact { + width: 32px; + height: 32px; + border-radius: $fallback--avatarAltRadius; + border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); +} + +.avatar { + width: 48px; + height: 48px; + border-radius: $fallback--avatarRadius; + border-radius: var(--avatarRadius, $fallback--avatarRadius); + overflow: hidden; + position: relative; + + img { + width: 100%; + height: 100%; + } + + &.animated::before { + display: none; + } + + &.retweeted { + } +} + +.status:hover .animated.avatar { + canvas { + display: none; + } + img { + visibility: visible; + } +} + +.status { + display: flex; + padding: 0.6em; +} + +.status-conversation:last-child { + border-bottom: none; +} + +.muted { + padding: 0.25em 0.5em; + button { + margin-left: auto; } - .status-el { - hyphens: auto; - overflow-wrap: break-word; - word-wrap: break-word; - word-break: break-word; - border-left-width: 0px; - line-height: 18px; - - .timeline & { - border-bottom-width: 1px; - border-bottom-style: solid; - } - - .notify { - .avatar { - border-width: 3px; - border-style: solid; - } - } - - .media-body { - flex: 1; - padding-left: 0.5em; - } - - - .user-content { - - min-height: 52px; - padding-top: 1px; - } - - .media-heading { - display: flex; - min-height: 1.4em; - margin-bottom: 0.3em; - - small { - font-weight: lighter; - } - h4 { - margin-right: 0.4em; - } - .name-and-links { - flex: 1 0; - display: flex; - flex-wrap: wrap; - } - .replies { - flex-basis: 100%; - } - } - - .source_url { - - } - - .expand { - margin-right: -0.3em; - } - - a { - display: inline-block; - word-break: break-all; - } - - .status-content { - margin: 3px 15px 4px 0; - max-height: 400px; - overflow-y: auto; - overflow-x: hidden; - - img, video { - max-width: 100%; - max-height: 400px; - vertical-align: middle; - object-fit: contain; - } - - blockquote { - margin: 0.2em 0 0.2em 2em; - font-style: italic; - } - } - - p { - margin: 0; - margin-top: 0.2em; - margin-bottom: 0.5em; - } - - .media-left { - margin: 0.2em 0.3em 0 0; - img { - float: right; - border-radius: 5px; - } - } - - .retweet-info { - padding: 0.7em 0 0 0.6em; - - .media-left { - display: flex; - - i { - align-self: center; - text-align: right; - flex: 1; - padding-right: 0.3em; - } - } - } - } - - .status-fadein { - animation-duration: 0.5s; - animation-name: fadein; - } - - @keyframes fadein { - from { - opacity: 0; - } - to { - opacity: 1; - } - } - - .greentext { - color: green; - } - - .status-conversation { - border-left-style: solid; - } - - .status-actions { - padding-top: 0.15em; - width: 100%; - display: flex; - - div, favorite-button { - max-width: 6em; - flex: 1; - } - } - - .icon-reply:hover { - color: $blue; - } - - .icon-reply.icon-reply-active { - color: $blue; - } - - .status .avatar { - width: 48px; - height: 48px; - - &.retweeted { - width: 40px; - height: 40px; - margin-right: 8px; - margin-bottom: 8px; - } - } - - .status img.avatar-retweeter { - width: 24px; - height: 24px; - position: absolute; - margin-left: 24px; - margin-top: 24px; - } - - .status.compact .avatar { - width: 32px; - } - - .status { - padding: 0.4em 0.7em 0.45em 0.7em; - border-left: 4px rgba(255, 48, 16, 0.65); - border-left-style: inherit; - } - - .status-conversation:last-child { - border-bottom: none; - } - - .timeline .panel.timeline { - border-radius: 10px; - overflow: hidden; - } - - .muted { - padding: 0.1em 0.4em 0.1em 0.8em; - button { - margin-left: auto; - } - - .muteWords { - margin-left: 10px; - } - } - - a.unmute { - display: block; - margin-left: auto; - } - - .reply-left { - flex: 0; - min-width: 48px; - } - - .reply-body { - flex: 1; - } - - @media all and (max-width: 960px) { - .status-el { - .name-and-links { - margin-left: -0.25em; - } - } - .status { - max-width: 100%; - } - - .status .avatar { - width: 40px; - height: 40px; - - &.retweeted { - width: 34px; - height: 34px; - margin-right: 8px; - margin-bottom: 8px; - } - } - - .status img.avatar-retweeter { - width: 22px; - height: 22px; - position: absolute; - margin-left: 18px; - margin-top: 18px; - } - } + .muteWords { + margin-left: 10px; + } +} + +a.unmute { + display: block; + margin-left: auto; +} + +.reply-left { + flex: 0; + min-width: 48px; +} + +.reply-body { + flex: 1; +} + +.timeline > { + .status-el:last-child { + border-bottom-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;; + border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); + } +} + +@media all and (max-width: 960px) { + .status-el { + .retweet-info { + .avatar { + margin-left: 20px; + } + } + } + .status { + max-width: 100%; + } + + .status .avatar { + width: 40px; + height: 40px; + } + + .status .avatar-compact { + width: 32px; + height: 32px; + } +} </style> diff --git a/src/components/still-image/still-image.js b/src/components/still-image/still-image.js new file mode 100644 index 00000000..0839aca5 --- /dev/null +++ b/src/components/still-image/still-image.js @@ -0,0 +1,26 @@ +const StillImage = { + props: [ + 'src', + 'referrerpolicy', + 'mimetype' + ], + data () { + return { + stopGifs: this.$store.state.config.stopGifs + } + }, + computed: { + animated () { + return this.stopGifs && (this.mimetype === 'image/gif' || this.src.endsWith('.gif')) + } + }, + methods: { + onLoad () { + const canvas = this.$refs.canvas + if (!canvas) return + canvas.getContext('2d').drawImage(this.$refs.src, 1, 1, canvas.width, canvas.height) + } + } +} + +export default StillImage diff --git a/src/components/still-image/still-image.vue b/src/components/still-image/still-image.vue new file mode 100644 index 00000000..a37c678d --- /dev/null +++ b/src/components/still-image/still-image.vue @@ -0,0 +1,65 @@ +<template> + <div class='still-image' :class='{ animated: animated }' > + <canvas ref="canvas" v-if="animated"></canvas> + <img ref="src" :src="src" :referrerpolicy="referrerpolicy" v-on:load="onLoad"/> + </div> +</template> + +<script src="./still-image.js"></script> + +<style lang="scss"> +@import '../../_variables.scss'; +.still-image { + position: relative; + line-height: 0; + overflow: hidden; + width: 100%; + height: 100%; + + &:hover canvas { + display: none; + } + + img { + width: 100%; + height: 100%; + } + + &.animated { + &:hover::before, + img { + visibility: hidden; + } + + &:hover img { + visibility: visible + } + + &::before { + content: 'gif'; + position: absolute; + line-height: 10px; + font-size: 10px; + top: 5px; + left: 5px; + background: rgba(127,127,127,.5); + color: #FFF; + display: block; + padding: 2px 4px; + border-radius: $fallback--tooltipRadius; + border-radius: var(--tooltipRadius, $fallback--tooltipRadius); + z-index: 2; + } + } + + canvas { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; + } +} +</style> diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index a762f914..08bc7113 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -6,9 +6,19 @@ export default { availableStyles: [], selected: this.$store.state.config.theme, bgColorLocal: '', - fgColorLocal: '', + btnColorLocal: '', textColorLocal: '', - linkColorLocal: '' + linkColorLocal: '', + redColorLocal: '', + blueColorLocal: '', + greenColorLocal: '', + orangeColorLocal: '', + btnRadiusLocal: '', + panelRadiusLocal: '', + avatarRadiusLocal: '', + avatarAltRadiusLocal: '', + attachmentRadiusLocal: '', + tooltipRadiusLocal: '' } }, created () { @@ -21,16 +31,29 @@ export default { }) }, mounted () { - this.bgColorLocal = rgbstr2hex(this.$store.state.config.colors['base00']) - this.fgColorLocal = rgbstr2hex(this.$store.state.config.colors['base02']) - this.textColorLocal = rgbstr2hex(this.$store.state.config.colors['base05']) - this.linkColorLocal = rgbstr2hex(this.$store.state.config.colors['base08']) + this.bgColorLocal = rgbstr2hex(this.$store.state.config.colors.bg) + this.btnColorLocal = rgbstr2hex(this.$store.state.config.colors.btn) + this.textColorLocal = rgbstr2hex(this.$store.state.config.colors.fg) + this.linkColorLocal = rgbstr2hex(this.$store.state.config.colors.link) + + this.redColorLocal = rgbstr2hex(this.$store.state.config.colors.cRed) + this.blueColorLocal = rgbstr2hex(this.$store.state.config.colors.cBlue) + this.greenColorLocal = rgbstr2hex(this.$store.state.config.colors.cGreen) + this.orangeColorLocal = rgbstr2hex(this.$store.state.config.colors.cOrange) + + this.btnRadiusLocal = this.$store.state.config.radii.btnRadius || 4 + this.panelRadiusLocal = this.$store.state.config.radii.panelRadius || 10 + this.avatarRadiusLocal = this.$store.state.config.radii.avatarRadius || 5 + this.avatarAltRadiusLocal = this.$store.state.config.radii.avatarAltRadius || 50 + this.tooltipRadiusLocal = this.$store.state.config.radii.tooltipRadius || 2 + this.attachmentRadiusLocal = this.$store.state.config.radii.attachmentRadius || 5 }, methods: { setCustomTheme () { - if (!this.bgColorLocal && !this.fgColorLocal && !this.linkColorLocal) { + if (!this.bgColorLocal && !this.btnColorLocal && !this.linkColorLocal) { // reset to picked themes } + const rgb = (hex) => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) return result ? { @@ -40,17 +63,33 @@ export default { } : null } const bgRgb = rgb(this.bgColorLocal) - const fgRgb = rgb(this.fgColorLocal) + const btnRgb = rgb(this.btnColorLocal) const textRgb = rgb(this.textColorLocal) const linkRgb = rgb(this.linkColorLocal) - if (bgRgb && fgRgb && linkRgb) { + + const redRgb = rgb(this.redColorLocal) + const blueRgb = rgb(this.blueColorLocal) + const greenRgb = rgb(this.greenColorLocal) + const orangeRgb = rgb(this.orangeColorLocal) + + if (bgRgb && btnRgb && linkRgb) { this.$store.dispatch('setOption', { name: 'customTheme', value: { - fg: fgRgb, + fg: btnRgb, bg: bgRgb, text: textRgb, - link: linkRgb + link: linkRgb, + cRed: redRgb, + cBlue: blueRgb, + cGreen: greenRgb, + cOrange: orangeRgb, + btnRadius: this.btnRadiusLocal, + panelRadius: this.panelRadiusLocal, + avatarRadius: this.avatarRadiusLocal, + avatarAltRadius: this.avatarAltRadiusLocal, + tooltipRadius: this.tooltipRadiusLocal, + attachmentRadius: this.attachmentRadiusLocal }}) } } @@ -58,9 +97,13 @@ export default { watch: { selected () { this.bgColorLocal = this.selected[1] - this.fgColorLocal = this.selected[2] + this.btnColorLocal = this.selected[2] this.textColorLocal = this.selected[3] this.linkColorLocal = this.selected[4] + this.redColorLocal = this.selected[5] + this.greenColorLocal = this.selected[6] + this.blueColorLocal = this.selected[7] + this.orangeColorLocal = this.selected[8] } } } diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 31bf546d..9c39b245 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -1,99 +1,231 @@ <template> <div> - <p>{{$t('settings.presets')}}</p> - <select v-model="selected" class="style-switcher"> - <option v-for="style in availableStyles" :value="style">{{style[0]}}</option> - </select> - <p>{{$t('settings.theme_help')}}</p> + <div>{{$t('settings.presets')}} + <label for="style-switcher" class='select'> + <select id="style-switcher" v-model="selected" class="style-switcher"> + <option v-for="style in availableStyles" :value="style">{{style[0]}}</option> + </select> + <i class="icon-down-open"/> + </label> + </div> <div class="color-container"> + <p>{{$t('settings.theme_help')}}</p> <div class="color-item"> - <label for="bgcolor" class="base04 theme-color-lb">{{$t('settings.background')}}</label> + <label for="bgcolor" class="theme-color-lb">{{$t('settings.background')}}</label> <input id="bgcolor" class="theme-color-cl" type="color" v-model="bgColorLocal"> <input id="bgcolor-t" class="theme-color-in" type="text" v-model="bgColorLocal"> </div> <div class="color-item"> - <label for="fgcolor" class="base04 theme-color-lb">{{$t('settings.foreground')}}</label> - <input id="fgcolor" class="theme-color-cl" type="color" v-model="fgColorLocal"> - <input id="fgcolor-t" class="theme-color-in" type="text" v-model="fgColorLocal"> + <label for="fgcolor" class="theme-color-lb">{{$t('settings.foreground')}}</label> + <input id="fgcolor" class="theme-color-cl" type="color" v-model="btnColorLocal"> + <input id="fgcolor-t" class="theme-color-in" type="text" v-model="btnColorLocal"> </div> <div class="color-item"> - <label for="textcolor" class="base04 theme-color-lb">{{$t('settings.text')}}</label> + <label for="textcolor" class="theme-color-lb">{{$t('settings.text')}}</label> <input id="textcolor" class="theme-color-cl" type="color" v-model="textColorLocal"> <input id="textcolor-t" class="theme-color-in" type="text" v-model="textColorLocal"> </div> <div class="color-item"> - <label for="linkcolor" class="base04 theme-color-lb">{{$t('settings.links')}}</label> + <label for="linkcolor" class="theme-color-lb">{{$t('settings.links')}}</label> <input id="linkcolor" class="theme-color-cl" type="color" v-model="linkColorLocal"> <input id="linkcolor-t" class="theme-color-in" type="text" v-model="linkColorLocal"> </div> + <div class="color-item"> + <label for="redcolor" class="theme-color-lb">{{$t('settings.cRed')}}</label> + <input id="redcolor" class="theme-color-cl" type="color" v-model="redColorLocal"> + <input id="redcolor-t" class="theme-color-in" type="text" v-model="redColorLocal"> + </div> + <div class="color-item"> + <label for="bluecolor" class="theme-color-lb">{{$t('settings.cBlue')}}</label> + <input id="bluecolor" class="theme-color-cl" type="color" v-model="blueColorLocal"> + <input id="bluecolor-t" class="theme-color-in" type="text" v-model="blueColorLocal"> + </div> + <div class="color-item"> + <label for="greencolor" class="theme-color-lb">{{$t('settings.cGreen')}}</label> + <input id="greencolor" class="theme-color-cl" type="color" v-model="greenColorLocal"> + <input id="greencolor-t" class="theme-color-in" type="green" v-model="greenColorLocal"> + </div> + <div class="color-item"> + <label for="orangecolor" class="theme-color-lb">{{$t('settings.cOrange')}}</label> + <input id="orangecolor" class="theme-color-cl" type="color" v-model="orangeColorLocal"> + <input id="orangecolor-t" class="theme-color-in" type="text" v-model="orangeColorLocal"> + </div> </div> - <div> - <div class="panel"> - <div class="panel-heading" :style="{ 'background-color': fgColorLocal, 'color': textColorLocal }">Preview</div> + <div class="radius-container"> + <p>{{$t('settings.radii_help')}}</p> + <div class="radius-item"> + <label for="btnradius" class="theme-radius-lb">{{$t('settings.btnRadius')}}</label> + <input id="btnradius" class="theme-radius-rn" type="range" v-model="btnRadiusLocal" max="16"> + <input id="btnradius-t" class="theme-radius-in" type="text" v-model="btnRadiusLocal"> + </div> + <div class="radius-item"> + <label for="panelradius" class="theme-radius-lb">{{$t('settings.panelRadius')}}</label> + <input id="panelradius" class="theme-radius-rn" type="range" v-model="panelRadiusLocal" max="50"> + <input id="panelradius-t" class="theme-radius-in" type="text" v-model="panelRadiusLocal"> + </div> + <div class="radius-item"> + <label for="avatarradius" class="theme-radius-lb">{{$t('settings.avatarRadius')}}</label> + <input id="avatarradius" class="theme-radius-rn" type="range" v-model="avatarRadiusLocal" max="28"> + <input id="avatarradius-t" class="theme-radius-in" type="green" v-model="avatarRadiusLocal"> + </div> + <div class="radius-item"> + <label for="avataraltradius" class="theme-radius-lb">{{$t('settings.avatarAltRadius')}}</label> + <input id="avataraltradius" class="theme-radius-rn" type="range" v-model="avatarAltRadiusLocal" max="28"> + <input id="avataraltradius-t" class="theme-radius-in" type="text" v-model="avatarAltRadiusLocal"> + </div> + <div class="radius-item"> + <label for="attachmentradius" class="theme-radius-lb">{{$t('settings.attachmentRadius')}}</label> + <input id="attachmentrradius" class="theme-radius-rn" type="range" v-model="attachmentRadiusLocal" max="50"> + <input id="attachmentradius-t" class="theme-radius-in" type="text" v-model="attachmentRadiusLocal"> + </div> + <div class="radius-item"> + <label for="tooltipradius" class="theme-radius-lb">{{$t('settings.tooltipRadius')}}</label> + <input id="tooltipradius" class="theme-radius-rn" type="range" v-model="tooltipRadiusLocal" max="20"> + <input id="tooltipradius-t" class="theme-radius-in" type="text" v-model="tooltipRadiusLocal"> + </div> + </div> + <div :style="{ + '--btnRadius': btnRadiusLocal + 'px', + '--panelRadius': panelRadiusLocal + 'px', + '--avatarRadius': avatarRadiusLocal + 'px', + '--avatarAltRadius': avatarAltRadiusLocal + 'px', + '--tooltipRadius': tooltipRadiusLocal + 'px', + '--attachmentRadius': attachmentRadiusLocal + 'px' + }"> + <div class="panel dummy"> + <div class="panel-heading" :style="{ 'background-color': btnColorLocal, 'color': textColorLocal }">Preview</div> <div class="panel-body theme-preview-content" :style="{ 'background-color': bgColorLocal, 'color': textColorLocal }"> + <div class="avatar" :style="{ + 'border-radius': avatarRadiusLocal + 'px' + }"> + ( ͡° ͜ʖ ͡°) + </div> <h4>Content</h4> <br> A bunch of more content and - <a :style="{ 'color': linkColorLocal }">a nice lil' link</a> + <a :style="{ color: linkColorLocal }">a nice lil' link</a> + <i :style="{ color: blueColorLocal }" class="icon-reply"/> + <i :style="{ color: greenColorLocal }" class="icon-retweet"/> + <i :style="{ color: redColorLocal }" class="icon-cancel"/> + <i :style="{ color: orangeColorLocal }" class="icon-star"/> <br> - <button class="btn" :style="{ 'background-color': fgColorLocal, 'color': textColorLocal }">Button</button> + <button class="btn" :style="{ 'background-color': btnColorLocal, 'color': textColorLocal }">Button</button> </div> </div> </div> - <button class="btn base02-background base04" @click="setCustomTheme">{{$t('general.apply')}}</button> + <button class="btn" @click="setCustomTheme">{{$t('general.apply')}}</button> </div> </template> <script src="./style_switcher.js"></script> <style lang="scss"> +@import '../../_variables.scss'; .style-switcher { - margin-right: 1em; + margin-right: 1em; } +.radius-container, .color-container { - display: flex; - flex-wrap: wrap; - justify-content: space-between; + display: flex; + + p { + margin-top: 2em; + margin-bottom: .5em; + } +} +.radius-container { + flex-direction: column; } +.color-container { + flex-wrap: wrap; + justify-content: space-between; +} + +.radius-item, .color-item { - min-width: 20em; - display:flex; - flex: 1 1 0; - align-items: baseline; - margin: 5px 6px 5px 0; + min-width: 20em; + display:flex; + flex: 1 1 0; + align-items: baseline; + margin: 5px 6px 5px 0; + + label { + color: var(--faint, $fallback--faint); + } } + +.radius-item { + flex-basis: auto; +} + +.theme-radius-rn, +.theme-color-cl { + border: 0; + box-shadow: none; + background: transparent; + color: var(--faint, $fallback--faint); + align-self: stretch; +} + .theme-color-cl, +.theme-radius-in, .theme-color-in { - margin-left: 4px; - border-radius: 2px; - border: 0; + margin-left: 4px; } .theme-color-in { - padding: 5px; - min-width: 4em; - max-width: 7em; - flex: 1; + min-width: 4em; } + +.theme-radius-in { + min-width: 1em; +} + +.theme-radius-in, +.theme-color-in { + max-width: 7em; + flex: 1; +} + +.theme-radius-lb, .theme-color-lb { - flex: 2; - min-width: 7em; - max-width: 10em; + flex: 2; + min-width: 7em; +} + +.theme-radius-lb{ + max-width: 50em; +} + +.theme-color-lb { + max-width: 10em; } .theme-color-cl { - padding: 1px; - max-width: 8em; - align-self: stretch; - height: 100%; - flex: 0; - min-width: 2em; - cursor: pointer; - } - - .theme-preview-content { - padding: 20px; - } + padding: 1px; + max-width: 8em; + height: 100%; + flex: 0; + min-width: 2em; + cursor: pointer; +} + +.theme-preview-content { + padding: 20px; +} + +.dummy { + .avatar { + background: linear-gradient(135deg, #b8e1fc 0%,#a9d2f3 10%,#90bae4 25%,#90bcea 37%,#90bff0 50%,#6ba8e5 51%,#a2daf5 83%,#bdf3fd 100%); + color: black; + text-align: center; + height: 48px; + line-height: 48px; + width: 48px; + float: left; + margin-right: 1em; + } +} </style> diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js index 660a8752..74ab85d3 100644 --- a/src/components/timeline/timeline.js +++ b/src/components/timeline/timeline.js @@ -105,7 +105,7 @@ const Timeline = { .then((friends) => this.$store.dispatch('addFriends', { friends })) }, scrollLoad (e) { - let height = Math.max(document.body.offsetHeight, document.body.scrollHeight) + const height = Math.max(document.body.offsetHeight, document.body.scrollHeight) if (this.timeline.loading === false && this.$store.state.config.autoLoad && this.$el.offsetHeight > 0 && diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue index d6ecfd2f..c4e0fbce 100644 --- a/src/components/timeline/timeline.vue +++ b/src/components/timeline/timeline.vue @@ -1,48 +1,50 @@ <template> <div class="timeline panel panel-default" v-if="viewing == 'statuses'"> - <div class="panel-heading timeline-heading base02-background base04"> + <div class="panel-heading timeline-heading"> <div class="title"> {{title}} </div> - <button @click.prevent="showNewStatuses" class="base05 base02-background loadmore-button" v-if="timeline.newStatusCount > 0 && !timelineError"> + <button @click.prevent="showNewStatuses" class="loadmore-button" v-if="timeline.newStatusCount > 0 && !timelineError"> {{$t('timeline.show_new')}}{{newStatusCountStr}} </button> - <div @click.prevent class="base06 error loadmore-text" v-if="timelineError"> + <div @click.prevent class="loadmore-error alert error" v-if="timelineError"> {{$t('timeline.error_fetching')}} </div> - <div @click.prevent class="base04 base02-background loadmore-text" v-if="!timeline.newStatusCount > 0 && !timelineError"> + <div @click.prevent class="loadmore-text" v-if="!timeline.newStatusCount > 0 && !timelineError"> {{$t('timeline.up_to_date')}} </div> </div> - <div class="panel-body base01-background"> + <div class="panel-body"> <div class="timeline"> - <status-or-conversation v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status"></status-or-conversation> - <a href="#" v-on:click.prevent='fetchOlderStatuses()' v-if="!timeline.loading"> - <div class="base02-background base03-border new-status-notification text-center">{{$t('timeline.load_older')}}</div> - </a> - <div class="base02-background base03-border new-status-notification text-center" v-else>...</div> + <status-or-conversation v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status" class="status-fadein"></status-or-conversation> </div> </div> + <div class="panel-footer"> + <a href="#" v-on:click.prevent='fetchOlderStatuses()' v-if="!timeline.loading"> + <div class="new-status-notification text-center panel-footer">{{$t('timeline.load_older')}}</div> + </a> + <div class="new-status-notification text-center panel-footer" v-else>...</div> + </div> </div> <div class="timeline panel panel-default" v-else-if="viewing == 'followers'"> - <div class="panel-heading timeline-heading base02-background base04"> + <div class="panel-heading timeline-heading"> <div class="title"> {{$t('user_card.followers')}} </div> </div> - <div class="panel-body base01-background"> + <div class="panel-body"> <div class="timeline"> <user-card v-for="follower in followers" :key="follower.id" :user="follower" :showFollows="false"></user-card> </div> </div> </div> <div class="timeline panel panel-default" v-else-if="viewing == 'friends'"> - <div class="panel-heading timeline-heading base02-background base04"> + <div class="panel-heading timeline-heading"> <div class="title"> {{$t('user_card.followees')}} </div> </div> - <div class="panel-body base01-background"> + <div class="panel-body"> <div class="timeline"> <user-card v-for="friend in friends" :key="friend.id" :user="friend" :showFollows="true"></user-card> </div> @@ -52,51 +54,69 @@ <script src="./timeline.js"></script> <style lang="scss"> +@import '../../_variables.scss'; + +.timeline { + .timeline-heading { + position: relative; + display: flex; + } + + .title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 70%; + } + + .loadmore-button { + position: absolute; + right: 0.6em; + font-size: 14px; - .timeline { - .timeline-heading { - position: relative; - display: flex; - } - .title { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 70%; - } - .loadmore-button { - position: absolute; - right: 0.6em; - font-size: 14px; + min-width: 6em; + height: 1.8em; + line-height: 100%; + } - min-width: 6em; - height: 1.8em; - line-height: 100%; - } - .loadmore-text { - position: absolute; - right: 0.6em; - font-size: 14px; - min-width: 6em; - border-radius: 5px; - font-family: sans-serif; - text-align: center; - padding: 0 0.5em 0 0.5em; - opacity: 0.8; - } - .error { - background-color: rgba(255, 48, 16, 0.65); - } + .loadmore-text { + position: absolute; + right: 0.6em; + font-size: 14px; + min-width: 6em; + font-family: sans-serif; + text-align: center; + padding: 0 0.5em 0 0.5em; + opacity: 0.8; + background-color: transparent; + color: $fallback--faint; + color: var(--faint, $fallback--faint); } - .new-status-notification { - position:relative; - margin-top: -1px; - font-size: 1.1em; - border-width: 1px 0 0 0; - border-style: solid; - border-radius: 0 0 10px 10px; - padding: 10px; - z-index: 1; + .loadmore-error { + position: absolute; + right: 0.6em; + font-size: 14px; + min-width: 6em; + font-family: sans-serif; + text-align: center; + padding: 0 0.25em 0 0.25em; + margin: 0; + color: $fallback--fg; + color: var(--fg, $fallback--fg); } +} + +.new-status-notification { + position:relative; + margin-top: -1px; + font-size: 1.1em; + border-width: 1px 0 0 0; + border-style: solid; + border-color: var(--border, $fallback--border); + padding: 10px; + z-index: 1; + background-color: $fallback--btn; + background-color: var(--btn, $fallback--btn); +} </style> diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index dd14d1b4..51d6965f 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -1,5 +1,5 @@ <template> - <div class="card base00-background"> + <div class="card"> <a href="#"> <img @click.prevent="toggleUserExpanded" class="avatar" :src="user.profile_image_url"> </a> @@ -7,7 +7,7 @@ <user-card-content :user="user" :switcher="false"></user-card-content> </div> <div class="name-and-screen-name" v-else> - <div class="user-name"> + <div :title="user.name" class="user-name"> {{ user.name }} <span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you"> {{ $t('user_card.follows_you') }} @@ -21,54 +21,58 @@ <script src="./user_card.js"></script> <style lang="scss"> - .name-and-screen-name { - margin-left: 0.7em; - margin-top:0.0em; - margin-right: 2em; - text-align: left; - width: 100%; - } +@import '../../_variables.scss'; - .follows-you { - margin-left: 2em; - float: right; - } +.name-and-screen-name { + margin-left: 0.7em; + margin-top:0.0em; + text-align: left; + width: 100%; +} - .follows { +.follows-you { + margin-left: 2em; + float: right; +} - } +.card { + display: flex; + flex: 1 0; + padding-top: 0.6em; + padding-right: 1em; + padding-bottom: 0.6em; + padding-left: 1em; + border-bottom: 1px solid; + margin: 0; + border-bottom-color: $fallback--border; + border-bottom-color: var(--border, $fallback--border); - .card { - display: flex; - flex: 1 0; - padding-top: 0.6em; - padding-right: 1em; - padding-bottom: 0.6em; - padding-left: 1em; - border-bottom: 1px solid; - margin: 0; - border-bottom-color: inherit; + .avatar { + margin-top: 0.2em; + width:32px; + height: 32px; + border-radius: $fallback--avatarAltRadius; + border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + } +} +.usercard { + width: fill-available; + margin: 0.2em 0 0.7em 0; + border-radius: $fallback--panelRadius; + border-radius: var(--panelRadius, $fallback--panelRadius); + border-style: solid; + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + border-width: 1px; + overflow: hidden; - .avatar { - margin-top: 0.2em; - width:32px; - height: 32px; - border-radius: 50%; - } + .panel-heading { + background: transparent; } - .usercard { - width: fill-available; - margin: 0.2em 0 0.7em 0; - border-radius: 10px; - border-style: solid; - border-color: inherit; - border-width: 1px; - overflow: hidden; - - p { - margin-bottom: 0; - } + p { + margin-bottom: 0; } +} </style> diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index 32d62ebb..1e8c91de 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -1,10 +1,11 @@ +import StillImage from '../still-image/still-image.vue' import { hex2rgb } from '../../services/color_convert/color_convert.js' export default { - props: [ 'user', 'switcher' ], + props: [ 'user', 'switcher', 'hideBio' ], computed: { headingStyle () { - const color = this.$store.state.config.colors['base00'] + const color = this.$store.state.config.colors.bg if (color) { const rgb = hex2rgb(color) console.log(rgb) @@ -14,11 +15,6 @@ export default { } } }, - bodyStyle () { - return { - background: `linear-gradient(to bottom, rgba(0, 0, 0, 0), ${this.$store.state.config.colors['base00']} 80%)` - } - }, isOtherUser () { return this.user.id !== this.$store.state.users.currentUser.id }, @@ -35,6 +31,9 @@ export default { return Math.round(this.user.statuses_count / days) } }, + components: { + StillImage + }, methods: { followUser () { const store = this.$store diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index ef000c94..ca8428ca 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -5,43 +5,45 @@ <router-link to='/user-settings' style="float: right; margin-top:16px;" v-if="!isOtherUser"> <i class="icon-cog usersettings"></i> </router-link> + <a :href="user.statusnet_profile_url" target="_blank" style="float: right; margin-top:16px;" v-if="isOtherUser"> + <i class="icon-link-ext usersettings"></i> + </a> <div class='container'> <router-link :to="{ name: 'user-profile', params: { id: user.id } }"> - <img :src="user.profile_image_url_original"> + <StillImage class="avatar" :src="user.profile_image_url_original"/> </router-link> - <span class="glyphicon glyphicon-user"></span> <div class="name-and-screen-name"> - <div class='user-name'>{{user.name}}</div> + <div :title="user.name" class='user-name'>{{user.name}}</div> <router-link :to="{ name: 'user-profile', params: { id: user.id } }"> <div class='user-screen-name'>@{{user.screen_name}}</div> </router-link> </div> </div> <div v-if="isOtherUser" class="user-interactions"> - <div v-if="user.follows_you && loggedIn" class="following base06"> + <div v-if="user.follows_you && loggedIn" class="following"> {{ $t('user_card.follows_you') }} </div> <div class="follow" v-if="loggedIn"> <span v-if="user.following"> <!--Following them!--> - <button @click="unfollowUser" class="base04 base00-background pressed"> + <button @click="unfollowUser" class="pressed"> {{ $t('user_card.following') }} </button> </span> <span v-if="!user.following"> - <button @click="followUser" class="base05 base02-background"> + <button @click="followUser"> {{ $t('user_card.follow') }} </button> </span> </div> <div class='mute' v-if='isOtherUser'> <span v-if='user.muted'> - <button @click="toggleMute" class="base04 base00-background pressed"> + <button @click="toggleMute" class="pressed"> {{ $t('user_card.muted') }} </button> </span> <span v-if='!user.muted'> - <button @click="toggleMute" class="base05 base02-background"> + <button @click="toggleMute"> {{ $t('user_card.mute') }} </button> </span> @@ -50,19 +52,19 @@ <form method="POST" :action='subscribeUrl'> <input type="hidden" name="nickname" :value="user.screen_name"> <input type="hidden" name="profile" value=""> - <button click="submit" class="remote-button base05 base02-background"> + <button click="submit" class="remote-button"> {{ $t('user_card.remote_follow') }} </button> </form> </div> <div class='block' v-if='isOtherUser && loggedIn'> <span v-if='user.statusnet_blocking'> - <button @click="unblockUser" class="base04 base00-background pressed"> + <button @click="unblockUser" class="pressed"> {{ $t('user_card.blocked') }} </button> </span> <span v-if='!user.statusnet_blocking'> - <button @click="blockUser" class="base05 base02-background"> + <button @click="blockUser"> {{ $t('user_card.block') }} </button> </span> @@ -70,25 +72,25 @@ </div> </div> </div> - <div class="panel-body profile-panel-body" :style="bodyStyle"> + <div class="panel-body profile-panel-body"> <div class="user-counts"> <div class="user-count"> - <a href="#" v-on:click.prevent="setProfileView('statuses')" v-if="switcher"><h5 class="base05">{{ $t('user_card.statuses') }}</h5></a> + <a href="#" v-on:click.prevent="setProfileView('statuses')" v-if="switcher"><h5>{{ $t('user_card.statuses') }}</h5></a> <h5 v-else>{{ $t('user_card.statuses') }}</h5> - <span class="base05">{{user.statuses_count}} <br><span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span></span> + <span>{{user.statuses_count}} <br><span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span></span> </div> <div class="user-count"> - <a href="#" v-on:click.prevent="setProfileView('friends')" v-if="switcher"><h5 class="base05">{{ $t('user_card.followees') }}</h5></a> + <a href="#" v-on:click.prevent="setProfileView('friends')" v-if="switcher"><h5>{{ $t('user_card.followees') }}</h5></a> <h5 v-else>{{ $t('user_card.followees') }}</h5> - <span class="base05">{{user.friends_count}}</span> + <span>{{user.friends_count}}</span> </div> <div class="user-count"> - <a href="#" v-on:click.prevent="setProfileView('followers')" v-if="switcher"><h5 class="base05">{{ $t('user_card.followers') }}</h5></a> + <a href="#" v-on:click.prevent="setProfileView('followers')" v-if="switcher"><h5>{{ $t('user_card.followers') }}</h5></a> <h5 v-else>{{ $t('user_card.followers') }}</h5> - <span class="base05">{{user.followers_count}}</span> + <span>{{user.followers_count}}</span> </div> </div> - <p>{{user.description}}</p> + <p v-if="!hideBio">{{user.description}}</p> </div> </div> </template> @@ -100,7 +102,8 @@ .profile-panel-background { background-size: cover; - border-radius: 10px; + border-radius: $fallback--panelRadius; + border-radius: var(--panelRadius, $fallback--panelRadius); .panel-heading { padding: 0.6em 0em; @@ -112,39 +115,51 @@ top: -0em; padding-top: 4em; word-wrap: break-word; + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%); + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%) } .user-info { - color: white; + color: white; padding: 0 16px 16px 16px; margin-bottom: -4em; - .usersettings { - color: white; - opacity: 0.8; - } - - .container{ + .container { padding: 16px 10px 4px 10px; display: flex; - flex-wrap: wrap; - flex-direction: column; - align-content: flex-start; - justify-content: center; max-height: 56px; overflow: hidden; + + .avatar { + border-radius: $fallback--avatarRadius; + border-radius: var(--avatarRadius, $fallback--avatarRadius); + flex: 1 0 100%; + width: 56px; + height: 56px; + box-shadow: 0px 1px 8px rgba(0,0,0,0.75); + object-fit: cover; + + &.animated::before { + display: none; + } + } } - img { - border-radius: 5px; - flex: 1 0 100%; - width: 56px; - height: 56px; - box-shadow: 0px 1px 8px rgba(0,0,0,0.75); - object-fit: cover; + &:hover .animated.avatar { + canvas { + display: none; + } + img { + visibility: visible; + } } - text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0); + text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0); + + .usersettings { + color: #fff; + opacity: .8; + } .name-and-screen-name { display: block; @@ -152,18 +167,20 @@ text-align: left; text-overflow: ellipsis; white-space: nowrap; + flex: 1 1 0; } - .user-name{ - color: white; - } + .user-name{ + color: white; + text-overflow: ellipsis; + overflow: hidden; + } .user-screen-name { - color: white; - font-weight: lighter; - font-size: 15px; - padding-right: 0.1em; - flex: 0 0 auto; + color: white; + font-weight: lighter; + font-size: 15px; + padding-right: 0.1em; } .user-interactions { @@ -219,23 +236,23 @@ } .user-counts { - display: flex; - line-height:16px; - padding: 1em 1.5em 0em 1em; - text-align: center; + display: flex; + line-height:16px; + padding: 1em 1.5em 0em 1em; + text-align: center; } .user-count { - flex: 1; + flex: 1; - h5 { - font-size:1em; - font-weight: bolder; - margin: 0 0 0.25em; - } - a { - text-decoration: none; - } + h5 { + font-size:1em; + font-weight: bolder; + margin: 0 0 0.25em; + } + a { + text-decoration: none; + } } .dailyAvg { diff --git a/src/components/user_finder/user_finder.vue b/src/components/user_finder/user_finder.vue index 3c69e3b4..69bd1d21 100644 --- a/src/components/user_finder/user_finder.vue +++ b/src/components/user_finder/user_finder.vue @@ -1,13 +1,13 @@ <template> <span class="user-finder-container"> - <span class="finder-error base05" v-if="error"> + <span class="alert error" v-if="error"> <i class="icon-cancel user-finder-icon" @click="dismissError"/> {{$t('finder.error_fetching_user')}} </span> <i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" /> <a href="#" v-if="hidden"><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden"/></a> <span v-else> - <input class="user-finder-input base03-border" @keyup.enter="findUser(username)" v-model="username" :placeholder="$t('finder.find_user')" id="user-finder-input" type="text"/> + <input class="user-finder-input" @keyup.enter="findUser(username)" v-model="username" :placeholder="$t('finder.find_user')" id="user-finder-input" type="text"/> <i class="icon-cancel user-finder-icon" @click.prevent.stop="toggleHidden"/> </span> </span> @@ -16,27 +16,16 @@ <script src="./user_finder.js"></script> <style lang="scss"> - .user-finder-container { - height: 21px; - max-width: 100%; - } +@import '../../_variables.scss'; - .user-finder-icon { - } +.user-finder-container { + height: 29px; + max-width: 100%; +} - .user-finder-input { - border-width: 1px; - border-style: solid; - border-color: inherit; - border-radius: 5px; - max-width: 80%; - padding: 0.1em 0.2em 0.2em 0.2em; - } +.user-finder-input { + max-width: 80%; + vertical-align: middle; +} - .finder-error { - background-color: rgba(255, 48, 16, 0.65); - margin: 0.35em; - border-radius: 5px; - padding: 0.25em; - } </style> diff --git a/src/components/user_panel/user_panel.vue b/src/components/user_panel/user_panel.vue index 1a5e20fb..3d4f873d 100644 --- a/src/components/user_panel/user_panel.vue +++ b/src/components/user_panel/user_panel.vue @@ -1,8 +1,8 @@ <template> <div class="user-panel"> <div v-if='user' class="panel panel-default" style="overflow: visible;"> - <user-card-content :user="user" :switcher="false"></user-card-content> - <div class="panel-footer base00-background"> + <user-card-content :user="user" :switcher="false" :hideBio="true"></user-card-content> + <div class="panel-footer"> <post-status-form v-if='user'></post-status-form> </div> </div> @@ -11,3 +11,11 @@ </template> <script src="./user_panel.js"></script> + +<style lang="scss"> +.user-panel { + .profile-panel-background .panel-heading { + background: transparent; + } +} +</style> diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue index 359abfef..838a43ab 100644 --- a/src/components/user_profile/user_profile.vue +++ b/src/components/user_profile/user_profile.vue @@ -1,6 +1,6 @@ <template> <div> - <div v-if="user" class="user-profile panel panel-default base00-background"> + <div v-if="user" class="user-profile panel panel-default"> <user-card-content :user="user" :switcher="true"></user-card-content> </div> <Timeline :title="$t('user_profile.timeline_title')" :timeline="timeline" :timeline-name="'user'" :user-id="userId"/> @@ -15,7 +15,8 @@ flex: 2; flex-basis: 500px; padding-bottom: 10px; - border-radius: 10px; + .panel-heading { + background: transparent; + } } - </style> diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 1ef52bbf..ed1864cc 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -1,16 +1,16 @@ <template> - <div class="settings panel panel-default base00-background"> - <div class="panel-heading base02-background base04"> + <div class="settings panel panel-default"> + <div class="panel-heading"> {{$t('settings.user_settings')}} </div> <div class="panel-body profile-edit"> <div class="setting-item"> <h3>{{$t('settings.name_bio')}}</h3> <p>{{$t('settings.name')}}</p> - <input class='name-changer base03-border' id='username' v-model="newname"></input> + <input class='name-changer' id='username' v-model="newname"></input> <p>{{$t('settings.bio')}}</p> - <textarea class="bio base03-border" v-model="newbio"></textarea> - <button :disabled='newname.length <= 0' class="btn btn-default base05 base02-background" @click="updateProfile">{{$t('general.submit')}}</button> + <textarea class="bio" v-model="newbio"></textarea> + <button :disabled='newname.length <= 0' class="btn btn-default" @click="updateProfile">{{$t('general.submit')}}</button> </div> <div class="setting-item"> <h3>{{$t('settings.avatar')}}</h3> @@ -22,8 +22,8 @@ <div> <input type="file" @change="uploadFile(0, $event)" ></input> </div> - <i class="base09 icon-spin4 animate-spin" v-if="uploading[0]"></i> - <button class="btn btn-default base05 base02-background" v-else-if="previews[0]" @click="submitAvatar">{{$t('general.submit')}}</button> + <i class="icon-spin4 animate-spin" v-if="uploading[0]"></i> + <button class="btn btn-default" v-else-if="previews[0]" @click="submitAvatar">{{$t('general.submit')}}</button> </div> <div class="setting-item"> <h3>{{$t('settings.profile_banner')}}</h3> @@ -35,8 +35,8 @@ <div> <input type="file" @change="uploadFile(1, $event)" ></input> </div> - <i class="base09 icon-spin4 animate-spin uploading" v-if="uploading[1]"></i> - <button class="btn btn-default base05 base02-background" v-else-if="previews[1]" @click="submitBanner">{{$t('general.submit')}}</button> + <i class=" icon-spin4 animate-spin uploading" v-if="uploading[1]"></i> + <button class="btn btn-default" v-else-if="previews[1]" @click="submitBanner">{{$t('general.submit')}}</button> </div> <div class="setting-item"> <h3>{{$t('settings.profile_background')}}</h3> @@ -46,8 +46,8 @@ <div> <input type="file" @change="uploadFile(2, $event)" ></input> </div> - <i class="base09 icon-spin4 animate-spin uploading" v-if="uploading[2]"></i> - <button class="btn btn-default base05 base02-background" v-else-if="previews[2]" @click="submitBg">{{$t('general.submit')}}</button> + <i class=" icon-spin4 animate-spin uploading" v-if="uploading[2]"></i> + <button class="btn btn-default" v-else-if="previews[2]" @click="submitBg">{{$t('general.submit')}}</button> </div> <div class="setting-item" v-if="pleromaBackend"> <h3>{{$t('settings.follow_import')}}</h3> @@ -55,8 +55,8 @@ <form v-model="followImportForm"> <input type="file" ref="followlist" v-on:change="followListChange"></input> </form> - <i class="base09 icon-spin4 animate-spin uploading" v-if="uploading[3]"></i> - <button class="btn btn-default base05 base02-background" v-else @click="importFollows">{{$t('general.submit')}}</button> + <i class=" icon-spin4 animate-spin uploading" v-if="uploading[3]"></i> + <button class="btn btn-default" v-else @click="importFollows">{{$t('general.submit')}}</button> <div v-if="followsImported"> <i class="icon-cross" @click="dismissImported"></i> <p>{{$t('settings.follows_imported')}}</p> @@ -75,24 +75,16 @@ <style lang="scss"> .profile-edit { - .name-changer { - border-width: 1px; - border-style: solid; - border-radius: 5px; - padding: 0.2em 0.2em 0.2em 0.2em; - } - .name-submit { - padding: 0.2em 0.5em 0.2em 0.5em; - } .bio { - border-width: 1px; - border-style: solid; - border-radius: 5px; margin: 0; } + + input[type=file] { + padding: 5px; + } + .banner { max-width: 400px; - border-radius: 5px; } .uploading { diff --git a/src/i18n/messages.js b/src/i18n/messages.js index a2ce3dff..7e17c931 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -20,14 +20,17 @@ const de = { muted: 'Stummgeschaltet', followers: 'Folgende', followees: 'Folgt', - per_day: 'pro Tag' + per_day: 'pro Tag', + remote_follow: 'Remote Follow' }, timeline: { show_new: 'Zeige Neuere', error_fetching: 'Fehler beim Laden', up_to_date: 'Aktuell', load_older: 'Lade ältere Beiträge', - conversation: 'Unterhaltung' + conversation: 'Unterhaltung', + collapse: 'Einklappen', + repeated: 'wiederholte' }, settings: { user_settings: 'Benutzereinstellungen', @@ -45,17 +48,28 @@ const de = { settings: 'Einstellungen', theme: 'Farbschema', presets: 'Voreinstellungen', - theme_help: 'Benutze HTML Farbcodes (#aabbcc) um dein Farbschema anzupassen.', + theme_help: 'Benutze HTML Farbcodes (#rrggbb) um dein Farbschema anzupassen.', background: 'Hintergrund', foreground: 'Vordergrund', text: 'Text', links: 'Links', + cBlue: 'Blau (Antworten, Folgt dir)', + cRed: 'Rot (Abbrechen)', + cOrange: 'Orange (Favorisieren)', + cGreen: 'Grün (Retweet)', + btnRadius: 'Buttons', + panelRadius: 'Panel', + avatarRadius: 'Avatare', + avatarAltRadius: 'Avatare (Benachrichtigungen)', + tooltipRadius: 'Tooltips/Warnungen', + attachmentRadius: 'Anhänge', filtering: 'Filter', filtering_explanation: 'Alle Beiträge die diese Wörter enthalten werden ausgeblendet. Ein Wort pro Zeile.', attachments: 'Anhänge', - hide_attachments_in_tl: 'Anhänge in der Timeline ausblenden', + hide_attachments_in_tl: 'Anhänge in der Zeitleiste ausblenden', hide_attachments_in_convo: 'Anhänge in Unterhaltungen ausblenden', - nsfw_clickthrough: 'Aktiviere ausblendbares Overlay für als NSFW markierte Anhänge', + nsfw_clickthrough: 'Aktiviere ausblendbares Overlay für Anhänge, die als NSFW markiert sind', + stop_gifs: 'Play-on-hover GIFs', autoload: 'Aktiviere automatisches Laden von älteren Beiträgen beim scrollen', streaming: 'Aktiviere automatisches Laden (Streaming) von neuen Beiträgen', reply_link_preview: 'Aktiviere reply-link Vorschau bei Maus-Hover', @@ -67,7 +81,9 @@ const de = { notifications: { notifications: 'Benachrichtigungen', read: 'Gelesen!', - followed_you: 'folgt dir' + followed_you: 'folgt dir', + favorited_you: 'favorisierte deine Nachricht', + repeated_you: 'wiederholte deine Nachricht' }, login: { login: 'Anmelden', @@ -94,6 +110,9 @@ const de = { general: { submit: 'Absenden', apply: 'Anwenden' + }, + user_profile: { + timeline_title: 'Beiträge' } } @@ -120,7 +139,9 @@ const fi = { error_fetching: 'Virhe ladatessa viestejä', up_to_date: 'Ajantasalla', load_older: 'Lataa vanhempia viestejä', - conversation: 'Keskustelu' + conversation: 'Keskustelu', + collapse: 'Sulje', + repeated: 'toisti' }, settings: { user_settings: 'Käyttäjän asetukset', @@ -156,7 +177,9 @@ const fi = { notifications: { notifications: 'Ilmoitukset', read: 'Lue!', - followed_you: 'seuraa sinua' + followed_you: 'seuraa sinua', + favorited_you: 'tykkäsi viestistäsi', + repeated_you: 'toisti viestisi' }, login: { login: 'Kirjaudu sisään', @@ -216,7 +239,9 @@ const en = { error_fetching: 'Error fetching updates', up_to_date: 'Up-to-date', load_older: 'Load older statuses', - conversation: 'Conversation' + conversation: 'Conversation', + collapse: 'Collapse', + repeated: 'repeated' }, settings: { user_settings: 'User Settings', @@ -234,29 +259,43 @@ const en = { settings: 'Settings', theme: 'Theme', presets: 'Presets', - theme_help: 'Use hex color codes (#aabbcc) to customize your color theme.', + theme_help: 'Use hex color codes (#rrggbb) to customize your color theme.', + radii_help: 'Set up interface edge rounding (in pixels)', background: 'Background', foreground: 'Foreground', text: 'Text', links: 'Links', + cBlue: 'Blue (Reply, follow)', + cRed: 'Red (Cancel)', + cOrange: 'Orange (Favorite)', + cGreen: 'Green (Retweet)', + btnRadius: 'Buttons', + panelRadius: 'Panels', + avatarRadius: 'Avatars', + avatarAltRadius: 'Avatars (Notifications)', + tooltipRadius: 'Tooltips/alerts', + attachmentRadius: 'Attachments', filtering: 'Filtering', filtering_explanation: 'All statuses containing these words will be muted, one per line', attachments: 'Attachments', hide_attachments_in_tl: 'Hide attachments in timeline', hide_attachments_in_convo: 'Hide attachments in conversations', nsfw_clickthrough: 'Enable clickthrough NSFW attachment hiding', + stop_gifs: 'Play-on-hover GIFs', autoload: 'Enable automatic loading when scrolled to the bottom', streaming: 'Enable automatic streaming of new posts when scrolled to the top', reply_link_preview: 'Enable reply-link preview on mouse hover', follow_import: 'Follow import', - import_followers_from_a_csv_file: 'Import followers from a csv file', + import_followers_from_a_csv_file: 'Import follows from a csv file', follows_imported: 'Follows imported! Processing them will take a while.', follow_import_error: 'Error importing followers' }, notifications: { notifications: 'Notifications', read: 'Read!', - followed_you: 'followed you' + followed_you: 'followed you', + favorited_you: 'favorited your status', + repeated_you: 'repeated your status' }, login: { login: 'Log in', @@ -539,9 +578,13 @@ const ro = { } const ja = { + chat: { + title: 'チャット' + }, nav: { + chat: 'ローカルチャット', timeline: 'タイムライン', - mentions: '通知', + mentions: 'メンション', public_tl: '公開タイムライン', twkn: '接続しているすべてのネットワーク' }, @@ -549,22 +592,28 @@ const ja = { follows_you: 'フォローされました!', following: 'フォロー中!', follow: 'フォロー', - statuses: 'ステータス', + blocked: 'ブロック済み!', + block: 'ブロック', + statuses: '投稿', mute: 'ミュート', muted: 'ミュート済み', followers: 'フォロワー', followees: 'フォロー', - per_day: '/日' + per_day: '/日', + remote_follow: 'リモートフォロー' }, timeline: { - show_new: '新しいものを表示', - error_fetching: '更新の取得中にエラーが発生しました', + show_new: '更新', + error_fetching: '更新の取得中にエラーが発生しました。', up_to_date: '最新', - load_older: '古いステータスを読み込む' + load_older: '古い投稿を読み込む', + conversation: '会話', + collapse: '折り畳む', + repeated: 'リピート' }, settings: { user_settings: 'ユーザー設定', - name_bio: '名前 & プロフィール', + name_bio: '名前とプロフィール', name: '名前', bio: 'プロフィール', avatar: 'アバター', @@ -577,23 +626,48 @@ const ja = { set_new_profile_background: '新しいプロフィールの背景を設定する', settings: '設定', theme: 'テーマ', + presets: 'プリセット', + theme_help: '16進数カラーコード (#aabbcc) を使用してカラーテーマをカスタマイズ出来ます。', + radii_help: 'インターフェースの縁の丸さを設定する。', + background: '背景', + foreground: '前景', + text: '文字', + links: 'リンク', + cBlue: '青 (返信, フォロー)', + cRed: '赤 (キャンセル)', + cOrange: 'オレンジ (お気に入り)', + cGreen: '緑 (リツイート)', + btnRadius: 'ボタン', + panelRadius: 'パネル', + avatarRadius: 'アバター', + avatarAltRadius: 'アバター (通知)', + tooltipRadius: 'ツールチップ/アラート', + attachmentRadius: 'ファイル', filtering: 'フィルタリング', - filtering_explanation: 'これらの単語を含むすべてのものはミュートされます、1行に1つのワードを入力してください', - attachments: '添付ファイル', - hide_attachments_in_tl: 'タイムラインの添付ファイルを隠す', - hide_attachments_in_convo: '会話の中の添付ファイルを隠す', - nsfw_clickthrough: 'NSFWファイルの非表示を有効にする', - autoload: '下にスクロールした時に自動で読み込むようにする', - reply_link_preview: 'マウスカーソルを重ねたときに返信リンクプレビューを表示するようにする' + filtering_explanation: 'これらの単語を含むすべてのものがミュートされます。1行に1つの単語を入力してください。', + attachments: 'ファイル', + hide_attachments_in_tl: 'タイムラインのファイルを隠す。', + hide_attachments_in_convo: '会話の中のファイルを隠す。', + nsfw_clickthrough: 'NSFWファイルの非表示を有効にする。', + stop_gifs: 'カーソルを重ねた時にGIFを再生する。', + autoload: '下にスクロールした時に自動で読み込むようにする。', + streaming: '上までスクロールした時に自動でストリーミングされるようにする。', + reply_link_preview: 'マウスカーソルを重ねた時に返信のプレビューを表示するようにする。', + follow_import: 'フォローインポート', + import_followers_from_a_csv_file: 'CSVファイルからフォローをインポートする。', + follows_imported: 'フォローがインポートされました!処理に少し時間がかかるかもしれません。', + follow_import_error: 'フォロワーのインポート中にエラーが発生しました。' }, notifications: { notifications: '通知', read: '読んだ!', - followed_you: 'フォローされました' + followed_you: 'フォローされました', + favorited_you: 'あなたの投稿がお気に入りされました', + repeated_you: 'あなたの投稿がリピートされました' }, login: { login: 'ログイン', - username: 'ユーザーネーム', + username: 'ユーザー名', password: 'パスワード', register: '登録', logout: 'ログアウト' @@ -607,43 +681,51 @@ const ja = { }, post_status: { posting: '投稿', - default: 'ちょうど羽田に着陸しました' + default: 'ちょうどL.A.に着陸しました。' }, finder: { find_user: 'ユーザー検索', error_fetching_user: 'ユーザー検索でエラーが発生しました' }, general: { - submit: '送信' + submit: '送信', + apply: '適用' + }, + user_profile: { + timeline_title: 'ユーザータイムライン' } } const fr = { nav: { + chat: 'Chat local', timeline: 'Journal', mentions: 'Notifications', public_tl: 'Statuts locaux', twkn: 'Le réseau connu' }, user_card: { - follows_you: 'Vous suit!', - following: 'Suivi!', + follows_you: 'Vous suit !', + following: 'Suivi !', follow: 'Suivre', blocked: 'Bloqué', block: 'Bloquer', statuses: 'Statuts', - mute: 'En sourdine', - muted: 'Mis en sourdine', + mute: 'Mettre en muet', + muted: 'Mis en muet', followers: 'Vous suivent', followees: 'Suivis', - per_day: 'par jour' + per_day: 'par jour', + remote_follow: 'Suivre d\'une autre instance' }, timeline: { show_new: 'Afficher plus', error_fetching: 'Erreur en cherchant des mises à jours', up_to_date: 'À jour', load_older: 'Afficher plus', - conversation: 'Conversation' + conversation: 'Conversation', + collapse: 'Fermer', + repeated: 'a partagé' }, settings: { user_settings: 'Paramètres utilisateur', @@ -653,26 +735,51 @@ const fr = { avatar: 'Avatar', current_avatar: 'Votre avatar', set_new_avatar: 'Changer d\'avatar', - profile_banner: 'Bannière du Profil', + profile_banner: 'Bannière du profil', current_profile_banner: 'Bannière du profil', set_new_profile_banner: 'Changer de bannière', profile_background: 'Image de fond', - set_new_profile_background: 'Changer l\'image de fond', + set_new_profile_background: 'Changer d\'image de fond', settings: 'Paramètres', theme: 'Thème', filtering: 'Filtre', - filtering_explanation: 'Tout les statuts contenant ces mots vont être mis sous silence, un mot par ligne.', + filtering_explanation: 'Tout les statuts contenant ces mots vont être cachés, un mot par ligne.', attachments: 'Pièces jointes', hide_attachments_in_tl: 'Cacher les pièces jointes dans le journal', hide_attachments_in_convo: 'Cacher les pièces jointes dans les conversations', nsfw_clickthrough: 'Activer le clic pour afficher les images marquées comme contenu adulte ou sensible', autoload: 'Activer le chargement automatique une fois le bas de la page atteint', - reply_link_preview: 'Activer un aperçu sur passage de la souris' + reply_link_preview: 'Activer un aperçu d\'une réponse sur passage de la souris', + presets: 'Thèmes prédéfinis', + theme_help: 'Utilisez les codes de couleur hexadécimaux (#aabbcc) pour customiser les couleurs de votre thème.', + background: 'Arrière plan', + foreground: 'Premier plan', + text: 'Texte', + links: 'Liens', + streaming: 'Active le défilement automatique de nouveaux statuts lorsqu\'on est au haut de la page', + follow_import: 'Importer ses abonnements', + import_followers_from_a_csv_file: 'Importer ses abonnements depuis un fichier csv', + follows_imported: 'Abonnements importés ! Le traitement peut prendre un moment.', + follow_import_error: 'Erreur lors de l\'importation des abonnements.', + cBlue: 'Bleu (Répondre, suivre)', + cRed: 'Rouge (Annuler)', + cOrange: 'Orange (Aimer)', + cGreen: 'Vert (Partager)', + btnRadius: 'Boutons', + panelRadius: 'Fenêtres', + avatarRadius: 'Avatars', + avatarAltRadius: 'Avatars (Notifications)', + tooltipRadius: 'Info-bulles/alertes ', + attachmentRadius: 'Pièces jointes', + radii_help: 'Mettre en place l\'arondissement des coins de l\'interface (en pixels)', + stop_gifs: 'Passer la souris sur un GIF pour l\'animer' }, notifications: { - notifications: 'Notfications', - read: 'Lu!', - followed_you: 'vous a suivi' + notifications: 'Notifications', + read: 'Lu !', + followed_you: 'vous a suivi', + favorited_you: 'a aimé votre statut', + repeated_you: 'a partagé votre statut' }, login: { login: 'Connexion', @@ -683,10 +790,10 @@ const fr = { }, registration: { registration: 'Inscription', - fullname: 'Nom complet', - email: 'Adresse courriel', + fullname: 'Nom affiché', + email: 'Adresse email', bio: 'Biographie', - password_confirm: 'Confirmer le mot de passe' + password_confirm: 'Confirmez le mot de passe' }, post_status: { posting: 'Envoi en cours', @@ -694,10 +801,14 @@ const fr = { }, finder: { find_user: 'Chercher un utilisateur', - error_fetching_user: 'Une erreur est survenue pendant la recherche d\'un utilisateur' + error_fetching_user: 'Une erreur est survenue lors de la recherche de l\'utilisateur' }, general: { - submit: 'Envoyer' + submit: 'Envoyer', + apply: 'Appliquer' + }, + user_profile: { + timeline_title: 'Journal de l\'utilisateur' } } @@ -759,8 +870,131 @@ const it = { } } +const oc = { + chat: { + title: 'Messatjariá' + }, + nav: { + chat: 'Chat local', + timeline: 'Flux d’actualitat', + mentions: 'Notificacions', + public_tl: 'Estatuts locals', + twkn: 'Lo malhum conegut' + }, + user_card: { + follows_you: 'Vos sèc !', + following: 'Seguit !', + follow: 'Seguir', + blocked: 'Blocat', + block: 'Blocar', + statuses: 'Estatuts', + mute: 'Amagar', + muted: 'Amagat', + followers: 'Seguidors', + followees: 'Abonaments', + per_day: 'per jorn', + remote_follow: 'Seguir a distància' + }, + timeline: { + show_new: 'Ne veire mai', + error_fetching: 'Error en cercant de mesas a jorn', + up_to_date: 'Actualizat', + load_older: 'Ne veire mai', + conversation: 'Conversacion', + collapse: 'Tampar', + repeated: 'repetit' + }, + settings: { + user_settings: 'Paramètres utilizaire', + name_bio: 'Nom & Bio', + name: 'Nom', + bio: 'Biografia', + avatar: 'Avatar', + current_avatar: 'Vòstre avatar actual', + set_new_avatar: 'Cambiar l’avatar', + profile_banner: 'Bandièra del perfil', + current_profile_banner: 'Bandièra actuala del perfil', + set_new_profile_banner: 'Cambiar de bandièra', + profile_background: 'Imatge de fons', + set_new_profile_background: 'Cambiar l’imatge de fons', + settings: 'Paramètres', + theme: 'Tèma', + presets: 'Pre-enregistrats', + theme_help: 'Emplegatz los còdis de color hex (#rrggbb) per personalizar vòstre tèma de color.', + radii_help: 'Configurar los caires arredondits de l’interfàcia (en pixèls)', + background: 'Rèire plan', + foreground: 'Endavant', + text: 'Tèxte', + links: 'Ligams', + cBlue: 'Blau (Respondre, seguir)', + cRed: 'Roge (Anullar)', + cOrange: 'Irange (Metre en favorit)', + cGreen: 'Verd (Repartajar)', + btnRadius: 'Botons', + panelRadius: 'Panèls', + avatarRadius: 'Avatars', + avatarAltRadius: 'Avatars (Notificacions)', + tooltipRadius: 'Astúcias/Alèrta', + attachmentRadius: 'Pèças juntas', + filtering: 'Filtre', + filtering_explanation: 'Totes los estatuts amb aqueles mots seràn en silenci, un mot per linha.', + attachments: 'Pèças juntas', + hide_attachments_in_tl: 'Rescondre las pèças juntas', + hide_attachments_in_convo: 'Rescondre las pèças juntas dins las conversacions', + nsfw_clickthrough: 'Activar lo clic per mostrar los imatges marcats coma pels adults o sensibles', + stop_gifs: 'Lançar los GIFs al subrevòl', + autoload: 'Activar lo cargament automatic un còp arribat al cap de la pagina', + streaming: 'Activar lo cargament automatic dels novèls estatus en anar amont', + reply_link_preview: 'Activar l’apercebut en passar la mirga', + follow_import: 'Importar los abonaments', + import_followers_from_a_csv_file: 'Importar los seguidors d’un fichièr csv', + follows_imported: 'Seguidors importats. Lo tractament pòt trigar una estona.', + follow_import_error: 'Error en important los seguidors' + }, + notifications: { + notifications: 'Notficacions', + read: 'Legit !', + followed_you: 'vos a seguit', + favorited_you: 'a aimat vòstre estatut', + repeated_you: 'a repetit your vòstre estatut' + }, + login: { + login: 'Connexion', + username: 'Nom d’utilizaire', + password: 'Senhal', + register: 'Se marcar', + logout: 'Desconnexion' + }, + registration: { + registration: 'Inscripcion', + fullname: 'Nom complèt', + email: 'Adreça de corrièl', + bio: 'Biografia', + password_confirm: 'Confirmar lo senhal' + }, + post_status: { + posting: 'Mandadís', + default: 'Escrivètz aquí vòstre estatut.' + }, + finder: { + find_user: 'Cercar un utilizaire', + error_fetching_user: 'Error pendent la recèrca d’un utilizaire' + }, + general: { + submit: 'Mandar', + apply: 'Aplicar' + }, + user_profile: { + timeline_title: 'Flux a l’utilizaire' + } +} + const pl = { + chat: { + title: 'Czat' + }, nav: { + chat: 'Lokalny czat', timeline: 'Oś czasu', mentions: 'Wzmianki', public_tl: 'Publiczna oś czasu', @@ -777,14 +1011,17 @@ const pl = { muted: 'Wyciszony', followers: 'Obserwujący', followees: 'Obserwowani', - per_day: 'dziennie' + per_day: 'dziennie', + remote_follow: 'Zdalna obserwacja' }, timeline: { show_new: 'Pokaż nowe', error_fetching: 'Błąd pobierania', up_to_date: 'Na bieżąco', load_older: 'Załaduj starsze statusy', - conversation: 'Rozmowa' + conversation: 'Rozmowa', + collapse: 'Zwiń', + repeated: 'powtórzono' }, settings: { user_settings: 'Ustawienia użytkownika', @@ -794,26 +1031,51 @@ const pl = { avatar: 'Awatar', current_avatar: 'Twój obecny awatar', set_new_avatar: 'Ustaw nowy awatar', - profile_banner: 'Banner profilui', + profile_banner: 'Banner profilu', current_profile_banner: 'Twój obecny banner profilu', set_new_profile_banner: 'Ustaw nowy banner profilu', profile_background: 'Tło profilu', set_new_profile_background: 'Ustaw nowe tło profilu', settings: 'Ustawienia', theme: 'Motyw', + presets: 'Gotowe motywy', + theme_help: 'Użyj kolorów w notacji szesnastkowej (#rrggbb), by stworzyć swój motyw.', + radii_help: 'Ustaw zaokrąglenie krawędzi interfejsu (w pikselach)', + background: 'Tło', + foreground: 'Pierwszy plan', + text: 'Tekst', + links: 'Łącza', + cBlue: 'Niebieski (odpowiedz, obserwuj)', + cRed: 'Czerwony (anuluj)', + cOrange: 'Pomarańczowy (ulubione)', + cGreen: 'Zielony (powtórzenia)', + btnRadius: 'Przyciski', + panelRadius: 'Panele', + avatarRadius: 'Awatary', + avatarAltRadius: 'Awatary (powiadomienia)', + tooltipRadius: 'Etykiety/alerty', + attachmentRadius: 'Załączniki', filtering: 'Filtrowanie', filtering_explanation: 'Wszystkie statusy zawierające te słowa będą wyciszone. Jedno słowo na linijkę', attachments: 'Załączniki', hide_attachments_in_tl: 'Ukryj załączniki w osi czasu', hide_attachments_in_convo: 'Ukryj załączniki w rozmowach', nsfw_clickthrough: 'Włącz domyślne ukrywanie załączników o treści nieprzyzwoitej (NSFW)', + stop_gifs: 'Odtwarzaj GIFy po najechaniu kursorem', autoload: 'Włącz automatyczne ładowanie po przewinięciu do końca strony', - reply_link_preview: 'Włącz dymek z podglądem postu po najechaniu na znak odpowiedzi' + streaming: 'Włącz automatycznie strumieniowanie nowych postów gdy na początku strony', + reply_link_preview: 'Włącz dymek z podglądem postu po najechaniu na znak odpowiedzi', + follow_import: 'Import obserwowanych', + import_followers_from_a_csv_file: 'Importuj obserwowanych z pliku CSV', + follows_imported: 'Obserwowani zaimportowani! Przetwarzanie może trochę potrwać.', + follow_import_error: 'Błąd przy importowaniu obserwowanych' }, notifications: { notifications: 'Powiadomienia', read: 'Przeczytane!', - followed_you: 'obserwuje cię' + followed_you: 'obserwuje cię', + favorited_you: 'dodał twój status do ulubionych', + repeated_you: 'powtórzył twój status' }, login: { login: 'Zaloguj', @@ -824,7 +1086,7 @@ const pl = { }, registration: { registration: 'Rejestracja', - fullname: 'Wyświetlane imię', + fullname: 'Wyświetlana nazwa profilu', email: 'Email', bio: 'Bio', password_confirm: 'Potwierdzenie hasła' @@ -838,7 +1100,11 @@ const pl = { error_fetching_user: 'Błąd przy pobieraniu profilu' }, general: { - submit: 'Wyślij' + submit: 'Wyślij', + apply: 'Zastosuj' + }, + user_profile: { + timeline_title: 'Oś czasu użytkownika' } } @@ -890,7 +1156,7 @@ const es = { settings: 'Ajustes', theme: 'Tema', presets: 'Por defecto', - theme_help: 'Use códigos de color hexadecimales (#aabbcc) para personalizar su tema de colores.', + theme_help: 'Use códigos de color hexadecimales (#rrggbb) para personalizar su tema de colores.', background: 'Segundo plano', foreground: 'Primer plano', text: 'Texto', @@ -960,11 +1226,12 @@ const pt = { blocked: 'Bloqueado!', block: 'Bloquear', statuses: 'Postagens', - mute: 'Mutar', - muted: 'Mudo', + mute: 'Silenciar', + muted: 'Silenciado', followers: 'Seguidores', followees: 'Seguindo', - per_day: 'por dia' + per_day: 'por dia', + remote_follow: 'Seguidor Remoto' }, timeline: { show_new: 'Mostrar novas', @@ -980,16 +1247,16 @@ const pt = { bio: 'Biografia', avatar: 'Avatar', current_avatar: 'Seu avatar atual', - set_new_avatar: 'Mudar avatar', + set_new_avatar: 'Alterar avatar', profile_banner: 'Capa de perfil', current_profile_banner: 'Sua capa de perfil atual', - set_new_profile_banner: 'Mudar capa de perfil', + set_new_profile_banner: 'Alterar capa de perfil', profile_background: 'Plano de fundo de perfil', - set_new_profile_background: 'Mudar o plano de fundo de perfil', + set_new_profile_background: 'Alterar o plano de fundo de perfil', settings: 'Configurações', theme: 'Tema', presets: 'Predefinições', - theme_help: 'Use cores em códigos hexadecimais (#aabbcc) para personalizar seu esquema de cores.', + theme_help: 'Use cores em código hexadecimal (#rrggbb) para personalizar seu esquema de cores.', background: 'Plano de Fundo', foreground: 'Primeiro Plano', text: 'Texto', @@ -1004,9 +1271,9 @@ const pt = { streaming: 'Habilitar o fluxo automático de postagens quando ao topo da página', reply_link_preview: 'Habilitar a pré-visualização de link de respostas ao passar o mouse.', follow_import: 'Importar seguidas', - import_followers_from_a_csv_file: 'Importe os perfis que tu segues apartir de um arquivo CSV', - follows_imported: 'Seguidas importadas! O processamento das mesmas pode demorar um pouco.', - follow_import_error: 'Erro ao importar seguidas' + import_followers_from_a_csv_file: 'Importe seguidores a partir de um arquivo CSV', + follows_imported: 'Seguidores importados! O processamento pode demorar um pouco.', + follow_import_error: 'Erro ao importar seguidores' }, notifications: { notifications: 'Notificações', @@ -1023,7 +1290,7 @@ const pt = { registration: { registration: 'Registro', fullname: 'Nome para exibição', - email: 'Correio eletônico', + email: 'Correio eletrônico', bio: 'Biografia', password_confirm: 'Confirmação de senha' }, @@ -1071,7 +1338,9 @@ const ru = { error_fetching: 'Ошибка при обновлении', up_to_date: 'Обновлено', load_older: 'Загрузить старые статусы', - conversation: 'Разговор' + conversation: 'Разговор', + collapse: 'Свернуть', + repeated: 'повторил(а)' }, settings: { user_settings: 'Настройки пользователя', @@ -1089,16 +1358,28 @@ const ru = { settings: 'Настройки', theme: 'Тема', presets: 'Пресеты', - theme_help: 'Используйте шестнадцатеричные коды цветов (#aabbcc) для настройки темы.', + theme_help: 'Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.', + radii_help: 'Округление краёв элементов интерфейса (в пикселях)', background: 'Фон', foreground: 'Передний план', text: 'Текст', links: 'Ссылки', + cBlue: 'Ответить, читать', + cRed: 'Отменить', + cOrange: 'Нравится', + cGreen: 'Повторить', + btnRadius: 'Кнопки', + panelRadius: 'Панели', + avatarRadius: 'Аватары', + avatarAltRadius: 'Аватары в уведомлениях', + tooltipRadius: 'Всплывающие подсказки/уведомления', + attachmentRadius: 'Прикреплённые файлы', filtering: 'Фильтрация', filtering_explanation: 'Все статусы, содержащие данные слова, будут игнорироваться, по одному в строке', attachments: 'Вложения', hide_attachments_in_tl: 'Прятать вложения в ленте', hide_attachments_in_convo: 'Прятать вложения в разговорах', + stop_gifs: 'Проигрывать GIF анимации только при наведении', nsfw_clickthrough: 'Включить скрытие NSFW вложений', autoload: 'Включить автоматическую загрузку при прокрутке вниз', streaming: 'Включить автоматическую загрузку новых сообщений при прокрутке вверх', @@ -1111,7 +1392,9 @@ const ru = { notifications: { notifications: 'Уведомления', read: 'Прочесть', - followed_you: 'начал читать вас' + followed_you: 'начал(а) читать вас', + favorited_you: 'нравится ваш статус', + repeated_you: 'повторил(а) ваш статус' }, login: { login: 'Войти', @@ -1154,6 +1437,7 @@ const messages = { ja, fr, it, + oc, pl, es, pt, diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 18191424..bd52f161 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -1,7 +1,23 @@ -import { includes, remove, slice, sortBy, toInteger, each, find, flatten, maxBy, last, merge, max, isArray } from 'lodash' +import { includes, remove, slice, sortBy, toInteger, each, find, flatten, maxBy, minBy, merge, last, isArray } from 'lodash' import apiService from '../services/api/api.service.js' // import parse from '../services/status_parser/status_parser.js' +const emptyTl = () => ({ + statuses: [], + statusesObject: {}, + faves: [], + visibleStatuses: [], + visibleStatusesObject: {}, + newStatusCount: 0, + maxId: 0, + minVisibleId: 0, + loading: false, + followers: [], + friends: [], + viewing: 'statuses', + flushMarker: 0 +}) + export const defaultState = { allStatuses: [], allStatusesObject: {}, @@ -10,96 +26,12 @@ export const defaultState = { favorites: new Set(), error: false, timelines: { - mentions: { - statuses: [], - statusesObject: {}, - faves: [], - visibleStatuses: [], - visibleStatusesObject: {}, - newStatusCount: 0, - maxId: 0, - minVisibleId: 0, - loading: false, - followers: [], - friends: [], - viewing: 'statuses', - flushMarker: 0 - }, - public: { - statuses: [], - statusesObject: {}, - faves: [], - visibleStatuses: [], - visibleStatusesObject: {}, - newStatusCount: 0, - maxId: 0, - minVisibleId: 0, - loading: false, - followers: [], - friends: [], - viewing: 'statuses', - flushMarker: 0 - }, - user: { - statuses: [], - statusesObject: {}, - faves: [], - visibleStatuses: [], - visibleStatusesObject: {}, - newStatusCount: 0, - maxId: 0, - minVisibleId: 0, - loading: false, - followers: [], - friends: [], - viewing: 'statuses', - flushMarker: 0 - }, - publicAndExternal: { - statuses: [], - statusesObject: {}, - faves: [], - visibleStatuses: [], - visibleStatusesObject: {}, - newStatusCount: 0, - maxId: 0, - minVisibleId: 0, - loading: false, - followers: [], - friends: [], - viewing: 'statuses', - flushMarker: 0 - }, - friends: { - statuses: [], - statusesObject: {}, - faves: [], - visibleStatuses: [], - visibleStatusesObject: {}, - newStatusCount: 0, - maxId: 0, - minVisibleId: 0, - loading: false, - followers: [], - friends: [], - viewing: 'statuses', - flushMarker: 0 - }, - tag: { - statuses: [], - statusesObject: {}, - faves: [], - visibleStatuses: [], - visibleStatusesObject: {}, - newStatusCount: 0, - maxId: 0, - minVisibleId: 0, - loading: false, - followers: [], - friends: [], - viewing: 'statuses', - flushMarker: 0 - } + mentions: emptyTl(), + public: emptyTl(), + user: emptyTl(), + publicAndExternal: emptyTl(), + friends: emptyTl(), + tag: emptyTl() } } @@ -112,6 +44,9 @@ export const prepareStatus = (status) => { // Parse nsfw tags if (status.nsfw === undefined) { status.nsfw = isNsfw(status) + if (status.retweeted_status) { + status.retweeted_status.nsfw = status.nsfw + } } // Set deleted flag @@ -175,7 +110,6 @@ const sortTimeline = (timeline) => { timeline.visibleStatuses = sortBy(timeline.visibleStatuses, ({id}) => -id) timeline.statuses = sortBy(timeline.statuses, ({id}) => -id) timeline.minVisibleId = (last(timeline.visibleStatuses) || {}).id - return timeline } @@ -189,10 +123,11 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us const allStatusesObject = state.allStatusesObject const timelineObject = state.timelines[timeline] - // Set the maxId to the new id if it's larger. - const updateMaxId = ({id}) => { - if (!timeline || noIdUpdate) { return false } - timelineObject.maxId = max([id, timelineObject.maxId]) + const maxNew = statuses.length > 0 ? maxBy(statuses, 'id').id : 0 + const older = timeline && maxNew < timelineObject.maxId + + if (timeline && !noIdUpdate && statuses.length > 0 && !older) { + timelineObject.maxId = maxNew } const addStatus = (status, showImmediately, addToTimeline = true) => { @@ -200,8 +135,6 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us status = result.item if (result.new) { - updateMaxId(status) - if (statusType(status) === 'retweet' && status.retweeted_status.user.id === user.id) { addNotification({ type: 'repeat', status: status.retweeted_status, action: status }) } @@ -246,7 +179,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us const addNotification = ({type, status, action}) => { // Only add a new notification if we don't have one for the same action if (!find(state.notifications, (oldNotification) => oldNotification.action.id === action.id)) { - state.notifications.push({type, status, action, seen: false}) + state.notifications.push({ type, status, action, seen: false }) if ('Notification' in window && window.Notification.permission === 'granted') { const title = action.user.name @@ -317,7 +250,6 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us // Only update if this is a new favorite. if (!state.favorites.has(favorite.id)) { state.favorites.add(favorite.id) - updateMaxId(favorite) favoriteStatus(favorite) } }, @@ -330,7 +262,6 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us }, 'deletion': (deletion) => { const uri = deletion.uri - updateMaxId(deletion) // Remove possible notification const status = find(allStatuses, {uri}) @@ -361,6 +292,9 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us // Keep the visible statuses sorted if (timeline) { sortTimeline(timelineObject) + if ((older || timelineObject.minVisibleId <= 0) && statuses.length > 0) { + timelineObject.minVisibleId = minBy(statuses, 'id').id + } } } @@ -371,27 +305,12 @@ export const mutations = { oldTimeline.newStatusCount = 0 oldTimeline.visibleStatuses = slice(oldTimeline.statuses, 0, 50) + oldTimeline.minVisibleId = last(oldTimeline.visibleStatuses).id oldTimeline.visibleStatusesObject = {} each(oldTimeline.visibleStatuses, (status) => { oldTimeline.visibleStatusesObject[status.id] = status }) }, clearTimeline (state, { timeline }) { - const emptyTimeline = { - statuses: [], - statusesObject: {}, - faves: [], - visibleStatuses: [], - visibleStatusesObject: {}, - newStatusCount: 0, - maxId: 0, - minVisibleId: 0, - loading: false, - followers: [], - friends: [], - viewing: 'statuses', - flushMarker: 0 - } - - state.timelines[timeline] = emptyTimeline + state.timelines[timeline] = emptyTl() }, setFavorited (state, { status, value }) { const newStatus = state.allStatusesObject[status.id] diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 6863bd0a..9dc4a3e1 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -45,12 +45,8 @@ const setStyle = (href, commit) => { const styleEl = document.createElement('style') head.appendChild(styleEl) - const styleSheet = styleEl.sheet + // const styleSheet = styleEl.sheet - styleSheet.insertRule(`a { color: ${colors['base08']}`, 'index-max') - styleSheet.insertRule(`body { color: ${colors['base05']}`, 'index-max') - styleSheet.insertRule(`.base05-border { border-color: ${colors['base05']}`, 'index-max') - styleSheet.insertRule(`.base03-border { border-color: ${colors['base03']}`, 'index-max') body.style.display = 'initial' } @@ -68,37 +64,47 @@ const setColors = (col, commit) => { const isDark = (col.text.r + col.text.g + col.text.b) > (col.bg.r + col.bg.g + col.bg.b) let colors = {} + let radii = {} - let mod = 10 - if (isDark) { - mod = mod * -1 - } + const mod = isDark ? -10 : 10 + + colors.bg = rgb2hex(col.bg.r, col.bg.g, col.bg.b) // background + colors.lightBg = rgb2hex((col.bg.r + col.fg.r) / 2, (col.bg.g + col.fg.g) / 2, (col.bg.b + col.fg.b) / 2) // hilighted bg + colors.btn = rgb2hex(col.fg.r, col.fg.g, col.fg.b) // panels & buttons + colors.border = rgb2hex(col.fg.r - mod, col.fg.g - mod, col.fg.b - mod) // borders + colors.faint = rgb2hex( + col.text.r * 0.45 + col.fg.r * 0.55, + col.text.g * 0.45 + col.fg.g * 0.55, + col.text.b * 0.45 + col.fg.b * 0.55) // faint text + colors.fg = rgb2hex(col.text.r, col.text.g, col.text.b) // text + colors.lightFg = rgb2hex(col.text.r - mod, col.text.g - mod, col.text.b - mod) // strong text - colors['base00'] = rgb2hex(col.bg.r, col.bg.g, col.bg.b) // background - colors['base01'] = rgb2hex((col.bg.r + col.fg.r) / 2, (col.bg.g + col.fg.g) / 2, (col.bg.b + col.fg.b) / 2) // hilighted bg - colors['base02'] = rgb2hex(col.fg.r, col.fg.g, col.fg.b) // panels & buttons - colors['base03'] = rgb2hex(col.fg.r - mod, col.fg.g - mod, col.fg.b - mod) // borders - colors['base04'] = rgb2hex(col.text.r + mod * 2, col.text.g + mod * 2, col.text.b + mod * 2) // faint text - colors['base05'] = rgb2hex(col.text.r, col.text.g, col.text.b) // text - colors['base06'] = rgb2hex(col.text.r - mod, col.text.g - mod, col.text.b - mod) // strong text colors['base07'] = rgb2hex(col.text.r - mod * 2, col.text.g - mod * 2, col.text.b - mod * 2) - colors['base08'] = rgb2hex(col.link.r, col.link.g, col.link.b) // links - colors['base09'] = rgb2hex((col.bg.r + col.text.r) / 2, (col.bg.g + col.text.g) / 2, (col.bg.b + col.text.b) / 2) // icons - - const num = 10 - times(num, (n) => { - const color = colors[`base0${num - 1 - n}`] - styleSheet.insertRule(`.base0${num - 1 - n} { color: ${color}`, 'index-max') - styleSheet.insertRule(`.base0${num - 1 - n}-background { background-color: ${color}`, 'index-max') - }) - - styleSheet.insertRule(`a { color: ${colors['base08']}`, 'index-max') - styleSheet.insertRule(`body { color: ${colors['base05']}`, 'index-max') - styleSheet.insertRule(`.base05-border { border-color: ${colors['base05']}`, 'index-max') - styleSheet.insertRule(`.base03-border { border-color: ${colors['base03']}`, 'index-max') + + colors.link = rgb2hex(col.link.r, col.link.g, col.link.b) // links + colors.icon = rgb2hex((col.bg.r + col.text.r) / 2, (col.bg.g + col.text.g) / 2, (col.bg.b + col.text.b) / 2) // icons + + colors.cBlue = col.cBlue && rgb2hex(col.cBlue.r, col.cBlue.g, col.cBlue.b) + colors.cRed = col.cRed && rgb2hex(col.cRed.r, col.cRed.g, col.cRed.b) + colors.cGreen = col.cGreen && rgb2hex(col.cGreen.r, col.cGreen.g, col.cGreen.b) + colors.cOrange = col.cOrange && rgb2hex(col.cOrange.r, col.cOrange.g, col.cOrange.b) + + colors.cAlertRed = col.cRed && `rgba(${col.cRed.r}, ${col.cRed.g}, ${col.cRed.b}, .5)` + + radii.btnRadius = col.btnRadius + radii.panelRadius = col.panelRadius + radii.avatarRadius = col.avatarRadius + radii.avatarAltRadius = col.avatarAltRadius + radii.tooltipRadius = col.tooltipRadius + radii.attachmentRadius = col.attachmentRadius + + styleSheet.toString() + styleSheet.insertRule(`body { ${Object.entries(colors).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';')} }`, 'index-max') + styleSheet.insertRule(`body { ${Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';')} }`, 'index-max') body.style.display = 'initial' commit('setOption', { name: 'colors', value: colors }) + commit('setOption', { name: 'radii', value: radii }) commit('setOption', { name: 'customTheme', value: col }) } @@ -111,12 +117,23 @@ const setPreset = (val, commit) => { const fgRgb = hex2rgb(theme[2]) const textRgb = hex2rgb(theme[3]) const linkRgb = hex2rgb(theme[4]) + + const cRedRgb = hex2rgb(theme[5] || '#FF0000') + const cGreenRgb = hex2rgb(theme[6] || '#00FF00') + const cBlueRgb = hex2rgb(theme[7] || '#0000FF') + const cOrangeRgb = hex2rgb(theme[8] || '#E3FF00') + const col = { bg: bgRgb, fg: fgRgb, text: textRgb, - link: linkRgb + link: linkRgb, + cRed: cRedRgb, + cBlue: cBlueRgb, + cGreen: cGreenRgb, + cOrange: cOrangeRgb } + // This is a hack, this function is only called during initial load. // We want to cancel loading the theme from config.json if we're already // loading a theme from the persisted state. diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js index a4a80df0..bb5fdc2e 100644 --- a/src/services/timeline_fetcher/timeline_fetcher.service.js +++ b/src/services/timeline_fetcher/timeline_fetcher.service.js @@ -30,7 +30,7 @@ const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false return apiService.fetchTimeline(args) .then((statuses) => { - if (!older && statuses.length >= 20) { + if (!older && statuses.length >= 20 && !timelineData.loading) { store.dispatch('queueFlush', { timeline: timeline, id: timelineData.maxId }) } update({store, statuses, timeline, showImmediately}) diff --git a/static/aurora_borealis.jpg b/static/aurora_borealis.jpg Binary files differnew file mode 100644 index 00000000..b6a0daf9 --- /dev/null +++ b/static/aurora_borealis.jpg diff --git a/static/bg.jpg b/static/bg2.jpg Binary files differindex 60e2311a..60e2311a 100644 --- a/static/bg.jpg +++ b/static/bg2.jpg diff --git a/static/config.json b/static/config.json index 23fdf8a8..fc1b0795 100644 --- a/static/config.json +++ b/static/config.json @@ -1,6 +1,6 @@ { "theme": "pleroma-dark", - "background": "/static/bg.jpg", + "background": "/static/aurora_borealis.jpg", "logo": "/static/logo.png", "defaultPath": "/main/all", "chatDisabled": false, diff --git a/static/font/config.json b/static/font/config.json index 98ece6ad..37adff79 100644 --- a/static/font/config.json +++ b/static/font/config.json @@ -95,6 +95,66 @@ "css": "logout", "code": 59400, "src": "fontawesome" + }, + { + "uid": "ccddff8e8670dcd130e3cb55fdfc2fd0", + "css": "down-open", + "code": 59401, + "src": "fontawesome" + }, + { + "uid": "44b9e75612c5fad5505edd70d071651f", + "css": "attach", + "code": 59402, + "src": "entypo" + }, + { + "uid": "e15f0d620a7897e2035c18c80142f6d9", + "css": "link-ext", + "code": 61582, + "src": "fontawesome" + }, + { + "uid": "381da2c2f7fd51f8de877c044d7f439d", + "css": "picture", + "code": 59403, + "src": "fontawesome" + }, + { + "uid": "872d9516df93eb6b776cc4d94bd97dac", + "css": "video", + "code": 59404, + "src": "fontawesome" + }, + { + "uid": "399ef63b1e23ab1b761dfbb5591fa4da", + "css": "right-open", + "code": 59405, + "src": "fontawesome" + }, + { + "uid": "d870630ff8f81e6de3958ecaeac532f2", + "css": "left-open", + "code": 59406, + "src": "fontawesome" + }, + { + "uid": "fe6697b391355dec12f3d86d6d490397", + "css": "up-open", + "code": 59407, + "src": "fontawesome" + }, + { + "uid": "9c1376672bb4f1ed616fdd78a23667e9", + "css": "comment-empty", + "code": 61669, + "src": "fontawesome" + }, + { + "uid": "cd21cbfb28ad4d903cede582157f65dc", + "css": "bell", + "code": 59408, + "src": "fontawesome" } ] }
\ No newline at end of file diff --git a/static/font/css/animation.css b/static/font/css/animation.css index c8cfc252..ac5a9562 100644 --- a/static/font/css/animation.css +++ b/static/font/css/animation.css @@ -8,13 +8,6 @@ animation: spin 2s infinite linear; display: inline-block; } -.animate-spin-slow { - -moz-animation: spin 4s infinite linear; - -o-animation: spin 4s infinite linear; - -webkit-animation: spin 4s infinite linear; - animation: spin 4s infinite linear; - display: inline-block; -} @-moz-keyframes spin { 0% { -moz-transform: rotate(0deg); diff --git a/static/font/css/fontello-codes.css b/static/font/css/fontello-codes.css index 8831e4ee..e4e4e64d 100644 --- a/static/font/css/fontello-codes.css +++ b/static/font/css/fontello-codes.css @@ -8,9 +8,19 @@ .icon-plus-squared:before { content: '\e806'; } /* '' */ .icon-cog:before { content: '\e807'; } /* '' */ .icon-logout:before { content: '\e808'; } /* '' */ +.icon-down-open:before { content: '\e809'; } /* '' */ +.icon-attach:before { content: '\e80a'; } /* '' */ +.icon-picture:before { content: '\e80b'; } /* '' */ +.icon-video:before { content: '\e80c'; } /* '' */ +.icon-right-open:before { content: '\e80d'; } /* '' */ +.icon-left-open:before { content: '\e80e'; } /* '' */ +.icon-up-open:before { content: '\e80f'; } /* '' */ +.icon-bell:before { content: '\e810'; } /* '' */ .icon-spin3:before { content: '\e832'; } /* '' */ .icon-spin4:before { content: '\e834'; } /* '' */ +.icon-link-ext:before { content: '\f08e'; } /* '' */ .icon-menu:before { content: '\f0c9'; } /* '' */ +.icon-comment-empty:before { content: '\f0e5'; } /* '' */ .icon-reply:before { content: '\f112'; } /* '' */ .icon-binoculars:before { content: '\f1e5'; } /* '' */ .icon-user-plus:before { content: '\f234'; } /* '' */
\ No newline at end of file diff --git a/static/font/css/fontello-embedded.css b/static/font/css/fontello-embedded.css index f9d38315..20e498fe 100644 --- a/static/font/css/fontello-embedded.css +++ b/static/font/css/fontello-embedded.css @@ -1,15 +1,15 @@ @font-face { font-family: 'fontello'; - src: url('../font/fontello.eot?34768509'); - src: url('../font/fontello.eot?34768509#iefix') format('embedded-opentype'), - url('../font/fontello.svg?34768509#fontello') format('svg'); + src: url('../font/fontello.eot?12951540'); + src: url('../font/fontello.eot?12951540#iefix') format('embedded-opentype'), + url('../font/fontello.svg?12951540#fontello') format('svg'); font-weight: normal; font-style: normal; } @font-face { font-family: 'fontello'; - src: url('data:application/octet-stream;base64,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') format('woff'), - url('data:application/octet-stream;base64,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') format('truetype'); + src: url('data:application/octet-stream;base64,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') format('woff'), + url('data:application/octet-stream;base64,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') format('truetype'); } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ @@ -17,7 +17,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'fontello'; - src: url('../font/fontello.svg?34768509#fontello') format('svg'); + src: url('../font/fontello.svg?12951540#fontello') format('svg'); } } */ @@ -61,9 +61,19 @@ .icon-plus-squared:before { content: '\e806'; } /* '' */ .icon-cog:before { content: '\e807'; } /* '' */ .icon-logout:before { content: '\e808'; } /* '' */ +.icon-down-open:before { content: '\e809'; } /* '' */ +.icon-attach:before { content: '\e80a'; } /* '' */ +.icon-picture:before { content: '\e80b'; } /* '' */ +.icon-video:before { content: '\e80c'; } /* '' */ +.icon-right-open:before { content: '\e80d'; } /* '' */ +.icon-left-open:before { content: '\e80e'; } /* '' */ +.icon-up-open:before { content: '\e80f'; } /* '' */ +.icon-bell:before { content: '\e810'; } /* '' */ .icon-spin3:before { content: '\e832'; } /* '' */ .icon-spin4:before { content: '\e834'; } /* '' */ +.icon-link-ext:before { content: '\f08e'; } /* '' */ .icon-menu:before { content: '\f0c9'; } /* '' */ +.icon-comment-empty:before { content: '\f0e5'; } /* '' */ .icon-reply:before { content: '\f112'; } /* '' */ .icon-binoculars:before { content: '\f1e5'; } /* '' */ .icon-user-plus:before { content: '\f234'; } /* '' */
\ No newline at end of file diff --git a/static/font/css/fontello-ie7-codes.css b/static/font/css/fontello-ie7-codes.css index 3c915b3c..d7a5a523 100644 --- a/static/font/css/fontello-ie7-codes.css +++ b/static/font/css/fontello-ie7-codes.css @@ -8,9 +8,19 @@ .icon-plus-squared { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-cog { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-down-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-attach { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-picture { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-video { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-right-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-left-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-up-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-bell { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-spin3 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-spin4 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-comment-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-reply { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-binoculars { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-user-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
\ No newline at end of file diff --git a/static/font/css/fontello-ie7.css b/static/font/css/fontello-ie7.css index 2fe2a707..5ca12cea 100644 --- a/static/font/css/fontello-ie7.css +++ b/static/font/css/fontello-ie7.css @@ -19,9 +19,19 @@ .icon-plus-squared { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-cog { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-down-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-attach { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-picture { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-video { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-right-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-left-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-up-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-bell { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-spin3 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-spin4 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-comment-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-reply { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-binoculars { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-user-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
\ No newline at end of file diff --git a/static/font/css/fontello.css b/static/font/css/fontello.css index 0c0d2930..5cc6f97d 100644 --- a/static/font/css/fontello.css +++ b/static/font/css/fontello.css @@ -1,11 +1,11 @@ @font-face { font-family: 'fontello'; - src: url('../font/fontello.eot?64848116'); - src: url('../font/fontello.eot?64848116#iefix') format('embedded-opentype'), - url('../font/fontello.woff2?64848116') format('woff2'), - url('../font/fontello.woff?64848116') format('woff'), - url('../font/fontello.ttf?64848116') format('truetype'), - url('../font/fontello.svg?64848116#fontello') format('svg'); + src: url('../font/fontello.eot?47566415'); + src: url('../font/fontello.eot?47566415#iefix') format('embedded-opentype'), + url('../font/fontello.woff2?47566415') format('woff2'), + url('../font/fontello.woff?47566415') format('woff'), + url('../font/fontello.ttf?47566415') format('truetype'), + url('../font/fontello.svg?47566415#fontello') format('svg'); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'fontello'; - src: url('../font/fontello.svg?64848116#fontello') format('svg'); + src: url('../font/fontello.svg?47566415#fontello') format('svg'); } } */ @@ -64,9 +64,19 @@ .icon-plus-squared:before { content: '\e806'; } /* '' */ .icon-cog:before { content: '\e807'; } /* '' */ .icon-logout:before { content: '\e808'; } /* '' */ +.icon-down-open:before { content: '\e809'; } /* '' */ +.icon-attach:before { content: '\e80a'; } /* '' */ +.icon-picture:before { content: '\e80b'; } /* '' */ +.icon-video:before { content: '\e80c'; } /* '' */ +.icon-right-open:before { content: '\e80d'; } /* '' */ +.icon-left-open:before { content: '\e80e'; } /* '' */ +.icon-up-open:before { content: '\e80f'; } /* '' */ +.icon-bell:before { content: '\e810'; } /* '' */ .icon-spin3:before { content: '\e832'; } /* '' */ .icon-spin4:before { content: '\e834'; } /* '' */ +.icon-link-ext:before { content: '\f08e'; } /* '' */ .icon-menu:before { content: '\f0c9'; } /* '' */ +.icon-comment-empty:before { content: '\f0e5'; } /* '' */ .icon-reply:before { content: '\f112'; } /* '' */ .icon-binoculars:before { content: '\f1e5'; } /* '' */ .icon-user-plus:before { content: '\f234'; } /* '' */
\ No newline at end of file diff --git a/static/font/demo.html b/static/font/demo.html index 2c5503c0..d01bd1d6 100644 --- a/static/font/demo.html +++ b/static/font/demo.html @@ -229,11 +229,11 @@ body { } @font-face { font-family: 'fontello'; - src: url('./font/fontello.eot?1253892'); - src: url('./font/fontello.eot?1253892#iefix') format('embedded-opentype'), - url('./font/fontello.woff?1253892') format('woff'), - url('./font/fontello.ttf?1253892') format('truetype'), - url('./font/fontello.svg?1253892#fontello') format('svg'); + src: url('./font/fontello.eot?34497073'); + src: url('./font/fontello.eot?34497073#iefix') format('embedded-opentype'), + url('./font/fontello.woff?34497073') format('woff'), + url('./font/fontello.ttf?34497073') format('truetype'), + url('./font/fontello.svg?34497073#fontello') format('svg'); font-weight: normal; font-style: normal; } @@ -275,7 +275,7 @@ body { /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } </style> - <link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/fontello-ie7.css"><![endif]--> + <link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/" + font.fontname + "-ie7.css"><![endif]--> <script> function toggleCodes(on) { var obj = document.getElementById('icons'); @@ -291,37 +291,50 @@ body { </head> <body> <div class="container header"> - <h1> - fontello - <small>font demo</small> - </h1> + <h1>fontello <small>font demo</small></h1> <label class="switch"> <input type="checkbox" onclick="toggleCodes(this.checked)">show codes </label> </div> - <div id="icons" class="container"> + <div class="container" id="icons"> <div class="row"> - <div title="Code: 0xe800" class="the-icons span3"><i class="demo-icon icon-cancel"></i> <span class="i-name">icon-cancel</span><span class="i-code">0xe800</span></div> - <div title="Code: 0xe801" class="the-icons span3"><i class="demo-icon icon-upload"></i> <span class="i-name">icon-upload</span><span class="i-code">0xe801</span></div> - <div title="Code: 0xe802" class="the-icons span3"><i class="demo-icon icon-star"></i> <span class="i-name">icon-star</span><span class="i-code">0xe802</span></div> - <div title="Code: 0xe803" class="the-icons span3"><i class="demo-icon icon-star-empty"></i> <span class="i-name">icon-star-empty</span><span class="i-code">0xe803</span></div> + <div class="the-icons span3" title="Code: 0xe800"><i class="demo-icon icon-cancel"></i> <span class="i-name">icon-cancel</span><span class="i-code">0xe800</span></div> + <div class="the-icons span3" title="Code: 0xe801"><i class="demo-icon icon-upload"></i> <span class="i-name">icon-upload</span><span class="i-code">0xe801</span></div> + <div class="the-icons span3" title="Code: 0xe802"><i class="demo-icon icon-star"></i> <span class="i-name">icon-star</span><span class="i-code">0xe802</span></div> + <div class="the-icons span3" title="Code: 0xe803"><i class="demo-icon icon-star-empty"></i> <span class="i-name">icon-star-empty</span><span class="i-code">0xe803</span></div> </div> <div class="row"> - <div title="Code: 0xe804" class="the-icons span3"><i class="demo-icon icon-retweet"></i> <span class="i-name">icon-retweet</span><span class="i-code">0xe804</span></div> - <div title="Code: 0xe805" class="the-icons span3"><i class="demo-icon icon-eye-off"></i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe805</span></div> - <div title="Code: 0xe806" class="the-icons span3"><i class="demo-icon icon-plus-squared"></i> <span class="i-name">icon-plus-squared</span><span class="i-code">0xe806</span></div> - <div title="Code: 0xe807" class="the-icons span3"><i class="demo-icon icon-cog"></i> <span class="i-name">icon-cog</span><span class="i-code">0xe807</span></div> + <div class="the-icons span3" title="Code: 0xe804"><i class="demo-icon icon-retweet"></i> <span class="i-name">icon-retweet</span><span class="i-code">0xe804</span></div> + <div class="the-icons span3" title="Code: 0xe805"><i class="demo-icon icon-eye-off"></i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe805</span></div> + <div class="the-icons span3" title="Code: 0xe806"><i class="demo-icon icon-plus-squared"></i> <span class="i-name">icon-plus-squared</span><span class="i-code">0xe806</span></div> + <div class="the-icons span3" title="Code: 0xe807"><i class="demo-icon icon-cog"></i> <span class="i-name">icon-cog</span><span class="i-code">0xe807</span></div> </div> <div class="row"> - <div title="Code: 0xe808" class="the-icons span3"><i class="demo-icon icon-logout"></i> <span class="i-name">icon-logout</span><span class="i-code">0xe808</span></div> - <div title="Code: 0xe832" class="the-icons span3"><i class="demo-icon icon-spin3 animate-spin"></i> <span class="i-name">icon-spin3</span><span class="i-code">0xe832</span></div> - <div title="Code: 0xe834" class="the-icons span3"><i class="demo-icon icon-spin4 animate-spin"></i> <span class="i-name">icon-spin4</span><span class="i-code">0xe834</span></div> - <div title="Code: 0xf0c9" class="the-icons span3"><i class="demo-icon icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xf0c9</span></div> + <div class="the-icons span3" title="Code: 0xe808"><i class="demo-icon icon-logout"></i> <span class="i-name">icon-logout</span><span class="i-code">0xe808</span></div> + <div class="the-icons span3" title="Code: 0xe809"><i class="demo-icon icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe809</span></div> + <div class="the-icons span3" title="Code: 0xe80a"><i class="demo-icon icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe80a</span></div> + <div class="the-icons span3" title="Code: 0xe80b"><i class="demo-icon icon-picture"></i> <span class="i-name">icon-picture</span><span class="i-code">0xe80b</span></div> </div> <div class="row"> - <div title="Code: 0xf112" class="the-icons span3"><i class="demo-icon icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xf112</span></div> - <div title="Code: 0xf1e5" class="the-icons span3"><i class="demo-icon icon-binoculars"></i> <span class="i-name">icon-binoculars</span><span class="i-code">0xf1e5</span></div> - <div title="Code: 0xf234" class="the-icons span3"><i class="demo-icon icon-user-plus"></i> <span class="i-name">icon-user-plus</span><span class="i-code">0xf234</span></div> + <div class="the-icons span3" title="Code: 0xe80c"><i class="demo-icon icon-video"></i> <span class="i-name">icon-video</span><span class="i-code">0xe80c</span></div> + <div class="the-icons span3" title="Code: 0xe80d"><i class="demo-icon icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe80d</span></div> + <div class="the-icons span3" title="Code: 0xe80e"><i class="demo-icon icon-left-open"></i> <span class="i-name">icon-left-open</span><span class="i-code">0xe80e</span></div> + <div class="the-icons span3" title="Code: 0xe80f"><i class="demo-icon icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe80f</span></div> + </div> + <div class="row"> + <div class="the-icons span3" title="Code: 0xe810"><i class="demo-icon icon-bell"></i> <span class="i-name">icon-bell</span><span class="i-code">0xe810</span></div> + <div class="the-icons span3" title="Code: 0xe832"><i class="demo-icon icon-spin3 animate-spin"></i> <span class="i-name">icon-spin3</span><span class="i-code">0xe832</span></div> + <div class="the-icons span3" title="Code: 0xe834"><i class="demo-icon icon-spin4 animate-spin"></i> <span class="i-name">icon-spin4</span><span class="i-code">0xe834</span></div> + <div class="the-icons span3" title="Code: 0xf08e"><i class="demo-icon icon-link-ext"></i> <span class="i-name">icon-link-ext</span><span class="i-code">0xf08e</span></div> + </div> + <div class="row"> + <div class="the-icons span3" title="Code: 0xf0c9"><i class="demo-icon icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xf0c9</span></div> + <div class="the-icons span3" title="Code: 0xf0e5"><i class="demo-icon icon-comment-empty"></i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xf0e5</span></div> + <div class="the-icons span3" title="Code: 0xf112"><i class="demo-icon icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xf112</span></div> + <div class="the-icons span3" title="Code: 0xf1e5"><i class="demo-icon icon-binoculars"></i> <span class="i-name">icon-binoculars</span><span class="i-code">0xf1e5</span></div> + </div> + <div class="row"> + <div class="the-icons span3" title="Code: 0xf234"><i class="demo-icon icon-user-plus"></i> <span class="i-name">icon-user-plus</span><span class="i-code">0xf234</span></div> </div> </div> <div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div> diff --git a/static/font/font/fontello.eot b/static/font/font/fontello.eot Binary files differindex 52fbefa9..d15e8391 100644 --- a/static/font/font/fontello.eot +++ b/static/font/font/fontello.eot diff --git a/static/font/font/fontello.svg b/static/font/font/fontello.svg index 43e9bee4..be07ddae 100644 --- a/static/font/font/fontello.svg +++ b/static/font/font/fontello.svg @@ -1,7 +1,7 @@ <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg"> -<metadata>Copyright (C) 2017 by original authors @ fontello.com</metadata> +<metadata>Copyright (C) 2018 by original authors @ fontello.com</metadata> <defs> <font id="fontello" horiz-adv-x="1000" > <font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" /> @@ -24,12 +24,32 @@ <glyph glyph-name="logout" unicode="" d="M357 46q0-2 1-11t0-14-2-14-5-11-12-3h-178q-67 0-114 47t-47 114v392q0 67 47 114t114 47h178q8 0 13-5t5-13q0-2 1-11t0-15-2-13-5-11-12-3h-178q-37 0-63-26t-27-64v-392q0-37 27-63t63-27h174t6 0 7-2 4-3 4-5 1-8z m518 304q0-14-11-25l-303-304q-11-10-25-10t-25 10-11 25v161h-250q-14 0-25 11t-11 25v214q0 15 11 25t25 11h250v161q0 14 11 25t25 10 25-10l303-304q11-10 11-25z" horiz-adv-x="928.6" /> +<glyph glyph-name="down-open" unicode="" d="M939 399l-414-413q-10-11-25-11t-25 11l-414 413q-11 11-11 26t11 25l93 92q10 11 25 11t25-11l296-296 296 296q11 11 25 11t26-11l92-92q11-11 11-25t-11-26z" horiz-adv-x="1000" /> + +<glyph glyph-name="attach" unicode="" d="M244-140q-102 0-170 72-72 70-74 166t84 190l496 496q80 80 174 54 44-12 79-47t47-79q26-96-54-176l-474-474q-40-40-88-46-48-4-80 28-30 24-27 74t47 92l332 334q24 26 50 0t0-50l-332-332q-44-44-20-70 12-8 24-6 24 4 46 26l474 474q50 50 34 108-16 60-76 76-54 14-108-36l-494-494q-66-76-64-143t52-117q50-48 117-50t141 62l496 494q24 24 50 0 26-22 0-48l-496-496q-82-82-186-82z" horiz-adv-x="939" /> + +<glyph glyph-name="picture" unicode="" d="M357 529q0-45-31-76t-76-32-76 32-31 76 31 76 76 31 76-31 31-76z m572-215v-250h-786v107l178 179 90-89 285 285z m53 393h-893q-7 0-12-5t-6-13v-678q0-7 6-13t12-5h893q7 0 13 5t5 13v678q0 8-5 13t-13 5z m89-18v-678q0-37-26-63t-63-27h-893q-36 0-63 27t-26 63v678q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" /> + +<glyph glyph-name="video" unicode="" d="M214-43v72q0 14-10 25t-25 10h-72q-14 0-25-10t-11-25v-72q0-14 11-25t25-11h72q14 0 25 11t10 25z m0 214v72q0 14-10 25t-25 11h-72q-14 0-25-11t-11-25v-72q0-14 11-25t25-10h72q14 0 25 10t10 25z m0 215v71q0 15-10 25t-25 11h-72q-14 0-25-11t-11-25v-71q0-15 11-25t25-11h72q14 0 25 11t10 25z m572-429v286q0 14-11 25t-25 11h-429q-14 0-25-11t-10-25v-286q0-14 10-25t25-11h429q15 0 25 11t11 25z m-572 643v71q0 15-10 26t-25 10h-72q-14 0-25-10t-11-26v-71q0-14 11-25t25-11h72q14 0 25 11t10 25z m786-643v72q0 14-11 25t-25 10h-71q-15 0-25-10t-11-25v-72q0-14 11-25t25-11h71q15 0 25 11t11 25z m-214 429v285q0 15-11 26t-25 10h-429q-14 0-25-10t-10-26v-285q0-15 10-25t25-11h429q15 0 25 11t11 25z m214-215v72q0 14-11 25t-25 11h-71q-15 0-25-11t-11-25v-72q0-14 11-25t25-10h71q15 0 25 10t11 25z m0 215v71q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-71q0-15 11-25t25-11h71q15 0 25 11t11 25z m0 214v71q0 15-11 26t-25 10h-71q-15 0-25-10t-11-26v-71q0-14 11-25t25-11h71q15 0 25 11t11 25z m71 89v-750q0-37-26-63t-63-26h-893q-36 0-63 26t-26 63v750q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" /> + +<glyph glyph-name="right-open" unicode="" d="M618 361l-414-415q-11-10-25-10t-25 10l-93 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l93 93q10 11 25 11t25-11l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" /> + +<glyph glyph-name="left-open" unicode="" d="M654 682l-297-296 297-297q10-10 10-25t-10-25l-93-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 11 25 11t25-11l93-93q10-10 10-25t-10-25z" horiz-adv-x="714.3" /> + +<glyph glyph-name="up-open" unicode="" d="M939 107l-92-92q-11-10-26-10t-25 10l-296 297-296-297q-11-10-25-10t-25 10l-93 92q-11 11-11 26t11 25l414 414q11 10 25 10t25-10l414-414q11-11 11-25t-11-26z" horiz-adv-x="1000" /> + +<glyph glyph-name="bell" unicode="" d="M509-96q0 8-9 8-33 0-57 24t-23 57q0 9-9 9t-9-9q0-41 29-70t69-28q9 0 9 9z m-372 160h726q-149 168-149 465 0 28-13 58t-39 58-67 45-95 17-95-17-67-45-39-58-13-58q0-297-149-465z m827 0q0-29-21-50t-50-21h-250q0-59-42-101t-101-42-101 42-42 101h-250q-29 0-50 21t-21 50q28 24 51 49t47 67 42 89 27 115 11 145q0 84 66 157t171 89q-5 10-5 21 0 23 16 38t38 16 38-16 16-38q0-11-5-21 106-16 171-89t66-157q0-78 11-145t28-115 41-89 48-67 50-49z" horiz-adv-x="1000" /> + <glyph glyph-name="spin3" unicode="" d="M494 850c-266 0-483-210-494-472-1-19 13-20 13-20l84 0c16 0 19 10 19 18 10 199 176 358 378 358 107 0 205-45 273-118l-58-57c-11-12-11-27 5-31l247-50c21-5 46 11 37 44l-58 227c-2 9-16 22-29 13l-65-60c-89 91-214 148-352 148z m409-508c-16 0-19-10-19-18-10-199-176-358-377-358-108 0-205 45-274 118l59 57c10 12 10 27-5 31l-248 50c-21 5-46-11-37-44l58-227c2-9 16-22 30-13l64 60c89-91 214-148 353-148 265 0 482 210 493 473 1 18-13 19-13 19l-84 0z" horiz-adv-x="1000" /> <glyph glyph-name="spin4" unicode="" d="M498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" /> +<glyph glyph-name="link-ext" unicode="" d="M786 332v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13z m214 482v-285q0-15-11-25t-25-11-25 11l-98 98-364-364q-5-6-13-6t-12 6l-64 64q-6 5-6 12t6 13l364 364-98 98q-11 11-11 25t11 25 25 11h285q15 0 25-11t11-25z" horiz-adv-x="1000" /> + <glyph glyph-name="menu" unicode="" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-14-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" /> +<glyph glyph-name="comment-empty" unicode="" d="M500 636q-114 0-213-39t-157-105-59-142q0-62 40-119t113-98l48-28-15-53q-13-51-39-97 85 36 154 96l24 21 32-3q38-5 72-5 114 0 213 39t157 105 59 142-59 142-157 105-213 39z m500-286q0-97-67-179t-182-130-251-48q-39 0-81 4-110-97-257-135-27-8-63-12h-3q-8 0-15 6t-9 15v1q-2 2 0 6t1 6 2 5l4 5t4 5 4 5q4 5 17 19t20 22 17 22 18 28 15 33 15 42q-88 50-138 123t-51 157q0 97 67 179t182 130 251 48 251-48 182-130 67-179z" horiz-adv-x="1000" /> + <glyph glyph-name="reply" unicode="" d="M1000 225q0-93-71-252-1-4-6-13t-7-17-7-12q-7-10-16-10-8 0-13 6t-5 14q0 5 1 15t2 13q3 38 3 69 0 56-10 101t-27 77-45 56-59 39-74 24-86 12-98 3h-125v-143q0-14-10-25t-26-11-25 11l-285 286q-11 10-11 25t11 25l285 286q11 10 25 10t26-10 10-25v-143h125q398 0 488-225 30-75 30-186z" horiz-adv-x="1000" /> <glyph glyph-name="binoculars" unicode="" d="M393 671v-428q0-15-11-25t-25-11v-321q0-15-10-25t-26-11h-285q-15 0-25 11t-11 25v285l139 488q4 12 17 12h237z m178 0v-392h-142v392h142z m429-500v-285q0-15-11-25t-25-11h-285q-15 0-25 11t-11 25v321q-15 0-25 11t-11 25v428h237q13 0 17-12z m-589 661v-125h-197v125q0 8 5 13t13 5h161q8 0 13-5t5-13z m375 0v-125h-197v125q0 8 5 13t13 5h161q8 0 13-5t5-13z" horiz-adv-x="1000" /> diff --git a/static/font/font/fontello.ttf b/static/font/font/fontello.ttf Binary files differindex 2548731d..3b08e96b 100644 --- a/static/font/font/fontello.ttf +++ b/static/font/font/fontello.ttf diff --git a/static/font/font/fontello.woff b/static/font/font/fontello.woff Binary files differindex fbbf748f..167d132d 100644 --- a/static/font/font/fontello.woff +++ b/static/font/font/fontello.woff diff --git a/static/font/font/fontello.woff2 b/static/font/font/fontello.woff2 Binary files differindex 89c49787..224e9b97 100644 --- a/static/font/font/fontello.woff2 +++ b/static/font/font/fontello.woff2 diff --git a/static/styles.json b/static/styles.json index 92715565..7116ef20 100644 --- a/static/styles.json +++ b/static/styles.json @@ -1,9 +1,9 @@ { - "pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070" ], - "pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f" ], - "classic-dark": [ "Classic Dark", "#161c20", "#282e32", "#b9b9b9", "#baaa9c" ], - "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8"], - "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60" ], - "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672" ], - "mammal": [ "Mammal", "#272c37", "#444b5d", "#f8f8f8", "#9bacc8" ] + "pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], + "pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], + "classic-dark": [ "Classic Dark", "#161c20", "#282e32", "#b9b9b9", "#baaa9c", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], + "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"], + "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ], + "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ], + "mammal": [ "Mammal", "#272c37", "#444b5d", "#f8f8f8", "#9bacc8", "#7f3142", "#2bd850", "#2b90d9", "#ca8f04" ] } |
