Page MenuHomePhorge

No OneTemporary

Size
88 KB
Referenced Files
None
Subscribers
None
diff --git a/src/App.scss b/src/App.scss
index 6e0378db21..ec80626bc3 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -1,347 +1,363 @@
@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;
}
i {
user-select: none;
}
h4 {
- margin: 0;
+ margin: 0;
}
#content {
box-sizing: border-box;
padding-top: 60px;
margin: auto;
min-height: 100vh;
max-width: 980px;
background-color: rgba(0,0,0,0.15);
align-content: flex-start;
}
.text-center {
- text-align: center;
+ text-align: center;
}
body {
- font-family: sans-serif;
- font-size: 14px;
- margin: 0;
- color: var(--fg);
+ font-family: sans-serif;
+ font-size: 14px;
+ margin: 0;
+ color: $fallback--fg;
+ color: var(--fg, $fallback--fg);
}
a {
- text-decoration: none;
- color: var(--link);
+ text-decoration: none;
+ color: $fallback--link;
+ color: var(--link, $fallback--link);
}
button{
- user-select: none;
- color: var(--faint);
- background-color: var(--btn);
- 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);
- }
+ user-select: none;
+ color: $fallback--faint;
+ color: var(--faint, $fallback--faint);
+ background-color: $fallback--btn;
+ background-color: var(--btn, $fallback--btn);
+ 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;
- &:disabled {
- cursor: not-allowed;
- opacity: 0.5;
- }
+ &:hover {
+ box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3);
+ }
- &.pressed {
- color: var(--faint);
- background-color: var(--bg)
- }
+ &: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)
+ }
}
input, textarea, select {
border: none;
border-radius: 5px;
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: var(--lightBg);
- color: var(--lightFg);
+ 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: 5px;
+ padding: 8px 7px 4px;
// TODO: Restyle <select> in a decent way. Needs different markup
// -webkit-appearance:none;
// -moz-appearance:none;
// appearance:none;
&[type=radio],
&[type=checkbox] {
display: none;
&:checked + label::before {
- color: var(--fg);
+ 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: 2px;
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: var(--btn);
+ background-color: $fallback--btn;
+ background-color: var(--btn, $fallback--btn);
vertical-align: baseline;
text-align: center;
line-height: 1.1em;
font-size: 1.1em;
box-sizing: border-box;
color: transparent;
overflow: hidden;
}
}
}
.icon-cancel,
.icon-reply,
.icon-retweet,
.icon-star-empty,
.icon-eye-off,
.icon-binoculars,
.icon-plus-squared,
.icon-spin4 {
- color: var(--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: 25px;
- height: 25px;
- overflow: hidden;
+ flex: 1;
+ line-height: 25px;
+ height: 25px;
+ 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;
-
- .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;
- }
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: contain;
+ }
}
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;
- background-color: var(--bg);
+ background-color: $fallback--bg;
+ background-color: var(--bg, $fallback--bg);
- border-radius: 10px;
- box-shadow: 1px 1px 4px rgba(0,0,0,.6);
- overflow: hidden;
+ border-radius: 10px;
+ border-radius: $fallback--panelRadius;
+ border-radius: var(--panelRadius, 10px);
+ box-shadow: 1px 1px 4px rgba(0,0,0,.6);
+ overflow: hidden;
}
.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;
- background-color: var(--btn);
+ border-radius: 10px 10px 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-footer {
- border-radius: 0 0 10px 10px;
+ border-radius: 0 0 10px 10px;
}
.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;
- background-color: var(--bg);
- color: var(--faint);
- 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 {
transition: opacity .2s
}
.fade-enter, .fade-leave-active {
opacity: 0
}
.main {
- flex-basis: 60%;
- flex-grow: 1;
- flex-shrink: 1;
+ flex-basis: 60%;
+ flex-grow: 1;
+ flex-shrink: 1;
}
.sidebar-bounds {
flex: 0;
flex-basis: 35%;
}
.sidebar-flexer {
flex: 1;
flex-basis: 345px;
width: 365px;
}
.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) {
body {
overflow-y: scroll;
}
.sidebar-bounds {
overflow: hidden;
max-height: 100vh;
width: 345px;
position: fixed;
margin-top: -10px;
.sidebar-scroller {
height: 96vh;
width: 365px;
padding-top: 10px;
padding-right: 50px;
overflow-x: hidden;
overflow-y: scroll;
}
.sidebar {
width: 345px;
}
}
.sidebar-flexer {
max-height: 96vh;
flex-shrink: 0;
flex-grow: 0;
}
}
@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/_variables.scss b/src/_variables.scss
index fa7eaec1bb..eccc0aabf0 100644
--- a/src/_variables.scss
+++ b/src/_variables.scss
@@ -1,6 +1,20 @@
$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--cYellow: yellow;
+
+$fallback--panelRadius: 10px;
diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue
index eeb6e6b8aa..e3b1e4d41b 100644
--- a/src/components/attachment/attachment.vue
+++ b/src/components/attachment/attachment.vue
@@ -1,140 +1,143 @@
<template>
<div class="attachment" :class="{[type]: true, loading}" v-show="!isEmpty">
<a class="image-attachment" v-if="hidden" @click.prevent="toggleHidden()">
<img :key="nsfwImage" :src="nsfwImage"/>
</a>
<div class="hider" v-if="nsfw && hideNsfwLocal && !hidden">
<a href="#" @click.prevent="toggleHidden()">Hide</a>
</div>
<a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank">
<StillImage referrerpolicy="no-referrer" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/>
</a>
<video v-if="type === 'video' && !hidden" :src="attachment.url" controls loop></video>
<audio v-if="type === 'audio'" :src="attachment.url" controls></audio>
<div @click.prevent="linkClicked" v-if="type === 'html' && attachment.oembed" class="oembed">
<div v-if="attachment.thumb_url" class="image">
<img :src="attachment.thumb_url"/>
</div>
<div class="text">
<h1><a :href="attachment.url">{{attachment.oembed.title}}</a></h1>
<div v-html="attachment.oembed.oembedHTML"></div>
</div>
</div>
</div>
</template>
<script src="./attachment.js"></script>
<style lang="scss">
+@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%;
}
.attachment {
flex: 1 0 30%;
margin: 0.5em 0.7em 0.6em 0.0em;
align-self: flex-start;
- border-color: var(--border);
+ border-color: $fallback--border;
+ border-color: var(--border, $fallback--border);
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;
}
}
}
}
</style>
diff --git a/src/components/delete_button/delete_button.vue b/src/components/delete_button/delete_button.vue
index 66727e7ccc..9966d85e99 100644
--- a/src/components/delete_button/delete_button.vue
+++ b/src/components/delete_button/delete_button.vue
@@ -1,21 +1,21 @@
<template>
<div v-if="canDelete">
<a href="#" v-on:click.prevent="deleteStatus()">
<i class='icon-cancel delete-status'></i>
</a>
</div>
</template>
<script src="./delete_button.js" ></script>
<style lang='scss'>
@import '../../_variables.scss';
.icon-cancel,.delete-status {
cursor: pointer;
&:hover {
- color: $red_;
- color: var(--red);
+ 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 a6e4c46bbe..f25c589a46 100644
--- a/src/components/favorite_button/favorite_button.vue
+++ b/src/components/favorite_button/favorite_button.vue
@@ -1,28 +1,32 @@
<template>
<div v-if="loggedIn">
<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'/>
<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;
- color: var(--cOrange);
- }
- }
- .favorite-button.icon-star {
- color: orange;
- color: var(--cOrange);
- }
+<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/login_form/login_form.vue b/src/components/login_form/login_form.vue
index 553858a389..82000d6b06 100644
--- a/src/components/login_form/login_form.vue
+++ b/src/components/login_form/login_form.vue
@@ -1,68 +1,69 @@
<template>
<div class="login panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
{{$t('login.login')}}
</div>
<div class="panel-body">
<form v-on:submit.prevent='submit(user)' class='login-form'>
<div class='form-group'>
<label for='username'>{{$t('login.username')}}</label>
<input :disabled="loggingIn" v-model='user.username' class='form-control' id='username' placeholder='e.g. lain'>
</div>
<div class='form-group'>
<label for='password'>{{$t('login.password')}}</label>
<input :disabled="loggingIn" v-model='user.password' class='form-control' id='password' type='password'>
</div>
<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'>{{$t('login.login')}}</button>
</div>
</div>
<div v-if="authError" class='form-group'>
<div class='error'>{{authError}}</div>
</div>
</form>
</div>
</div>
</template>
<script src="./login_form.js" ></script>
<style lang="scss">
+@import '../../_variables.scss';
.login-form {
input {
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);
- background-color: var(--cRed);
+ background-color: $fallback--cRed;
min-height: 28px;
line-height: 28px;
}
.register {
flex: 1 1;
}
.login-bottom {
margin-top: 1.0em;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
}
</style>
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index 2a92586bca..43b4c3dcb2 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -1,73 +1,83 @@
<template>
<div class="nav-panel">
<div class="panel panel-default">
<ul>
<li v-if='currentUser'>
<router-link to='/main/friends'>
{{ $t("nav.timeline") }}
</router-link>
</li>
<li v-if='currentUser'>
<router-link :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
{{ $t("nav.mentions") }}
</router-link>
</li>
<li>
<router-link to='/main/public'>
{{ $t("nav.public_tl") }}
</router-link>
</li>
<li>
<router-link to='/main/all'>
{{ $t("nav.twkn") }}
</router-link>
</li>
</ul>
</div>
</div>
</template>
<script src="./nav_panel.js" ></script>
<style lang="scss">
+@import '../../_variables.scss';
+
.nav-panel ul {
list-style: none;
margin: 0;
padding: 0;
}
.nav-panel li {
border-bottom: 1px solid;
- border-color: var(--border);
- background-color: var(--bg);
+ border-color: $fallback--border;
+ border-color: var(--border, $fallback--border);
+ background-color: $fallback--bg;
+ background-color: var(--bg, $fallback--bg);
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 li:last-child {
border: none;
}
.nav-panel a {
display: block;
padding: 0.8em 0.85em;
+
&:hover {
- background-color: var(--lightBg);
+ background-color: $fallback--lightBg;
+ background-color: var(--lightBg, $fallback--lightBg);
}
+
&.router-link-active {
font-weight: bolder;
- background-color: var(--lightBg);
+ background-color: $fallback--lightBg;
+ background-color: var(--lightBg, $fallback--lightBg);
+
&:hover {
text-decoration: underline;
}
}
}
-
</style>
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 58d82a0961..e55c6e24b6 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -1,53 +1,48 @@
import Status from '../status/status.vue'
import StillImage from '../still-image/still-image.vue'
import { sortBy, take, filter } from 'lodash'
const Notifications = {
data () {
return {
visibleNotificationCount: 10
}
},
computed: {
notifications () {
return this.$store.state.statuses.notifications
},
unseenNotifications () {
return filter(this.notifications, ({seen}) => !seen)
},
visibleNotifications () {
// Don't know why, but sortBy([seen, -action.id]) doesn't work.
let sortedNotifications = sortBy(this.notifications, ({action}) => -action.id)
sortedNotifications = sortBy(sortedNotifications, 'seen')
return take(sortedNotifications, this.visibleNotificationCount)
},
unseenCount () {
return this.unseenNotifications.length
- },
- hiderStyle () {
- return {
- background: `linear-gradient(to bottom, rgba(0, 0, 0, 0), ${this.$store.state.config.colors.bg} 80%)`
- }
}
},
components: {
Status, StillImage
},
watch: {
unseenCount (count) {
if (count > 0) {
this.$store.dispatch('setPageTitle', `(${count})`)
} else {
this.$store.dispatch('setPageTitle', '')
}
}
},
methods: {
markAsSeen () {
this.$store.commit('markNotificationsAsSeen', this.visibleNotifications)
}
}
}
export default Notifications
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index a739d52e60..5af2454e29 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -1,157 +1,170 @@
@import '../../_variables.scss';
.notifications {
// a bit of a hack to allow scrolling below notifications
padding-bottom: 15em;
.panel {
- background: var(--bg)
+ background: $fallback--bg;
+ background: var(--bg, $fallback--bg)
}
.panel-body {
- border-color: var(--border)
+ 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: var(--btn);
- color: var(--faint);
+ background: $fallback--btn;
+ background: var(--btn, $fallback--btn);
+ color: $fallback--faint;
+ color: var(--faint, $fallback--faint);
.read-button {
position: absolute;
right: 0.7em;
height: 1.8em;
line-height: 100%;
- background-color: var(--btn);
- color: var(--faint);
+ background-color: $fallback--btn;
+ background-color: var(--btn, $fallback--btn);
+ color: $fallback--faint;
+ color: var(--faint, $fallback--faint);
}
}
.unseen-count {
display: inline-block;
- background-color: var(--cRed);
+ 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;
margin: 0 0.2em 0 -0.4em;
color: white;
font-size: 0.9em;
text-align: center;
line-height: 1.3em;
padding: 1px;
}
.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;
+ .notification-gradient {
+ 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%)
+ }
.text {
min-width: 0px;
word-wrap: break-word;
line-height:18px;
position: relative;
overflow: hidden;
.icon-retweet.lit {
- color: $green_;
- color: var(--cGreen);
+ color: $fallback--cGreen;
+ color: var(--cGreen, $fallback--cGreen);
}
.icon-user-plus.lit {
- color: $blue_;
- color: var(--cBlue);
+ color: $fallback--cBlue;
+ color: var(--cBlue, $fallback--cBlue);
}
.icon-reply.lit {
- color: $blue_;
- color: var(--cBlue);
+ color: $fallback--cBlue;
+ color: var(--cBlue, $fallback--cBlue);
}
.icon-star.lit {
color: orange;
- color: var(--cOrange);
+ 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;
}
}
padding: 0.3em 0.8em 0.5em;
p {
margin: 0;
margin-top: 0;
margin-bottom: 0.3em;
}
}
.avatar {
margin-top: 0.3em;
width: 32px;
height: 32px;
border-radius: 50%;
overflow: hidden;
line-height: 0;
&.animated::before {
display: none;
}
}
&:hover .animated.avatar {
canvas {
display: none;
}
img {
visibility: visible;
}
}
&:last-child {
border-bottom: none;
border-radius: 0 0 10px 10px;
}
}
.notification-content {
max-height: 12em;
overflow-y: hidden;
//text-overflow: ellipsis;
img {
object-fit: contain;
}
}
.notification-gradient {
position: absolute;
width: 100%;
height: 4em;
margin-top:8em;
}
.unseen {
- border-left: 4px solid var(--cRed);
+ border-left: 4px solid $fallback--cRed;
+ border-left: 4px solid var(--cRed, $fallback--cRed);
padding-left: 6px;
}
}
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 77e2942640..17bae71e0f 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -1,60 +1,60 @@
<template>
<div class="notifications">
<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="read-button">{{$t('notifications.read')}}</button>
</div>
<div class="panel-body">
<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">
<StillImage 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-gradient"></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-gradient"></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>
</div>
</div>
</div>
</template>
<script src="./notifications.js"></script>
<style lang="scss" src="./notifications.scss"></style>
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index 3f268ff513..d57418fbf3 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -1,199 +1,209 @@
<template>
<div class="post-status-form">
<form @submit.prevent="postStatus(newStatus)">
<div class="form-group" >
<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">
<span v-if="candidate.img"><img :src="candidate.img"></span>
<span v-else>{{candidate.utf}}</span>
<span>{{candidate.screen_name}}<small>{{candidate.name}}</small></span>
</div>
<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>{{candidate.name}}</small></span>
</div>
</div>
</div>
</div>
<div class='form-bottom'>
<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">{{ charactersLeft }}</p>
<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">
Error: {{ error }}
<i class="icon-cancel" @click="clearError"></i>
</div>
<div class="attachments">
<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>
<audio v-if="type(file) === 'audio'" :src="file.image" controls></audio>
<a v-if="type(file) === 'unknown'" :href="file.image">{{file.url}}</a>
</div>
</div>
</form>
</div>
</template>
<script src="./post_status_form.js"></script>
<style lang="scss">
+@import '../../_variables.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);
- background-color: var(--cRed);
+ background-color: $fallback--cRed;
+ background-color: var(--cRed, $fallback--cRed);
padding: 0.25em;
margin: 0.35em;
display: flex;
}
.attachments {
padding: 0 0.5em;
.attachment {
position: relative;
- border: var(--border);
+ border: $fallback--border;
+ border: 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: 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-radius: 5px;
line-height:16px;
- padding: 5px;
resize: none;
overflow: hidden;
+ transition: min-height 200ms;
+ min-height: 1px;
}
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%;
- background: var(--btn);
- color: var(--lightFg);
+ 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: 2px;
object-fit: contain;
}
+
span {
line-height: 24px;
margin: 0 0.1em 0 0.2em;
}
+
small {
margin-left: .5em;
- color: var(--faint);
+ color: $fallback--faint;
+ color: var(--faint, $fallback--faint);
}
}
}
</style>
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index 786a59e3e2..0966645ded 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -1,132 +1,128 @@
<template>
<div class="settings panel panel-default">
<div class="panel-heading">
{{$t('registration.registration')}}
</div>
<div class="panel-body">
<form v-on:submit.prevent='submit(user)' class='registration-form'>
<div class='container'>
<div class='text-fields'>
<div class='form-group'>
<label for='username'>{{$t('login.username')}}</label>
<input :disabled="registering" v-model='user.username' class='form-control' id='username' placeholder='e.g. lain'>
</div>
<div class='form-group'>
<label for='fullname'>{{$t('registration.fullname')}}</label>
<input :disabled="registering" v-model='user.fullname' class='form-control' id='fullname' placeholder='e.g. Lain Iwakura'>
</div>
<div class='form-group'>
<label for='email'>{{$t('registration.email')}}</label>
<input :disabled="registering" v-model='user.email' class='form-control' id='email' type="email">
</div>
<div class='form-group'>
<label for='bio'>{{$t('registration.bio')}}</label>
<input :disabled="registering" v-model='user.bio' class='form-control' id='bio'>
</div>
<div class='form-group'>
<label for='password'>{{$t('login.password')}}</label>
<input :disabled="registering" v-model='user.password' class='form-control' id='password' type='password'>
</div>
<div class='form-group'>
<label for='password_confirmation'>{{$t('registration.password_confirm')}}</label>
<input :disabled="registering" v-model='user.confirm' class='form-control' id='password_confirmation' type='password'>
</div>
<!--
<div class='form-group'>
<label for='captcha'>Captcha</label>
<img src='/qvittersimplesecurity/captcha.jpg' alt='captcha' class='captcha'>
<input :disabled="registering" v-model='user.captcha' placeholder='Enter captcha' type='test' class='form-control' id='captcha'>
</div>
-->
<div class='form-group'>
<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'>{{error}}</div>
</div>
</form>
</div>
</div>
</template>
<script src="./registration.js"></script>
<style lang="scss">
+@import '../../_variables.scss';
.registration-form {
display: flex;
flex-direction: column;
margin: 0.6em;
.container {
display: flex;
flex-direction: row;
//margin-bottom: 1em;
}
.terms-of-service {
flex: 0 1 50%;
margin: 0.8em;
}
.text-fields {
margin-top: 0.6em;
flex: 1 0;
display: flex;
flex-direction: column;
}
.form-group {
display: flex;
flex-direction: column;
padding: 0.3em 0.0em 0.3em;
line-height:24px;
}
form textarea {
- border: solid;
- border-width: 1px;
- border-color: silver;
border-radius: 5px;
line-height:16px;
- padding: 5px;
resize: vertical;
}
input {
border-radius: 5px;
- padding: 0.1em 0.2em 0.2em 0.2em;
}
.captcha {
max-width: 350px;
margin-bottom: 0.4em;
}
.btn {
//align-self: flex-start;
//width: 10em;
margin-top: 0.6em;
height: 28px;
- }
+ }
- .error {
- border-radius: 5px;
- text-align: center;
- margin: 0.5em 0.6em 0;
- background-color: rgba(255, 48, 16, 0.65);
- background-color: var(--cRed);
- min-height: 28px;
- line-height: 28px;
- }
+ .error {
+ border-radius: 5px;
+ text-align: center;
+ margin: 0.5em 0.6em 0;
+ background-color: $fallback--cRed;
+ background-color: var(--cRed, $fallback--cRed);
+ min-height: 28px;
+ line-height: 28px;
+ }
}
@media all and (max-width: 959px) {
- .registration-form .container {
+ .registration-form .container {
flex-direction: column-reverse;
}
}
</style>
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index 7c75f3bc7c..a21942c3f6 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -1,28 +1,28 @@
<template>
<div v-if="loggedIn">
<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'></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_;
- color: var(--cGreen);
- }
- }
- .icon-retweet.retweeted {
- color: $green_;
- color: var(--cGreen);
- }
+<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.vue b/src/components/settings/settings.vue
index b842c9e982..98f70f7b57 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -1,85 +1,86 @@
<template>
<div class="settings panel panel-default">
<div class="panel-heading">
{{$t('settings.settings')}}
</div>
<div class="panel-body">
<div class="setting-item">
<h2>{{$t('settings.theme')}}</h2>
<style-switcher></style-switcher>
</div>
<div class="setting-item">
<h2>{{$t('settings.filtering')}}</h2>
<p>{{$t('settings.filtering_explanation')}}</p>
<textarea id="muteWords" v-model="muteWordsString"></textarea>
</div>
<div class="setting-item">
<h2>{{$t('settings.attachments')}}</h2>
<ul class="setting-list">
<li>
<input type="checkbox" id="hideAttachments" v-model="hideAttachmentsLocal">
<label for="hideAttachments">{{$t('settings.hide_attachments_in_tl')}}</label>
</li>
<li>
<input type="checkbox" id="hideAttachmentsInConv" v-model="hideAttachmentsInConvLocal">
<label for="hideAttachmentsInConv">{{$t('settings.hide_attachments_in_convo')}}</label>
</li>
<li>
<input type="checkbox" id="hideNsfw" v-model="hideNsfwLocal">
<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>
</li>
<li>
<input type="checkbox" id="streaming" v-model="streamingLocal">
<label for="streaming">{{$t('settings.streaming')}}</label>
</li>
<li>
<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>
</div>
</template>
<script src="./settings.js">
</script>
<style lang="scss">
.setting-item {
margin: 1em 1em 1.4em;
+
textarea {
width: 100%;
height: 100px;
}
.old-avatar {
width: 128px;
border-radius: 5px;
}
.new-avatar {
object-fit: cover;
width: 128px;
height: 128px;
border-radius: 5px;
}
.btn {
margin-top: 1em;
min-height: 28px;
width: 10em;
}
}
.setting-list {
list-style-type: none;
}
</style>
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 8410aeba4b..80f6a3157e 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -1,462 +1,473 @@
<template>
<div class="status-el" 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="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 status-fadein" v-else-if="!status.deleted" v-bind:class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inConversation }]" >
<template v-if="muted">
<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="icon-eye-off"></i></a>
</div>
</template>
<template v-if="!muted">
<div v-if="retweet" class="media container retweet-info">
<div class="media-left">
<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>
</div>
</div>
<div class="media status container">
<div class="media-left">
<a :href="status.user.statusnet_profile_url">
<StillImage @click.native.prevent="toggleUserExpanded" :class="{retweeted: retweet}" class='avatar' :src="status.user.profile_image_url_original"/>
<StillImage v-if="retweet" class='avatar avatar-retweeter' :src="statusoid.user.profile_image_url_original"/>
</a>
</div>
<div class="media-body">
<div class="usercard" v-if="userExpanded">
<user-card-content :user="status.user" :switcher="false"></user-card-content>
</div>
<div class="user-content">
<div class="media-heading">
<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"> &gt;
<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}}&nbsp;</a>
</small>
</h4>
</div>
<div class="heading-icons">
<a href="#" @click.prevent="toggleMute" v-if="unmuted"><i class="icon-eye-off"></i></a>
<a :href="status.external_url" target="_blank" v-if="!status.is_local" class="source_url"><i class="icon-binoculars"></i></a>
<template v-if="expandable">
<a href="#" @click.prevent="toggleExpanded" class="expand"><i class="icon-plus-squared"></i></a>
</template>
</div>
</div>
<div class="status-preview" v-if="showPreview && preview">
<StillImage 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>
<div class="status-preview status-preview-loading" v-else-if="showPreview">
<i class="icon-spin4 animate-spin"></i>
</div>
<div @click.prevent="linkClicked" class="status-content" v-html="status.statusnet_html"></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>
<div class='status-actions'>
<div v-if="loggedIn">
<a href="#" v-on:click.prevent="toggleReplying">
<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>
</div>
</div>
</div>
<div class="status 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>
</template>
</div>
</template>
<script src="./status.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
status-text-container {
display: block;
}
.status-preview {
position: absolute;
max-width: 34em;
padding: 0.5em;
display: flex;
- background-color: var(--bg);
- border-color: var(--border);
+ 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: 4px;
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
margin-top: 0.5em;
margin-left: 1em;
z-index: 50;
.avatar {
flex-shrink: 0;
width: 32px;
height: 32px;
border-radius: 50%;
}
.text {
h4 {
margin-bottom: 0.4em;
small {
font-weight: lighter;
}
}
padding: 0 0.5em 0.5em 0.5em;
}
}
.status-preview-loading {
display: block;
font-size: 2em;
min-width: 8em;
text-align: center;
}
.status-el {
hyphens: auto;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
border-left-width: 0px;
line-height: 18px;
- background-color: var(--bg);
- border-color: var(--border);
+ background-color: $fallback--bg;
+ background-color: var(--bg, $fallback--bg);
+ border-color: $fallback--border;
+ border-color: var(--border, $fallback--border);
&_focused {
- background-color: var(--lightBg);
+ background-color: $fallback--lightBg;
+ background-color: var(--lightBg, $fallback--lightBg);
}
.usercard {
- border-color: var(--border);
+ border-color: $fallback--border;
+ border-color: var(--border, $fallback--border);
}
.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;
.avatar {
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_;
- color: var(--cBlue);
- }
+ color: $fallback--cBlue;
+ color: var(--cBlue, $fallback--cBlue);
+}
- .icon-reply.icon-reply-active {
- color: $blue_;
- color: var(--cBlue);
- }
+.icon-reply.icon-reply-active {
+ color: $fallback--cBlue;
+ color: var(--cBlue, $fallback--cBlue);
+}
.status .avatar {
width: 48px;
height: 48px;
border-radius: 5px;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
&.animated::before {
display: none;
}
- &.retweeted {
- width: 40px;
- height: 40px;
- margin-right: 8px;
- margin-bottom: 8px;
- }
- }
+ &.retweeted {
+ width: 40px;
+ height: 40px;
+ margin-right: 8px;
+ margin-bottom: 8px;
+ }
+}
.status:hover .animated.avatar {
canvas {
display: none;
}
img {
visibility: visible;
}
}
- .status .avatar-retweeter {
- width: 24px;
- height: 24px;
- position: absolute;
- margin-left: 24px;
- margin-top: 24px;
- }
+.status img.avatar-retweeter {
+ width: 24px;
+ height: 24px;
+ position: absolute;
+ margin-left: 24px;
+ margin-top: 24px;
+}
- .status.compact .avatar {
- width: 32px;
- }
+.status.compact .avatar {
+ width: 32px;
+}
- .status {
- padding: 0.4em 0.7em 0.45em 0.7em;
- border-left: 4px var(--cRed);
- border-left-style: inherit;
- }
+.status {
+ padding: 0.4em 0.7em 0.45em 0.7em;
+ border-left: 4px $fallback--cRed;
+ border-left: 4px var(--cRed, $fallback--cRed);
+ border-left-style: inherit;
+}
- .status-conversation:last-child {
+.status-conversation:last-child {
border-bottom: none;
- }
+}
- .timeline .panel.timeline {
+.timeline .panel.timeline {
border-radius: 10px;
overflow: hidden;
- }
+}
- .muted {
- padding: 0.1em 0.4em 0.1em 0.8em;
- button {
- margin-left: auto;
- }
+.muted {
+ padding: 0.1em 0.4em 0.1em 0.8em;
+ button {
+ margin-left: auto;
+ }
- .muteWords {
- margin-left: 10px;
- }
- }
+ .muteWords {
+ margin-left: 10px;
+ }
+}
- a.unmute {
- display: block;
- margin-left: auto;
- }
+a.unmute {
+ display: block;
+ margin-left: auto;
+}
- .reply-left {
- flex: 0;
- min-width: 48px;
- }
+.reply-left {
+ flex: 0;
+ min-width: 48px;
+}
- .reply-body {
- flex: 1;
- }
+.reply-body {
+ flex: 1;
+}
- @media all and (max-width: 960px) {
- .status-el {
- .name-and-links {
- margin-left: -0.25em;
- }
- }
- .status {
- max-width: 100%;
- }
+@media all and (max-width: 960px) {
+ .status-el {
+ .name-and-links {
+ margin-left: -0.25em;
+ }
+ }
- .status .avatar {
- width: 40px;
- height: 40px;
+ .status {
+ max-width: 100%;
+ }
- &.retweeted {
- width: 34px;
- height: 34px;
- margin-right: 8px;
- margin-bottom: 8px;
- }
- }
+ .status .avatar {
+ width: 40px;
+ height: 40px;
+
+ &.retweeted {
+ width: 34px;
+ height: 34px;
+ margin-right: 8px;
+ margin-bottom: 8px;
+ }
+ }
.status .avatar-retweeter {
width: 22px;
height: 22px;
position: absolute;
margin-left: 18px;
margin-top: 18px;
}
}
</style>
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 6c0cc6e76b..e6a00275ff 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -1,103 +1,110 @@
<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 class="color-container">
<div class="color-item">
<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="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">
</div>
<div class="color-item">
<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="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>
<div>
<div class="panel">
<div class="panel-heading" :style="{ 'background-color': fgColorLocal, 'color': textColorLocal }">Preview</div>
<div class="panel-body theme-preview-content" :style="{ 'background-color': bgColorLocal, 'color': textColorLocal }">
<h4>Content</h4>
<br>
A bunch of more content and
<a :style="{ 'color': linkColorLocal }">a nice lil' link</a>
<br>
<button class="btn" :style="{ 'background-color': fgColorLocal, 'color': textColorLocal }">Button</button>
</div>
</div>
</div>
<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;
}
.color-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.color-item {
min-width: 20em;
display:flex;
flex: 1 1 0;
align-items: baseline;
margin: 5px 6px 5px 0;
label {
- color: var(--faint);
+ color: var(--faint, $fallback--faint);
}
}
+
+.theme-color-cl {
+ border: 0;
+ box-shadow: none;
+ background: transparent;
+}
+
.theme-color-cl,
.theme-color-in {
margin-left: 4px;
border-radius: 2px;
- border: 0;
}
.theme-color-in {
padding: 5px;
min-width: 4em;
max-width: 7em;
flex: 1;
}
.theme-color-lb {
flex: 2;
min-width: 7em;
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;
}
</style>
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index b6a5ab1418..c3cc939a18 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -1,106 +1,115 @@
<template>
<div class="timeline panel panel-default" v-if="viewing == 'statuses'">
<div class="panel-heading timeline-heading">
<div class="title">
{{title}}
</div>
<button @click.prevent="showNewStatuses" class="loadmore-button" v-if="timeline.newStatusCount > 0 && !timelineError">
{{$t('timeline.show_new')}}{{newStatusCountStr}}
</button>
<div @click.prevent class="loadmore-text" v-if="timelineError">
{{$t('timeline.error_fetching')}}
</div>
<div @click.prevent class="loadmore-text" v-if="!timeline.newStatusCount > 0 && !timelineError">
{{$t('timeline.up_to_date')}}
</div>
</div>
<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="new-status-notification text-center">{{$t('timeline.load_older')}}</div>
</a>
<div class="new-status-notification text-center" v-else>...</div>
</div>
</div>
</div>
<div class="timeline panel panel-default" v-else-if="viewing == 'followers'">
<div class="panel-heading timeline-heading">
<div class="title">
{{$t('user_card.followers')}}
</div>
</div>
<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">
<div class="title">
{{$t('user_card.followees')}}
</div>
</div>
<div class="panel-body">
<div class="timeline">
<user-card v-for="friend in friends" :key="friend.id" :user="friend" :showFollows="true"></user-card>
</div>
</div>
</div>
</template>
<script src="./timeline.js"></script>
<style lang="scss">
+@import '../../_variables.scss';
- .timeline {
+.timeline {
.timeline-heading {
- position: relative;
- display: flex;
+ position: relative;
+ display: flex;
}
+
.title {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 70%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 70%;
}
+
.loadmore-button {
- position: absolute;
- right: 0.6em;
- font-size: 14px;
+ 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;
- background-color: transparent;
- color: var(--faint);
- font-family: sans-serif;
- text-align: center;
- padding: 0 0.5em 0 0.5em;
- opacity: 0.8;
+ position: absolute;
+ right: 0.6em;
+ font-size: 14px;
+ min-width: 6em;
+ border-radius: 5px;
+ background-color: transparent;
+ color: $fallback--faint;
+ color: var(--faint, $fallback--faint);
+ font-family: sans-serif;
+ text-align: center;
+ padding: 0 0.5em 0 0.5em;
+ opacity: 0.8;
}
+
.error {
- color: var(--lightFg);
- background-color: var(--cRed);
+ color: $fallback--lightFg;
+ color: var(--lightFg, $fallback--lightFg);
+ background-color: $fallback--cRed;
+ background-color: var(--cRed, $fallback--cRed);
}
- }
+}
- .new-status-notification {
+.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;
- border-color: var(--border);
+ border-color: $fallback--border;
+ border-color: var(--border, $fallback--border);
padding: 10px;
z-index: 1;
}
</style>
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 0561fa9504..6487d2a6cc 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -1,76 +1,76 @@
<template>
<div class="card">
<a href="#">
<img @click.prevent="toggleUserExpanded" class="avatar" :src="user.profile_image_url">
</a>
<div class="usercard" v-if="userExpanded">
<user-card-content :user="user" :switcher="false"></user-card-content>
</div>
<div class="name-and-screen-name" v-else>
<div class="user-name">
{{ user.name }}
<span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you">
{{ $t('user_card.follows_you') }}
</span>
</div>
<a :href="user.statusnet_profile_url" target="blank"><div class="user-screen-name">@{{ user.screen_name }}</div></a>
</div>
</div>
</template>
<script src="./user_card.js"></script>
<style lang="scss">
+@import '../../_variables.scss';
+
.name-and-screen-name {
margin-left: 0.7em;
margin-top:0.0em;
margin-right: 2em;
text-align: left;
width: 100%;
}
.follows-you {
margin-left: 2em;
float: right;
}
-.follows {
-
-}
-
.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: var(--border);
+ border-bottom-color: $fallback--border;
+ border-bottom-color: var(--border, $fallback--border);
.avatar {
margin-top: 0.2em;
width:32px;
height: 32px;
border-radius: 50%;
}
}
.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;
.panel-heading {
background: transparent;
}
+
p {
- margin-bottom: 0;
+ 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 b7f156d2bf..2e448f1cb9 100644
--- a/src/components/user_card_content/user_card_content.js
+++ b/src/components/user_card_content/user_card_content.js
@@ -1,73 +1,68 @@
import StillImage from '../still-image/still-image.vue'
import { hex2rgb } from '../../services/color_convert/color_convert.js'
export default {
props: [ 'user', 'switcher' ],
computed: {
headingStyle () {
const color = this.$store.state.config.colors.bg
if (color) {
const rgb = hex2rgb(color)
console.log(rgb)
return {
backgroundColor: `rgb(${Math.floor(rgb[0] * 0.53)}, ${Math.floor(rgb[1] * 0.56)}, ${Math.floor(rgb[2] * 0.59)})`,
backgroundImage: `url(${this.user.cover_photo})`
}
}
},
- bodyStyle () {
- return {
- background: `linear-gradient(to bottom, rgba(0, 0, 0, 0), ${this.$store.state.config.colors.bg} 80%)`
- }
- },
isOtherUser () {
return this.user.id !== this.$store.state.users.currentUser.id
},
subscribeUrl () {
// eslint-disable-next-line no-undef
const serverUrl = new URL(this.user.statusnet_profile_url)
return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
},
loggedIn () {
return this.$store.state.users.currentUser
},
dailyAvg () {
const days = Math.ceil((new Date() - new Date(this.user.created_at)) / (60 * 60 * 24 * 1000))
return Math.round(this.user.statuses_count / days)
}
},
components: {
StillImage
},
methods: {
followUser () {
const store = this.$store
store.state.api.backendInteractor.followUser(this.user.id)
.then((followedUser) => store.commit('addNewUsers', [followedUser]))
},
unfollowUser () {
const store = this.$store
store.state.api.backendInteractor.unfollowUser(this.user.id)
.then((unfollowedUser) => store.commit('addNewUsers', [unfollowedUser]))
},
blockUser () {
const store = this.$store
store.state.api.backendInteractor.blockUser(this.user.id)
.then((blockedUser) => store.commit('addNewUsers', [blockedUser]))
},
unblockUser () {
const store = this.$store
store.state.api.backendInteractor.unblockUser(this.user.id)
.then((unblockedUser) => store.commit('addNewUsers', [unblockedUser]))
},
toggleMute () {
const store = this.$store
store.commit('setMuted', {user: this.user, muted: !this.user.muted})
store.state.api.backendInteractor.setUserMute(this.user)
},
setProfileView (v) {
const store = this.$store
store.commit('setProfileView', { v })
}
}
}
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index e3c9b5f9b1..ca3da632c1 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -1,258 +1,260 @@
<template>
<div id="heading" class="profile-panel-background" :style="headingStyle">
<div class="panel-heading text-center">
<div class='user-info'>
<router-link to='/user-settings' style="float: right; margin-top:16px;" v-if="!isOtherUser">
<i class="icon-cog usersettings"></i>
</router-link>
<div class='container'>
<router-link :to="{ name: 'user-profile', params: { id: user.id } }">
<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>
<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">
{{ $t('user_card.follows_you') }}
</div>
<div class="follow" v-if="loggedIn">
<span v-if="user.following">
<!--Following them!-->
<button @click="unfollowUser" class="pressed">
{{ $t('user_card.following') }}
</button>
</span>
<span v-if="!user.following">
<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="pressed">
{{ $t('user_card.muted') }}
</button>
</span>
<span v-if='!user.muted'>
<button @click="toggleMute">
{{ $t('user_card.mute') }}
</button>
</span>
</div>
<div class="remote-follow" v-if='!loggedIn && user.is_local'>
<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">
{{ $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="pressed">
{{ $t('user_card.blocked') }}
</button>
</span>
<span v-if='!user.statusnet_blocking'>
<button @click="blockUser">
{{ $t('user_card.block') }}
</button>
</span>
</div>
</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>{{ $t('user_card.statuses') }}</h5></a>
<h5 v-else>{{ $t('user_card.statuses') }}</h5>
<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>{{ $t('user_card.followees') }}</h5></a>
<h5 v-else>{{ $t('user_card.followees') }}</h5>
<span>{{user.friends_count}}</span>
</div>
<div class="user-count">
<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>{{user.followers_count}}</span>
</div>
</div>
<p>{{user.description}}</p>
</div>
</div>
</template>
<script src="./user_card_content.js"></script>
<style lang="scss">
@import '../../_variables.scss';
.profile-panel-background {
- background-size: cover;
- border-radius: 10px;
+ background-size: cover;
+ border-radius: 10px;
- .panel-heading {
- padding: 0.6em 0em;
- text-align: center;
- }
+ .panel-heading {
+ padding: 0.6em 0em;
+ text-align: center;
+ }
}
.profile-panel-body {
- top: -0em;
- padding-top: 4em;
- word-wrap: break-word;
+ 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;
padding: 0 16px 16px 16px;
margin-bottom: -4em;
.usersettings {
color: white;
opacity: 0.8;
}
.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: 5px;
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;
}
}
&:hover .animated.avatar {
canvas {
display: none;
}
img {
visibility: visible;
}
}
text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0);
.name-and-screen-name {
display: block;
margin-left: 0.6em;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
}
.user-name{
color: white;
}
.user-screen-name {
color: white;
font-weight: lighter;
font-size: 15px;
padding-right: 0.1em;
flex: 0 0 auto;
}
.user-interactions {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
div {
flex: 1;
}
margin-top: 0.7em;
margin-bottom: -1.0em;
.following {
color: white;
font-size: 14px;
flex: 0 0 100%;
margin: -0.7em 0.0em 0.3em 0.0em;
padding-left: 16px;
text-align: left;
}
.mute {
max-width: 220px;
min-height: 28px;
}
.remote-follow {
max-width: 220px;
min-height: 28px;
}
.follow {
max-width: 220px;
min-height: 28px;
}
button {
width: 92%;
height: 100%;
}
.remote-button {
height: 28px !important;
width: 92%;
}
.pressed {
border-bottom-color: rgba(255, 255, 255, 0.2);
border-top-color: rgba(0, 0, 0, 0.2);
}
}
}
.user-counts {
display: flex;
line-height:16px;
padding: 1em 1.5em 0em 1em;
text-align: center;
}
.user-count {
flex: 1;
h5 {
font-size:1em;
font-weight: bolder;
margin: 0 0 0.25em;
}
a {
text-decoration: none;
}
}
.dailyAvg {
font-size: 0.8em;
opacity: 0.5;
}
</style>
diff --git a/src/components/user_finder/user_finder.vue b/src/components/user_finder/user_finder.vue
index 66b2fc87ec..e4453fe73d 100644
--- a/src/components/user_finder/user_finder.vue
+++ b/src/components/user_finder/user_finder.vue
@@ -1,40 +1,40 @@
<template>
<span class="user-finder-container">
<span class="finder-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" @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>
</template>
<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: 21px;
+ max-width: 100%;
+}
- .user-finder-input {
- border-radius: 5px;
- max-width: 80%;
- padding: 0.1em 0.2em 0.2em 0.2em;
- }
+.user-finder-input {
+ border-radius: 5px;
+ max-width: 80%;
+ padding: 0.1em 0.2em 0.2em 0.2em;
+}
- .finder-error {
- background-color: rgba(255, 48, 16, 0.65);
- margin: 0.35em;
- border-radius: 5px;
- padding: 0.25em;
- color: var(--faint);
- }
+.finder-error {
+ background-color: rgba(255, 48, 16, 0.65);
+ margin: 0.35em;
+ border-radius: 5px;
+ padding: 0.25em;
+ color: $fallback--faint;
+ color: var(--faint, $fallback--faint);
+}
</style>
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 1bd8df51c8..bedadb126c 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -1,138 +1,130 @@
import { times } from 'lodash'
import { rgb2hex, hex2rgb } from '../color_convert/color_convert.js'
// While this is not used anymore right now, I left it in if we want to do custom
// styles that aren't just colors, so user can pick from a few different distinct
// styles as well as set their own colors in the future.
const setStyle = (href, commit) => {
/***
What's going on here?
I want to make it easy for admins to style this application. To have
a good set of default themes, I chose the system from base16
(https://chriskempson.github.io/base16/) to style all elements. They
all have the base00..0F classes. So the only thing an admin needs to
do to style Pleroma is to change these colors in that one css file.
Some default things (body text color, link color) need to be set dy-
namically, so this is done here by waiting for the stylesheet to be
loaded and then creating an element with the respective classes.
It is a bit weird, but should make life for admins somewhat easier.
***/
const head = document.head
const body = document.body
body.style.display = 'none'
const cssEl = document.createElement('link')
cssEl.setAttribute('rel', 'stylesheet')
cssEl.setAttribute('href', href)
head.appendChild(cssEl)
const setDynamic = () => {
const baseEl = document.createElement('div')
body.appendChild(baseEl)
let colors = {}
times(16, (n) => {
const name = `base0${n.toString(16).toUpperCase()}`
baseEl.setAttribute('class', name)
const color = window.getComputedStyle(baseEl).getPropertyValue('color')
colors[name] = color
})
commit('setOption', { name: 'colors', value: colors })
body.removeChild(baseEl)
const styleEl = document.createElement('style')
head.appendChild(styleEl)
// const styleSheet = styleEl.sheet
- // styleSheet.insertRule(`a { color: ${colors['base08']}`, 'index-max')
- // styleSheet.insertRule(`body { color: ${colors['base05']}`, 'index-max')
body.style.display = 'initial'
}
cssEl.addEventListener('load', setDynamic)
}
const setColors = (col, commit) => {
const head = document.head
const body = document.body
body.style.display = 'none'
const styleEl = document.createElement('style')
head.appendChild(styleEl)
const styleSheet = styleEl.sheet
const isDark = (col.text.r + col.text.g + col.text.b) > (col.bg.r + col.bg.g + col.bg.b)
let colors = {}
let mod = 10
if (isDark) {
mod = mod * -1
}
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 + mod * 2, col.text.g + mod * 2, col.text.b + mod * 2) // 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['base07'] = rgb2hex(col.text.r - mod * 2, col.text.g - mod * 2, col.text.b - mod * 2)
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 = 'blue'
+ colors.cBlue = '#0095ff'
colors.cRed = 'red'
- colors.cGreen = 'green'
+ colors.cGreen = '#0fa00f'
colors.cYellow = 'yellow'
colors.cOrange = 'orange'
- const colorVars = Object.entries(colors).map(([k, v]) => {
- return `--${k}: ${v}`
- })
- console.log(colorVars)
-
- styleSheet.insertRule(`body { ${colorVars.join(';')} }`, 'index-max')
- // styleSheet.insertRule(`.base05-border { border-color: ${colors['base05']}`, 'index-max')
- // styleSheet.insertRule(`.base03-border { border-color: ${colors['base03']}`, 'index-max')
+ styleSheet.toString()
+ styleSheet.insertRule(`body { ${Object.entries(colors).map(([k, v]) => `--${k}: ${v}`).join(';')} }`, 'index-max')
body.style.display = 'initial'
commit('setOption', { name: 'colors', value: colors })
commit('setOption', { name: 'customTheme', value: col })
}
const setPreset = (val, commit) => {
window.fetch('/static/styles.json')
.then((data) => data.json())
.then((themes) => {
const theme = themes[val] ? themes[val] : themes['pleroma-dark']
const bgRgb = hex2rgb(theme[1])
const fgRgb = hex2rgb(theme[2])
const textRgb = hex2rgb(theme[3])
const linkRgb = hex2rgb(theme[4])
const col = {
bg: bgRgb,
fg: fgRgb,
text: textRgb,
link: linkRgb
}
// 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.
// Needed some way of dealing with the async way of things.
// load config -> set preset -> wait for styles.json to load ->
// load persisted state -> set colors -> styles.json loaded -> set colors
if (!window.themeLoaded) {
setColors(col, commit)
}
})
}
const StyleSetter = {
setStyle,
setPreset,
setColors
}
export default StyleSetter

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 19, 2:26 PM (20 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1765936
Default Alt Text
(88 KB)

Event Timeline