diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/notification/notification.js | 11 | ||||
| -rw-r--r-- | src/components/notification/notification.vue | 2 | ||||
| -rw-r--r-- | src/components/notifications/notifications.scss | 4 | ||||
| -rw-r--r-- | src/components/status/status.js | 20 | ||||
| -rw-r--r-- | src/components/status/status.vue | 9 | ||||
| -rw-r--r-- | src/components/user_card_content/user_card_content.js | 28 | ||||
| -rw-r--r-- | src/components/user_card_content/user_card_content.vue | 120 | ||||
| -rw-r--r-- | src/main.js | 1 | ||||
| -rw-r--r-- | src/modules/config.js | 16 | ||||
| -rw-r--r-- | src/modules/users.js | 4 | ||||
| -rw-r--r-- | src/services/user_highlighter/user_highlighter.js | 48 |
11 files changed, 218 insertions, 45 deletions
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 3a274374..c786f2cc 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -1,6 +1,7 @@ import Status from '../status/status.vue' import StillImage from '../still-image/still-image.vue' import UserCardContent from '../user_card_content/user_card_content.vue' +import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' const Notification = { data () { @@ -18,6 +19,16 @@ const Notification = { toggleUserExpanded () { this.userExpanded = !this.userExpanded } + }, + computed: { + userClass () { + return highlightClass(this.notification.action.user) + }, + userStyle () { + const highlight = this.$store.state.config.highlight + const user = this.notification.action.user + return highlightStyle(highlight[user.screen_name]) + } } } diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 208e389c..bb76ddf8 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -1,6 +1,6 @@ <template> <status v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status> - <div class="non-mention" v-else> + <div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]"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> diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 008530b4..5853c68e 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -45,8 +45,7 @@ } .unseen { - border-left: 4px solid $fallback--cRed; - border-left: 4px solid var(--cRed, $fallback--cRed); + box-shadow: inset 4px 0 0 var(--cRed, $fallback--cRed); padding-left: 0; } } @@ -56,7 +55,6 @@ display: flex; border-bottom: 1px solid; border-bottom-color: inherit; - padding-left: 4px; .avatar-compact { width: 32px; diff --git a/src/components/status/status.js b/src/components/status/status.js index eb7d24d6..a2d6f41f 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -6,6 +6,7 @@ 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' +import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' const Status = { name: 'Status', @@ -34,6 +35,25 @@ const Status = { muteWords () { return this.$store.state.config.muteWords }, + repeaterClass () { + const user = this.statusoid.user + return highlightClass(user) + }, + userClass () { + const user = this.retweet ? (this.statusoid.retweeted_status.user) : this.statusoid.user + return highlightClass(user) + }, + repeaterStyle () { + const user = this.statusoid.user + const highlight = this.$store.state.config.highlight + return highlightStyle(highlight[user.screen_name]) + }, + userStyle () { + if (this.noHeading) return + const user = this.retweet ? (this.statusoid.retweeted_status.user) : this.statusoid.user + const highlight = this.$store.state.config.highlight + return highlightStyle(highlight[user.screen_name]) + }, hideAttachments () { return (this.$store.state.config.hideAttachments && !this.inConversation) || (this.$store.state.config.hideAttachmentsInConv && this.inConversation) diff --git a/src/components/status/status.vue b/src/components/status/status.vue index b871d7fe..e2fb5d36 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -8,7 +8,7 @@ </div> </template> <template v-else> - <div v-if="retweet && !noHeading" class="media container retweet-info"> + <div v-if="retweet && !noHeading" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info"> <StillImage v-if="retweet" class='avatar' :src="statusoid.user.profile_image_url_original"/> <div class="media-body faint"> <a v-if="retweeterHtml" :href="statusoid.user.statusnet_profile_url" style="font-weight: bold;" :title="'@'+statusoid.user.screen_name" v-html="retweeterHtml"></a> @@ -18,7 +18,7 @@ </div> </div> - <div class="media status"> + <div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet }]" :style="[ userStyle ]" 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"/> @@ -317,7 +317,7 @@ .retweet-info { padding: 0.4em 0.6em 0 0.6em; - margin: 0 0 -0.5em 0; + margin: 0; .avatar { border-radius: $fallback--avatarAltRadius; border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); @@ -429,6 +429,9 @@ .status { display: flex; padding: 0.6em; + &.is-retweet { + padding-top: 0.1em; + } } .status-conversation:last-child { diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index 4d4266cb..76a5577e 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -9,11 +9,6 @@ export default { if (color) { const rgb = hex2rgb(color) const tintColor = `rgba(${Math.floor(rgb.r)}, ${Math.floor(rgb.g)}, ${Math.floor(rgb.b)}, .5)` - console.log(rgb) - console.log([ - `url(${this.user.cover_photo})`, - `linear-gradient(to bottom, ${tintColor}, ${tintColor})` - ].join(', ')) return { backgroundColor: `rgb(${Math.floor(rgb.r * 0.53)}, ${Math.floor(rgb.g * 0.56)}, ${Math.floor(rgb.b * 0.59)})`, backgroundImage: [ @@ -37,6 +32,29 @@ export default { 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) + }, + userHighlightType: { + get () { + const data = this.$store.state.config.highlight[this.user.screen_name] + return data && data.type || 'disabled' + }, + set (type) { + const data = this.$store.state.config.highlight[this.user.screen_name] + if (type !== 'disabled') { + this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: data && data.color || '#FFFFFF', type }) + } else { + this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: undefined }) + } + } + }, + userHighlightColor: { + get () { + const data = this.$store.state.config.highlight[this.user.screen_name] + return data && data.color + }, + set (color) { + this.$store.dispatch('setHighlight', { user: this.user.screen_name, color }) + } } }, components: { diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index 96923786..71222d15 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -1,30 +1,46 @@ <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> +<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> + <a :href="user.statusnet_profile_url" target="_blank" class="floater" v-if="isOtherUser"> + <i class="icon-link-ext usersettings"></i> + </a> + <div class='container'> + <router-link :to="{ name: 'user-profile', params: { id: user.id } }"> + <StillImage class="avatar" :src="user.profile_image_url_original"/> </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 } }"> - <StillImage class="avatar" :src="user.profile_image_url_original"/> + <div class="name-and-screen-name"> + <div :title="user.name" class='user-name' v-if="user.name_html" v-html="user.name_html"></div> + <div :title="user.name" class='user-name' v-else>{{user.name}}</div> + <router-link class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }"> + <span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span> + <span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span> </router-link> - <div class="name-and-screen-name"> - <div :title="user.name" class='user-name' v-if="user.name_html" v-html="user.name_html"></div> - <div :title="user.name" class='user-name' v-else>{{user.name}}</div> - <router-link class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }"> - <span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span> - <span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span> - </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> + <div class="user-meta"> + <div v-if="user.follows_you && loggedIn && isOtherUser" class="following"> + {{ $t('user_card.follows_you') }} + </div> + <div class="floater" v-if="switcher || isOtherUser"> + <!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to --> + <input class="userHighlightText" type="text" :id="'userHighlightColorTx'+user.id" v-if="userHighlightType !== 'disabled'" v-model="userHighlightColor"/> + <input class="userHighlightCl" type="color" :id="'userHighlightColor'+user.id" v-if="userHighlightType !== 'disabled'" v-model="userHighlightColor"/> + <label for="style-switcher" class='userHighlightSel select'> + <select class="userHighlightSel" :id="'userHighlightSel'+user.id" v-model="userHighlightType"> + <option value="disabled">No highlight</option> + <option value="solid">Solid bg</option> + <option value="striped">Striped bg</option> + <option value="side">Side stripe</option> + </select> + <i class="icon-down-open"/> + </label> + </div> + </div> + <div v-if="isOtherUser" class="user-interactions"> <div class="follow" v-if="loggedIn"> <span v-if="user.following"> <!--Following them!--> @@ -181,6 +197,27 @@ padding-right: 0.1em; } + .user-meta { + margin-bottom: .4em; + + .following { + font-size: 14px; + flex: 0 0 100%; + margin: 0; + padding-left: 16px; + text-align: left; + float: left; + } + .floater { + margin: 0; + } + + &::after { + display: block; + content: ''; + clear: both; + } + } .user-interactions { display: flex; flex-flow: row wrap; @@ -190,14 +227,6 @@ flex: 1; } - .following { - font-size: 14px; - flex: 0 0 100%; - margin: 0 0 .4em 0; - padding-left: 16px; - text-align: left; - } - .mute { max-width: 220px; min-height: 28px; @@ -280,4 +309,33 @@ font-size: 0.7em; color: #CCC; } +.floater { + float: right; + margin-top: 16px; + + .userHighlightCl { + padding: 2px 10px; + } + .userHighlightSel, + .userHighlightSel.select { + padding-top: 0; + padding-bottom: 0; + } + .userHighlightSel.select i { + line-height: 22px; + } + + .userHighlightText { + width: 70px; + } + + .userHighlightCl, + .userHighlightText, + .userHighlightSel, + .userHighlightSel.select { + height: 22px; + vertical-align: top; + margin-right: 0 + } +} </style> diff --git a/src/main.js b/src/main.js index fa955063..100519f4 100644 --- a/src/main.js +++ b/src/main.js @@ -53,6 +53,7 @@ const persistedStateOptions = { 'config.streaming', 'config.muteWords', 'config.customTheme', + 'config.highlight', 'users.lastLoginName' ] } diff --git a/src/modules/config.js b/src/modules/config.js index 9a62905e..2b50655b 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -1,4 +1,4 @@ -import { set } from 'vue' +import { set, delete as del } from 'vue' import StyleSetter from '../services/style_setter/style_setter.js' const defaultState = { @@ -10,7 +10,8 @@ const defaultState = { autoLoad: true, streaming: false, hoverPreview: true, - muteWords: [] + muteWords: [], + highlight: {} } const config = { @@ -18,12 +19,23 @@ const config = { mutations: { setOption (state, { name, value }) { set(state, name, value) + }, + setHighlight (state, { user, color, type }) { + const data = this.state.config.highlight[user] + if (color || type) { + set(state.highlight, user, { color: color || data.color, type: type || data.type }) + } else { + del(state.highlight, user) + } } }, actions: { setPageTitle ({state}, option = '') { document.title = `${option} ${state.name}` }, + setHighlight ({ commit, dispatch }, { user, color, type }) { + commit('setHighlight', {user, color, type}) + }, setOption ({ commit, dispatch }, { name, value }) { commit('setOption', {name, value}) switch (name) { diff --git a/src/modules/users.js b/src/modules/users.js index 8303ecc1..ba548765 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -42,6 +42,10 @@ export const mutations = { }, setUserForStatus (state, status) { status.user = state.usersObject[status.user.id] + }, + setColor (state, { user: {id}, highlighted }) { + const user = state.usersObject[id] + set(user, 'highlight', highlighted) } } diff --git a/src/services/user_highlighter/user_highlighter.js b/src/services/user_highlighter/user_highlighter.js new file mode 100644 index 00000000..ebb25eca --- /dev/null +++ b/src/services/user_highlighter/user_highlighter.js @@ -0,0 +1,48 @@ +import { hex2rgb } from '../color_convert/color_convert.js' +const highlightStyle = (prefs) => { + if (prefs === undefined) return + const {color, type} = prefs + if (typeof color !== 'string') return + const rgb = hex2rgb(color) + if (rgb == null) return + const solidColor = `rgb(${Math.floor(rgb.r)}, ${Math.floor(rgb.g)}, ${Math.floor(rgb.b)})` + const tintColor = `rgba(${Math.floor(rgb.r)}, ${Math.floor(rgb.g)}, ${Math.floor(rgb.b)}, .1)` + const tintColor2 = `rgba(${Math.floor(rgb.r)}, ${Math.floor(rgb.g)}, ${Math.floor(rgb.b)}, .2)` + if (type === 'striped') { + return { + backgroundImage: [ + 'repeating-linear-gradient(-45deg,', + `${tintColor} ,`, + `${tintColor} 20px,`, + `${tintColor2} 20px,`, + `${tintColor2} 40px` + ].join(' '), + backgroundPosition: '0 0' + } + } else if (type === 'solid') { + return { + backgroundColor: tintColor2 + } + } else if (type === 'side') { + return { + backgroundImage: [ + 'linear-gradient(to right,', + `${solidColor} ,`, + `${solidColor} 2px,`, + `transparent 6px` + ].join(' '), + backgroundPosition: '0 0' + } + } +} + +const highlightClass = (user) => { + return 'USER____' + user.screen_name + .replace(/\./g, '_') + .replace(/@/g, '_AT_') +} + +export { + highlightClass, + highlightStyle +} |
