aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/App.scss7
-rw-r--r--src/components/notification/notification.js11
-rw-r--r--src/components/notification/notification.vue5
-rw-r--r--src/components/notifications/notifications.scss4
-rw-r--r--src/components/post_status_form/post_status_form.js8
-rw-r--r--src/components/registration/registration.js10
-rw-r--r--src/components/registration/registration.vue4
-rw-r--r--src/components/retweet_button/retweet_button.js2
-rw-r--r--src/components/retweet_button/retweet_button.vue4
-rw-r--r--src/components/status/status.js21
-rw-r--r--src/components/status/status.vue17
-rw-r--r--src/components/style_switcher/style_switcher.vue5
-rw-r--r--src/components/timeline/timeline.js15
-rw-r--r--src/components/user_card/user_card.vue10
-rw-r--r--src/components/user_card_content/user_card_content.js28
-rw-r--r--src/components/user_card_content/user_card_content.vue122
-rw-r--r--src/i18n/messages.js6
-rw-r--r--src/main.js5
-rw-r--r--src/modules/config.js16
-rw-r--r--src/modules/users.js4
-rw-r--r--src/services/api/api.service.js1
-rw-r--r--src/services/user_highlighter/user_highlighter.js48
22 files changed, 289 insertions, 64 deletions
diff --git a/src/App.scss b/src/App.scss
index f830a33b..2426b998 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -168,6 +168,13 @@ input, textarea, .select {
}
}
+option {
+ color: $fallback--fg;
+ color: var(--fg, $fallback--fg);
+ background-color: $fallback--bg;
+ background-color: var(--bg, $fallback--bg);
+}
+
i[class*=icon-] {
color: $fallback--icon;
color: var(--icon, $fallback--icon)
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 eed598a8..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>
@@ -10,7 +10,8 @@
</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 class="username" v-if="!!notification.action.user.name_html" :title="'@'+notification.action.user.screen_name" v-html="notification.action.user.name_html"></span>
+ <span class="username" v-else :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>
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/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 4f4c6aca..61f2ac0a 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -31,6 +31,10 @@ const PostStatusForm = {
},
mounted () {
this.resize(this.$refs.textarea)
+
+ if (this.replyTo) {
+ this.$refs.textarea.focus()
+ }
},
data () {
const preset = this.$route.query.message
@@ -87,11 +91,11 @@ const PostStatusForm = {
return false
}
return map(take(matchedEmoji, 5), ({shortcode, image_url, utf}, index) => ({
- // eslint-disable-next-line camelcase
screen_name: `:${shortcode}:`,
name: '',
utf: utf || '',
- img: image_url,
+ // eslint-disable-next-line camelcase
+ img: utf ? '' : this.$store.state.config.server + image_url,
highlighted: index === this.highlighted
}))
} else {
diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js
index 771b3b27..73840608 100644
--- a/src/components/registration/registration.js
+++ b/src/components/registration/registration.js
@@ -5,17 +5,23 @@ const registration = {
registering: false
}),
created () {
- if (!this.$store.state.config.registrationOpen || !!this.$store.state.users.currentUser) {
+ if ((!this.$store.state.config.registrationOpen && !this.token) || !!this.$store.state.users.currentUser) {
this.$router.push('/main/all')
}
+ // Seems like this doesn't work at first page open for some reason
+ if (this.$store.state.config.registrationOpen && this.token) {
+ this.$router.push('/registration')
+ }
},
computed: {
- termsofservice () { return this.$store.state.config.tos }
+ termsofservice () { return this.$store.state.config.tos },
+ token () { return this.$route.params.token }
},
methods: {
submit () {
this.registering = true
this.user.nickname = this.user.username
+ this.user.token = this.token
this.$store.state.api.backendInteractor.register(this.user).then(
(response) => {
if (response.ok) {
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index 00f665af..087cab6b 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -38,6 +38,10 @@
<input :disabled="registering" v-model='user.captcha' placeholder='Enter captcha' type='test' class='form-control' id='captcha'>
</div>
-->
+ <div class='form-group' v-if='token' >
+ <label for='token'>{{$t('registration.token')}}</label>
+ <input disabled='true' v-model='token' class='form-control' id='token' type='text'>
+ </div>
<div class='form-group'>
<button :disabled="registering" type='submit' class='btn btn-default'>{{$t('general.submit')}}</button>
</div>
diff --git a/src/components/retweet_button/retweet_button.js b/src/components/retweet_button/retweet_button.js
index 9833e8b2..cafa9cbc 100644
--- a/src/components/retweet_button/retweet_button.js
+++ b/src/components/retweet_button/retweet_button.js
@@ -1,5 +1,5 @@
const RetweetButton = {
- props: ['status', 'loggedIn'],
+ props: ['status', 'loggedIn', 'visibility'],
data () {
return {
animated: false
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index 1bee3d08..f5b00599 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -1,9 +1,9 @@
<template>
- <div v-if="loggedIn">
+ <div v-if="loggedIn && visibility !== 'private' && visibility !== 'direct'">
<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>
+ <div v-else-if="!loggedIn">
<i :class='classes' class='icon-retweet'></i>
<span v-if='status.repeat_num > 0'>{{status.repeat_num}}</span>
</div>
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 87ef90d8..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,12 +35,32 @@ 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)
},
retweet () { return !!this.statusoid.retweeted_status },
retweeter () { return this.statusoid.user.name },
+ retweeterHtml () { return this.statusoid.user.name_html },
status () {
if (this.retweet) {
return this.statusoid.retweeted_status
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index f88c810d..e2fb5d36 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -8,16 +8,17 @@
</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 :href="statusoid.user.statusnet_profile_url" style="font-weight: bold;" :title="'@'+statusoid.user.screen_name">{{retweeter}}</a>
+ <a v-if="retweeterHtml" :href="statusoid.user.statusnet_profile_url" style="font-weight: bold;" :title="'@'+statusoid.user.screen_name" v-html="retweeterHtml"></a>
+ <a v-else :href="statusoid.user.statusnet_profile_url" style="font-weight: bold;" :title="'@'+statusoid.user.screen_name">{{retweeter}}</a>
<i class='fa icon-retweet retweeted'></i>
{{$t('timeline.repeated')}}
</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"/>
@@ -30,7 +31,8 @@
<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>
+ <h4 class="user-name" v-if="status.user.name_html" v-html="status.user.name_html"></h4>
+ <h4 class="user-name" v-else>{{status.user.name}}</h4>
<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">
@@ -88,7 +90,7 @@
<i class="icon-reply" :class="{'icon-reply-active': replying}"></i>
</a>
</div>
- <retweet-button :loggedIn='loggedIn' :status='status'></retweet-button>
+ <retweet-button :visibility='status.visibility' :loggedIn='loggedIn' :status='status'></retweet-button>
<favorite-button :loggedIn='loggedIn' :status='status'></favorite-button>
<delete-button :status='status'></delete-button>
</div>
@@ -315,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);
@@ -427,6 +429,9 @@
.status {
display: flex;
padding: 0.6em;
+ &.is-retweet {
+ padding-top: 0.1em;
+ }
}
.status-conversation:last-child {
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 7acba1dc..112bbc1e 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -3,7 +3,10 @@
<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>
+ <option v-for="style in availableStyles" :value="style" :style="{
+ backgroundColor: style[1],
+ color: style[3]
+ }">{{style[0]}}</option>
</select>
<i class="icon-down-open"/>
</label>
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index f24626f9..5c179567 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -13,7 +13,8 @@ const Timeline = {
],
data () {
return {
- paused: false
+ paused: false,
+ unfocused: false
}
},
computed: {
@@ -65,8 +66,15 @@ const Timeline = {
this.fetchFollowers()
}
},
+ mounted () {
+ if (typeof document.hidden !== 'undefined') {
+ document.addEventListener('visibilitychange', this.handleVisibilityChange, false)
+ this.unfocused = document.hidden
+ }
+ },
destroyed () {
window.removeEventListener('scroll', this.scrollLoad)
+ if (typeof document.hidden !== 'undefined') document.removeEventListener('visibilitychange', this.handleVisibilityChange, false)
this.$store.commit('setLoading', { timeline: this.timelineName, value: false })
},
methods: {
@@ -113,6 +121,9 @@ const Timeline = {
(window.innerHeight + window.pageYOffset) >= (height - 750)) {
this.fetchOlderStatuses()
}
+ },
+ handleVisibilityChange () {
+ this.unfocused = document.hidden
}
},
watch: {
@@ -122,7 +133,7 @@ const Timeline = {
}
if (count > 0) {
// only 'stream' them when you're scrolled to the top
- if (window.pageYOffset < 15 && !this.paused) {
+ if (window.pageYOffset < 15 && !this.paused && !this.unfocused) {
this.showNewStatuses()
} else {
this.paused = true
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 6478a65f..7e3e0afe 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -7,10 +7,16 @@
<user-card-content :user="user" :switcher="false"></user-card-content>
</div>
<div class="name-and-screen-name" v-else>
- <div :title="user.name" class="user-name">
+ <div :title="user.name" v-if="user.name_html" class="user-name">
+ <span v-html="user.name_html"></span>
+ <span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you">
+ {{ $t('user_card.follows_you') }}
+ </span>
+ </div>
+ <div :title="user.name" v-else class="user-name">
{{ user.name }}
<span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you">
- {{ $t('user_card.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>
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 09e91271..71222d15 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -1,29 +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'>{{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!-->
@@ -88,7 +105,8 @@
<span>{{user.followers_count}}</span>
</div>
</div>
- <p v-if="!hideBio">{{user.description}}</p>
+ <p v-if="!hideBio && user.description_html" v-html="user.description_html"></p>
+ <p v-else-if="!hideBio">{{ user.description }}</p>
</div>
</div>
</template>
@@ -179,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;
@@ -188,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;
@@ -278,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/i18n/messages.js b/src/i18n/messages.js
index 577aaa30..93be30bc 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -358,7 +358,8 @@ const en = {
fullname: 'Display name',
email: 'Email',
bio: 'Bio',
- password_confirm: 'Password confirmation'
+ password_confirm: 'Password confirmation',
+ token: 'Invite token'
},
post_status: {
posting: 'Posting',
@@ -1647,7 +1648,8 @@ const ru = {
fullname: 'Отображаемое имя',
email: 'Email',
bio: 'Описание',
- password_confirm: 'Подтверждение пароля'
+ password_confirm: 'Подтверждение пароля',
+ token: 'Код приглашения'
},
post_status: {
posting: 'Отправляется',
diff --git a/src/main.js b/src/main.js
index bacd7f6d..cb53edd3 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'
]
}
@@ -79,11 +80,12 @@ const i18n = new VueI18n({
window.fetch('/api/statusnet/config.json')
.then((res) => res.json())
.then((data) => {
- const {name, closed: registrationClosed, textlimit} = data.site
+ const {name, closed: registrationClosed, textlimit, server} = data.site
store.dispatch('setOption', { name: 'name', value: name })
store.dispatch('setOption', { name: 'registrationOpen', value: (registrationClosed === '0') })
store.dispatch('setOption', { name: 'textlimit', value: parseInt(textlimit) })
+ store.dispatch('setOption', { name: 'server', value: server })
})
window.fetch('/static/config.json')
@@ -119,6 +121,7 @@ window.fetch('/static/config.json')
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
{ name: 'settings', path: '/settings', component: Settings },
{ name: 'registration', path: '/registration', component: Registration },
+ { name: 'registration', path: '/registration/:token', component: Registration },
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
{ name: 'user-settings', path: '/user-settings', component: UserSettings }
]
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/api/api.service.js b/src/services/api/api.service.js
index adf598b7..13cc4796 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -159,6 +159,7 @@ const updateProfile = ({credentials, params}) => {
// bio
// homepage
// location
+// token
const register = (params) => {
const form = new FormData()
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
+}