Merge remote-tracking branch 'upstream/develop' into shigusegubu

* upstream/develop:
  check for user before checking users props
  Set hide_follows and hide_followers settings when parsing Mastodon format
  all the manual fixes
  fix merge conflict
  fix hot reload always reloading the page
  Use target from the settings
  preserve formatting of content
  add unit tests
  update regex for commit hash
  eslint --fix --ext .js,.vue src
  npm eslint --fix .
  Support compositionupdate event to properly show autocomplete popup for IMEs and android
  place scope selector on the left consistently
  hide text format when only plaintext is available
  update test for clearTimeline action
  make sure that user timelines are empty when opening profile page
  clear userId property of timeline by default in clearTimeline action
  Revoke oAuth token
  Update oc.json
This commit is contained in:
Henry Jameson 2019-07-08 09:06:20 +03:00
commit abf36dc466
152 changed files with 5445 additions and 2648 deletions

View file

@ -21,26 +21,6 @@ module.exports = {
'generator-star-spacing': 0, 'generator-star-spacing': 0,
// allow debugger during development // allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
// Webpack 4 update commit, most of these probably should be fixed and removed in a separate MR 'vue/require-prop-types': 0
// A lot of errors come from .vue files that are now properly linted
'vue/valid-v-if': 1,
'vue/use-v-on-exact': 1,
'vue/no-parsing-error': 1,
'vue/require-v-for-key': 1,
'vue/valid-v-for': 1,
'vue/require-prop-types': 1,
'vue/no-use-v-if-with-v-for': 1,
'indent': 1,
'import/first': 1,
'object-curly-spacing': 1,
'prefer-promise-reject-errors': 1,
'eol-last': 1,
'no-return-await': 1,
'no-multi-spaces': 1,
'no-trailing-spaces': 1,
'no-unused-expressions': 1,
'no-mixed-operators': 1,
'camelcase': 1,
'no-multiple-empty-lines': 1
} }
} }

View file

@ -31,8 +31,13 @@ var hotMiddleware = require('webpack-hot-middleware')(compiler)
// force page reload when html-webpack-plugin template changes // force page reload when html-webpack-plugin template changes
compiler.plugin('compilation', function (compilation) { compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
hotMiddleware.publish({ action: 'reload' }) // FIXME: This supposed to reload whole page when index.html is changed,
cb() // however now it reloads entire page on every breath, i suppose the order
// of plugins changed or something. It's a minor thing and douesn't hurt
// disabling it, constant reloads hurt much more
// hotMiddleware.publish({ action: 'reload' })
// cb()
}) })
}) })

View file

@ -48,6 +48,11 @@ module.exports = {
changeOrigin: true, changeOrigin: true,
cookieDomainRewrite: 'localhost', cookieDomainRewrite: 'localhost',
ws: true ws: true
},
'/oauth/revoke': {
target,
changeOrigin: true,
cookieDomainRewrite: 'localhost'
} }
}, },
// CSS Sourcemaps off by default because relative paths are "buggy" // CSS Sourcemaps off by default because relative paths are "buggy"

View file

@ -1,53 +1,111 @@
<template> <template>
<div id="app" v-bind:style="bgAppStyle"> <div
<div class="app-bg-wrapper" v-bind:style="bgStyle"></div> id="app"
:style="bgAppStyle"
>
<div
class="app-bg-wrapper"
:style="bgStyle"
/>
<MobileNav v-if="isMobileLayout" /> <MobileNav v-if="isMobileLayout" />
<nav v-else class='nav-bar container' @click="scrollToTop()" id="nav"> <nav
<div class='logo' :style='logoBgStyle'> v-else
<div class='mask' :style='logoMaskStyle'></div> id="nav"
<img :src='logo' :style='logoStyle'> class="nav-bar container"
@click="scrollToTop()"
>
<div
class="logo"
:style="logoBgStyle"
>
<div
class="mask"
:style="logoMaskStyle"
/>
<img
:src="logo"
:style="logoStyle"
>
</div> </div>
<div class='inner-nav'> <div class="inner-nav">
<div class='item'> <div class="item">
<router-link class="site-name" :to="{ name: 'root' }" active-class="home">{{sitename}}</router-link> <router-link
class="site-name"
:to="{ name: 'root' }"
active-class="home"
>
{{ sitename }}
</router-link>
</div> </div>
<div class='item right'> <div class="item right">
<user-finder class="button-icon nav-icon mobile-hidden" @toggled="onFinderToggled"></user-finder> <user-finder
<router-link class="mobile-hidden" :to="{ name: 'settings'}"><i class="button-icon icon-cog nav-icon" :title="$t('nav.preferences')"></i></router-link> class="button-icon nav-icon mobile-hidden"
<a href="#" class="mobile-hidden" v-if="currentUser" @click.prevent="logout"><i class="button-icon icon-logout nav-icon" :title="$t('login.logout')"></i></a> @toggled="onFinderToggled"
/>
<router-link
class="mobile-hidden"
:to="{ name: 'settings'}"
>
<i
class="button-icon icon-cog nav-icon"
:title="$t('nav.preferences')"
/>
</router-link>
<a
v-if="currentUser"
href="#"
class="mobile-hidden"
@click.prevent="logout"
><i
class="button-icon icon-logout nav-icon"
:title="$t('login.logout')"
/></a>
</div> </div>
</div> </div>
</nav> </nav>
<div class="container" id="content"> <div
id="content"
class="container"
>
<div class="sidebar-flexer mobile-hidden"> <div class="sidebar-flexer mobile-hidden">
<div class="sidebar-bounds"> <div class="sidebar-bounds">
<div class="sidebar-scroller"> <div class="sidebar-scroller">
<div class="sidebar"> <div class="sidebar">
<user-panel></user-panel> <user-panel />
<div v-if="!isMobileLayout"> <div v-if="!isMobileLayout">
<nav-panel></nav-panel> <nav-panel />
<instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel> <instance-specific-panel v-if="showInstanceSpecificPanel" />
<features-panel v-if="!currentUser && showFeaturesPanel"></features-panel> <features-panel v-if="!currentUser && showFeaturesPanel" />
<who-to-follow-panel v-if="currentUser && suggestionsEnabled"></who-to-follow-panel> <who-to-follow-panel v-if="currentUser && suggestionsEnabled" />
<notifications v-if="currentUser"></notifications> <notifications v-if="currentUser" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="main"> <div class="main">
<div v-if="!currentUser" class="login-hint panel panel-default"> <div
<router-link :to="{ name: 'login' }" class="panel-body"> v-if="!currentUser"
class="login-hint panel panel-default"
>
<router-link
:to="{ name: 'login' }"
class="panel-body"
>
{{ $t("login.hint") }} {{ $t("login.hint") }}
</router-link> </router-link>
</div> </div>
<transition name="fade"> <transition name="fade">
<router-view></router-view> <router-view />
</transition> </transition>
</div> </div>
<media-modal></media-modal> <media-modal />
</div> </div>
<chat-panel :floating="true" v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel> <chat-panel
v-if="currentUser && chat"
:floating="true"
class="floating-chat mobile-hidden"
/>
<UserReportingModal /> <UserReportingModal />
<portal-target name="modal" /> <portal-target name="modal" />
</div> </div>

View file

@ -1,8 +1,8 @@
<template> <template>
<div class="sidebar"> <div class="sidebar">
<instance-specific-panel></instance-specific-panel> <instance-specific-panel />
<features-panel v-if="showFeaturesPanel"></features-panel> <features-panel v-if="showFeaturesPanel" />
<terms-of-service-panel></terms-of-service-panel> <terms-of-service-panel />
</div> </div>
</template> </template>

View file

@ -1,54 +1,106 @@
<template> <template>
<div v-if="usePlaceHolder" @click="openModal"> <div
<a class="placeholder" v-if="usePlaceHolder"
@click="openModal"
>
<a
v-if="type !== 'html'" v-if="type !== 'html'"
target="_blank" :href="attachment.url" class="placeholder"
target="_blank"
:href="attachment.url"
> >
[{{ nsfw ? "NSFW/" : "" }}{{ type.toUpperCase() }}] [{{ nsfw ? "NSFW/" : "" }}{{ type.toUpperCase() }}]
</a> </a>
</div> </div>
<div <div
v-else class="attachment" v-else
:class="{[type]: true, loading, 'fullwidth': fullwidth, 'nsfw-placeholder': hidden}"
v-show="!isEmpty" v-show="!isEmpty"
class="attachment"
:class="{[type]: true, loading, 'fullwidth': fullwidth, 'nsfw-placeholder': hidden}"
> >
<a class="image-attachment" v-if="hidden" :href="attachment.url" @click.prevent="toggleHidden"> <a
<img class="nsfw" :key="nsfwImage" :src="nsfwImage" :class="{'small': isSmall}"/> v-if="hidden"
<i v-if="type === 'video'" class="play-icon icon-play-circled"></i> class="image-attachment"
:href="attachment.url"
@click.prevent="toggleHidden"
>
<img
:key="nsfwImage"
class="nsfw"
:src="nsfwImage"
:class="{'small': isSmall}"
>
<i
v-if="type === 'video'"
class="play-icon icon-play-circled"
/>
</a> </a>
<div class="hider" v-if="nsfw && hideNsfwLocal && !hidden"> <div
<a href="#" @click.prevent="toggleHidden">Hide</a> v-if="nsfw && hideNsfwLocal && !hidden"
class="hider"
>
<a
href="#"
@click.prevent="toggleHidden"
>Hide</a>
</div> </div>
<a v-if="type === 'image' && (!hidden || preloadImage)" <a
@click="openModal" v-if="type === 'image' && (!hidden || preloadImage)"
class="image-attachment" class="image-attachment"
:class="{'hidden': hidden && preloadImage }" :class="{'hidden': hidden && preloadImage }"
:href="attachment.url" target="_blank" :href="attachment.url"
target="_blank"
:title="attachment.description" :title="attachment.description"
@click="openModal"
> >
<StillImage :referrerpolicy="referrerpolicy" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/> <StillImage
:referrerpolicy="referrerpolicy"
:mimetype="attachment.mimetype"
:src="attachment.large_thumb_url || attachment.url"
/>
</a> </a>
<a class="video-container" <a
@click="openModal"
v-if="type === 'video' && !hidden" v-if="type === 'video' && !hidden"
class="video-container"
:class="{'small': isSmall}" :class="{'small': isSmall}"
:href="allowPlay ? undefined : attachment.url" :href="allowPlay ? undefined : attachment.url"
@click="openModal"
> >
<VideoAttachment class="video" :attachment="attachment" :controls="allowPlay" /> <VideoAttachment
<i v-if="!allowPlay" class="play-icon icon-play-circled"></i> class="video"
:attachment="attachment"
:controls="allowPlay"
/>
<i
v-if="!allowPlay"
class="play-icon icon-play-circled"
/>
</a> </a>
<audio v-if="type === 'audio'" :src="attachment.url" controls></audio> <audio
v-if="type === 'audio'"
:src="attachment.url"
controls
/>
<div @click.prevent="linkClicked" v-if="type === 'html' && attachment.oembed" class="oembed"> <div
<div v-if="attachment.thumb_url" class="image"> v-if="type === 'html' && attachment.oembed"
<img :src="attachment.thumb_url"/> class="oembed"
@click.prevent="linkClicked"
>
<div
v-if="attachment.thumb_url"
class="image"
>
<img :src="attachment.thumb_url">
</div> </div>
<div class="text"> <div class="text">
<!-- eslint-disable vue/no-v-html -->
<h1><a :href="attachment.url">{{ attachment.oembed.title }}</a></h1> <h1><a :href="attachment.url">{{ attachment.oembed.title }}</a></h1>
<div v-html="attachment.oembed.oembedHTML"></div> <div v-html="attachment.oembed.oembedHTML" />
<!-- eslint-enabled vue/no-v-html -->
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,8 +1,22 @@
<template> <template>
<div class="autosuggest" v-click-outside="onClickOutside"> <div
<input v-model="term" :placeholder="placeholder" @click="onInputClick" class="autosuggest-input" /> v-click-outside="onClickOutside"
<div class="autosuggest-results" v-if="resultsVisible && filtered.length > 0"> class="autosuggest"
<slot v-for="item in filtered" :item="item" /> >
<input
v-model="term"
:placeholder="placeholder"
class="autosuggest-input"
@click="onInputClick"
>
<div
v-if="resultsVisible && filtered.length > 0"
class="autosuggest-results"
>
<slot
v-for="item in filtered"
:item="item"
/>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,12 +1,15 @@
<template> <template>
<div class="avatars"> <div class="avatars">
<router-link <router-link
:to="userProfileLink(user)"
class="avatars-item"
v-for="user in slicedUsers" v-for="user in slicedUsers"
:key="user.id" :key="user.id"
:to="userProfileLink(user)"
class="avatars-item"
> >
<UserAvatar :user="user" class="avatar-small" /> <UserAvatar
:user="user"
class="avatar-small"
/>
</router-link> </router-link>
</div> </div>
</template> </template>

View file

@ -7,20 +7,45 @@
@click.prevent.native="toggleUserExpanded" @click.prevent.native="toggleUserExpanded"
/> />
</router-link> </router-link>
<div class="basic-user-card-expanded-content" v-if="userExpanded"> <div
<UserCard :user="user" :rounded="true" :bordered="true"/> v-if="userExpanded"
class="basic-user-card-expanded-content"
>
<UserCard
:user="user"
:rounded="true"
:bordered="true"
/>
</div> </div>
<div class="basic-user-card-collapsed-content" v-else> <div
<div :title="user.name" class="basic-user-card-user-name"> v-else
<span v-if="user.name_html" class="basic-user-card-user-name-value" v-html="user.name_html"></span> class="basic-user-card-collapsed-content"
<span v-else class="basic-user-card-user-name-value">{{ user.name }}</span> >
<div
:title="user.name"
class="basic-user-card-user-name"
>
<!-- eslint-disable vue/no-v-html -->
<span
v-if="user.name_html"
class="basic-user-card-user-name-value"
v-html="user.name_html"
/>
<!-- eslint-enable vue/no-v-html -->
<span
v-else
class="basic-user-card-user-name-value"
>{{ user.name }}</span>
</div> </div>
<div> <div>
<router-link class="basic-user-card-screen-name" :to="userProfileLink(user)"> <router-link
class="basic-user-card-screen-name"
:to="userProfileLink(user)"
>
@{{ user.screen_name }} @{{ user.screen_name }}
</router-link> </router-link>
</div> </div>
<slot></slot> <slot />
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,7 +1,12 @@
<template> <template>
<basic-user-card :user="user"> <basic-user-card :user="user">
<div class="block-card-content-container"> <div class="block-card-content-container">
<button class="btn btn-default" @click="unblockUser" :disabled="progress" v-if="blocked"> <button
v-if="blocked"
class="btn btn-default"
:disabled="progress"
@click="unblockUser"
>
<template v-if="progress"> <template v-if="progress">
{{ $t('user_card.unblock_progress') }} {{ $t('user_card.unblock_progress') }}
</template> </template>
@ -9,7 +14,12 @@
{{ $t('user_card.unblock') }} {{ $t('user_card.unblock') }}
</template> </template>
</button> </button>
<button class="btn btn-default" @click="blockUser" :disabled="progress" v-else> <button
v-else
class="btn btn-default"
:disabled="progress"
@click="blockUser"
>
<template v-if="progress"> <template v-if="progress">
{{ $t('user_card.block_progress') }} {{ $t('user_card.block_progress') }}
</template> </template>

View file

@ -1,21 +1,39 @@
<template> <template>
<div class="chat-panel" v-if="!this.collapsed || !this.floating"> <div
v-if="!collapsed || !floating"
class="chat-panel"
>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading timeline-heading" :class="{ 'chat-heading': floating }" @click.stop.prevent="togglePanel"> <div
class="panel-heading timeline-heading"
:class="{ 'chat-heading': floating }"
@click.stop.prevent="togglePanel"
>
<div class="title"> <div class="title">
<span>{{ $t('chat.title') }}</span> <span>{{ $t('chat.title') }}</span>
<i class="icon-cancel" v-if="floating"></i> <i
v-if="floating"
class="icon-cancel"
/>
</div> </div>
</div> </div>
<div class="chat-window" v-chat-scroll> <div
<div class="chat-message" v-for="message in messages" :key="message.id"> v-chat-scroll
class="chat-window"
>
<div
v-for="message in messages"
:key="message.id"
class="chat-message"
>
<span class="chat-avatar"> <span class="chat-avatar">
<img :src="message.author.avatar" /> <img :src="message.author.avatar">
</span> </span>
<div class="chat-content"> <div class="chat-content">
<router-link <router-link
class="chat-name" class="chat-name"
:to="userProfileLink(message.author)"> :to="userProfileLink(message.author)"
>
{{ message.author.username }} {{ message.author.username }}
</router-link> </router-link>
<br> <br>
@ -26,15 +44,26 @@
</div> </div>
</div> </div>
<div class="chat-input"> <div class="chat-input">
<textarea @keyup.enter="submit(currentMessage)" v-model="currentMessage" class="chat-input-textarea" rows="1"></textarea> <textarea
v-model="currentMessage"
class="chat-input-textarea"
rows="1"
@keyup.enter="submit(currentMessage)"
/>
</div> </div>
</div> </div>
</div> </div>
<div v-else class="chat-panel"> <div
v-else
class="chat-panel"
>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading stub timeline-heading chat-heading" @click.stop.prevent="togglePanel"> <div
class="panel-heading stub timeline-heading chat-heading"
@click.stop.prevent="togglePanel"
>
<div class="title"> <div class="title">
<i class="icon-comment-empty"></i> <i class="icon-comment-empty" />
{{ $t('chat.title') }} {{ $t('chat.title') }}
</div> </div>
</div> </div>

View file

@ -1,8 +1,13 @@
<template> <template>
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" :checked="checked" @change="$emit('change', $event.target.checked)" :indeterminate.prop="indeterminate"> <input
type="checkbox"
:checked="checked"
:indeterminate.prop="indeterminate"
@change="$emit('change', $event.target.checked)"
>
<i class="checkbox-indicator" /> <i class="checkbox-indicator" />
<span v-if="!!$slots.default"><slot></slot></span> <span v-if="!!$slots.default"><slot /></span>
</label> </label>
</template> </template>

View file

@ -1,16 +1,27 @@
<template> <template>
<div class="color-control style-control" :class="{ disabled: !present || disabled }"> <div
<label :for="name" class="label"> class="color-control style-control"
:class="{ disabled: !present || disabled }"
>
<label
:for="name"
class="label"
>
{{ label }} {{ label }}
</label> </label>
<input <input
v-if="typeof fallback !== 'undefined'" v-if="typeof fallback !== 'undefined'"
class="opt exlcude-disabled"
:id="name + '-o'" :id="name + '-o'"
class="opt exlcude-disabled"
type="checkbox" type="checkbox"
:checked="present" :checked="present"
@input="$emit('input', typeof value === 'undefined' ? fallback : undefined)"> @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
<label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label> >
<label
v-if="typeof fallback !== 'undefined'"
class="opt-l"
:for="name + '-o'"
/>
<input <input
:id="name" :id="name"
class="color-input" class="color-input"

View file

@ -1,6 +1,12 @@
<template> <template>
<span v-if="contrast" class="contrast-ratio"> <span
<span :title="hint" class="rating"> v-if="contrast"
class="contrast-ratio"
>
<span
:title="hint"
class="rating"
>
<span v-if="contrast.aaa"> <span v-if="contrast.aaa">
<i class="icon-thumbs-up-alt" /> <i class="icon-thumbs-up-alt" />
</span> </span>
@ -11,7 +17,11 @@
<i class="icon-attention" /> <i class="icon-attention" />
</span> </span>
</span> </span>
<span class="rating" v-if="contrast && large" :title="hint_18pt"> <span
v-if="contrast && large"
class="rating"
:title="hint_18pt"
>
<span v-if="contrast.laaa"> <span v-if="contrast.laaa">
<i class="icon-thumbs-up-alt" /> <i class="icon-thumbs-up-alt" />
</span> </span>

View file

@ -1,9 +1,9 @@
<template> <template>
<conversation <conversation
:collapsable="false" :collapsable="false"
isPage="true" is-page="true"
:statusoid="statusoid" :statusoid="statusoid"
></conversation> />
</template> </template>
<script src="./conversation-page.js"></script> <script src="./conversation-page.js"></script>

View file

@ -86,6 +86,7 @@ const conversation = {
}, },
replies () { replies () {
let i = 1 let i = 1
// eslint-disable-next-line camelcase
return reduce(this.conversation, (result, { id, in_reply_to_status_id }) => { return reduce(this.conversation, (result, { id, in_reply_to_status_id }) => {
/* eslint-disable camelcase */ /* eslint-disable camelcase */
const irid = in_reply_to_status_id const irid = in_reply_to_status_id

View file

@ -1,25 +1,34 @@
<template> <template>
<div class="timeline panel-default" :class="[isExpanded ? 'panel' : 'panel-disabled']"> <div
<div v-if="isExpanded" class="panel-heading conversation-heading"> class="timeline panel-default"
:class="[isExpanded ? 'panel' : 'panel-disabled']"
>
<div
v-if="isExpanded"
class="panel-heading conversation-heading"
>
<span class="title"> {{ $t('timeline.conversation') }} </span> <span class="title"> {{ $t('timeline.conversation') }} </span>
<span v-if="collapsable"> <span v-if="collapsable">
<a href="#" @click.prevent="toggleExpanded">{{ $t('timeline.collapse') }}</a> <a
href="#"
@click.prevent="toggleExpanded"
>{{ $t('timeline.collapse') }}</a>
</span> </span>
</div> </div>
<status <status
v-for="status in conversation" v-for="status in conversation"
@goto="setHighlight"
@toggleExpanded="toggleExpanded"
:key="status.id" :key="status.id"
:inlineExpanded="collapsable && isExpanded" :inline-expanded="collapsable && isExpanded"
:statusoid="status" :statusoid="status"
:expandable='!isExpanded' :expandable="!isExpanded"
:showPinned="showPinned" :show-pinned="showPinned"
:focused="focused(status.id)" :focused="focused(status.id)"
:inConversation="isExpanded" :in-conversation="isExpanded"
:highlight="getHighlight()" :highlight="getHighlight()"
:replies="getReplies(status.id)" :replies="getReplies(status.id)"
class="status-fadein panel-body" class="status-fadein panel-body"
@goto="setHighlight"
@toggleExpanded="toggleExpanded"
/> />
</div> </div>
</template> </template>

View file

@ -1,16 +1,22 @@
<template> <template>
<span v-bind:class="{ 'dark-overlay': darkOverlay }" @click.self.stop='onCancel()'> <span
<div class="dialog-modal panel panel-default" @click.stop=''> :class="{ 'dark-overlay': darkOverlay }"
@click.self.stop="onCancel()"
>
<div
class="dialog-modal panel panel-default"
@click.stop=""
>
<div class="panel-heading dialog-modal-heading"> <div class="panel-heading dialog-modal-heading">
<div class="title"> <div class="title">
<slot name="header"></slot> <slot name="header" />
</div> </div>
</div> </div>
<div class="dialog-modal-content"> <div class="dialog-modal-content">
<slot name="default"></slot> <slot name="default" />
</div> </div>
<div class="dialog-modal-footer user-interactions panel-footer"> <div class="dialog-modal-footer user-interactions panel-footer">
<slot name="footer"></slot> <slot name="footer" />
</div> </div>
</div> </div>
</span> </span>

View file

@ -1,5 +1,9 @@
<template> <template>
<Timeline :title="$t('nav.dms')" v-bind:timeline="timeline" v-bind:timeline-name="'dms'"/> <Timeline
:title="$t('nav.dms')"
:timeline="timeline"
:timeline-name="'dms'"
/>
</template> </template>
<script src="./dm_timeline.js"></script> <script src="./dm_timeline.js"></script>

View file

@ -105,6 +105,7 @@ const EmojiInput = {
input.elm.addEventListener('keyup', this.onKeyUp) input.elm.addEventListener('keyup', this.onKeyUp)
input.elm.addEventListener('keydown', this.onKeyDown) input.elm.addEventListener('keydown', this.onKeyDown)
input.elm.addEventListener('transitionend', this.onTransition) input.elm.addEventListener('transitionend', this.onTransition)
input.elm.addEventListener('compositionupdate', this.onCompositionUpdate)
}, },
unmounted () { unmounted () {
const { input } = this const { input } = this
@ -115,6 +116,7 @@ const EmojiInput = {
input.elm.removeEventListener('keyup', this.onKeyUp) input.elm.removeEventListener('keyup', this.onKeyUp)
input.elm.removeEventListener('keydown', this.onKeyDown) input.elm.removeEventListener('keydown', this.onKeyDown)
input.elm.removeEventListener('transitionend', this.onTransition) input.elm.removeEventListener('transitionend', this.onTransition)
input.elm.removeEventListener('compositionupdate', this.onCompositionUpdate)
} }
}, },
methods: { methods: {
@ -225,6 +227,12 @@ const EmojiInput = {
} }
}, },
onInput (e) { onInput (e) {
this.setCaret(e)
this.$emit('input', e.target.value)
},
onCompositionUpdate (e) {
this.setCaret(e)
this.resize()
this.$emit('input', e.target.value) this.$emit('input', e.target.value)
}, },
setCaret ({ target: { selectionStart } }) { setCaret ({ target: { selectionStart } }) {

View file

@ -1,17 +1,24 @@
<template> <template>
<div class="emoji-input"> <div class="emoji-input">
<slot></slot> <slot />
<div ref="panel" class="autocomplete-panel" :class="{ hide: !showPopup }"> <div
ref="panel"
class="autocomplete-panel"
:class="{ hide: !showPopup }"
>
<div class="autocomplete-panel-body"> <div class="autocomplete-panel-body">
<div <div
v-for="(suggestion, index) in suggestions" v-for="(suggestion, index) in suggestions"
:key="index" :key="index"
@click.stop.prevent="onClick($event, suggestion)"
class="autocomplete-item" class="autocomplete-item"
:class="{ highlighted: suggestion.highlighted }" :class="{ highlighted: suggestion.highlighted }"
@click.stop.prevent="onClick($event, suggestion)"
> >
<span class="image"> <span class="image">
<img v-if="suggestion.img":src="suggestion.img" /> <img
v-if="suggestion.img"
:src="suggestion.img"
>
<span v-else>{{ suggestion.replacement }}</span> <span v-else>{{ suggestion.replacement }}</span>
</span> </span>
<div class="label"> <div class="label">
@ -103,7 +110,6 @@
} }
} }
input, textarea { input, textarea {
flex: 1 0 auto; flex: 1 0 auto;
} }

View file

@ -1,10 +1,25 @@
<template> <template>
<div class="import-export-container"> <div class="import-export-container">
<slot name="before" /> <slot name="before" />
<button class="btn" @click="exportData">{{ exportLabel }}</button> <button
<button class="btn" @click="importData">{{ importLabel }}</button> class="btn"
@click="exportData"
>
{{ exportLabel }}
</button>
<button
class="btn"
@click="importData"
>
{{ importLabel }}
</button>
<slot name="afterButtons" /> <slot name="afterButtons" />
<p v-if="importFailed" class="alert error">{{ importFailedText }}</p> <p
v-if="importFailed"
class="alert error"
>
{{ importFailedText }}
</p>
<slot name="afterError" /> <slot name="afterError" />
</div> </div>
</template> </template>

View file

@ -1,10 +1,16 @@
<template> <template>
<div class="exporter"> <div class="exporter">
<div v-if="processing"> <div v-if="processing">
<i class="icon-spin4 animate-spin exporter-processing"></i> <i class="icon-spin4 animate-spin exporter-processing" />
<span>{{ processingMessage }}</span> <span>{{ processingMessage }}</span>
</div> </div>
<button class="btn btn-default" @click="process" v-else>{{exportButtonLabel}}</button> <button
v-else
class="btn btn-default"
@click="process"
>
{{ exportButtonLabel }}
</button>
</div> </div>
</template> </template>

View file

@ -1,9 +1,8 @@
<template> <template>
<Popper <Popper
trigger="click"
@hide='showDropDown = false'
append-to-body
v-if="enabled && showPopper" v-if="enabled && showPopper"
trigger="click"
append-to-body
:options="{ :options="{
placement: 'top', placement: 'top',
modifiers: { modifiers: {
@ -11,22 +10,42 @@
offset: { offset: '0, 5px' }, offset: { offset: '0, 5px' },
} }
}" }"
@hide="showDropDown = false"
> >
<div class="popper-wrapper"> <div class="popper-wrapper">
<div class="dropdown-menu"> <div class="dropdown-menu">
<button class="dropdown-item dropdown-item-icon" @click.prevent="pinStatus" v-if="!status.pinned && canPin"> <button
<i class="icon-pin"></i><span>{{$t("status.pin")}}</span> v-if="!status.pinned && canPin"
class="dropdown-item dropdown-item-icon"
@click.prevent="pinStatus"
>
<i class="icon-pin" /><span>{{ $t("status.pin") }}</span>
</button> </button>
<button class="dropdown-item dropdown-item-icon" @click.prevent="unpinStatus" v-if="status.pinned && canPin"> <button
<i class="icon-pin"></i><span>{{$t("status.unpin")}}</span> v-if="status.pinned && canPin"
class="dropdown-item dropdown-item-icon"
@click.prevent="unpinStatus"
>
<i class="icon-pin" /><span>{{ $t("status.unpin") }}</span>
</button> </button>
<button class="dropdown-item dropdown-item-icon" @click.prevent="deleteStatus" v-if="canDelete"> <button
<i class="icon-cancel"></i><span>{{$t("status.delete")}}</span> v-if="canDelete"
class="dropdown-item dropdown-item-icon"
@click.prevent="deleteStatus"
>
<i class="icon-cancel" /><span>{{ $t("status.delete") }}</span>
</button> </button>
</div> </div>
</div> </div>
<div class="button-icon" slot="reference" @click="toggleMenu"> <div
<i class='icon-ellipsis' :class="{'icon-clicked': showDropDown}"></i> slot="reference"
class="button-icon"
@click="toggleMenu"
>
<i
class="icon-ellipsis"
:class="{'icon-clicked': showDropDown}"
/>
</div> </div>
</Popper> </Popper>
</template> </template>

View file

@ -1,11 +1,20 @@
<template> <template>
<div v-if="loggedIn"> <div v-if="loggedIn">
<i :class='classes' class='button-icon favorite-button fav-active' @click.prevent='favorite()' :title="$t('tool_tip.favorite')"/> <i
<span v-if='!hidePostStatsLocal && status.fave_num > 0'>{{status.fave_num}}</span> :class="classes"
class="button-icon favorite-button fav-active"
:title="$t('tool_tip.favorite')"
@click.prevent="favorite()"
/>
<span v-if="!hidePostStatsLocal && status.fave_num > 0">{{ status.fave_num }}</span>
</div> </div>
<div v-else> <div v-else>
<i :class='classes' class='button-icon favorite-button' :title="$t('tool_tip.favorite')"/> <i
<span v-if='!hidePostStatsLocal && status.fave_num > 0'>{{status.fave_num}}</span> :class="classes"
class="button-icon favorite-button"
:title="$t('tool_tip.favorite')"
/>
<span v-if="!hidePostStatsLocal && status.fave_num > 0">{{ status.fave_num }}</span>
</div> </div>
</template> </template>

View file

@ -8,10 +8,18 @@
</div> </div>
<div class="panel-body features-panel"> <div class="panel-body features-panel">
<ul> <ul>
<li v-if="chat">{{$t('features_panel.chat')}}</li> <li v-if="chat">
<li v-if="gopher">{{$t('features_panel.gopher')}}</li> {{ $t('features_panel.chat') }}
<li v-if="whoToFollow">{{$t('features_panel.who_to_follow')}}</li> </li>
<li v-if="mediaProxy">{{$t('features_panel.media_proxy')}}</li> <li v-if="gopher">
{{ $t('features_panel.gopher') }}
</li>
<li v-if="whoToFollow">
{{ $t('features_panel.who_to_follow') }}
</li>
<li v-if="mediaProxy">
{{ $t('features_panel.media_proxy') }}
</li>
<li>{{ $t('features_panel.scope_options') }}</li> <li>{{ $t('features_panel.scope_options') }}</li>
<li>{{ $t('features_panel.text_limit') }} = {{ textlimit }}</li> <li>{{ $t('features_panel.text_limit') }} = {{ textlimit }}</li>
</ul> </ul>

View file

@ -1,11 +1,17 @@
<template> <template>
<basic-user-card :user="user"> <basic-user-card :user="user">
<div class="follow-card-content-container"> <div class="follow-card-content-container">
<span class="faint" v-if="!noFollowsYou && user.follows_you"> <span
v-if="!noFollowsYou && user.follows_you"
class="faint"
>
{{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }} {{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }}
</span> </span>
<template v-if="!loggedIn"> <template v-if="!loggedIn">
<div class="follow-card-follow-button" v-if="!user.following"> <div
v-if="!user.following"
class="follow-card-follow-button"
>
<RemoteFollow :user="user" /> <RemoteFollow :user="user" />
</div> </div>
</template> </template>
@ -13,9 +19,9 @@
<button <button
v-if="!user.following" v-if="!user.following"
class="btn btn-default follow-card-follow-button" class="btn btn-default follow-card-follow-button"
@click="followUser"
:disabled="inProgress" :disabled="inProgress"
:title="requestSent ? $t('user_card.follow_again') : ''" :title="requestSent ? $t('user_card.follow_again') : ''"
@click="followUser"
> >
<template v-if="inProgress"> <template v-if="inProgress">
{{ $t('user_card.follow_progress') }} {{ $t('user_card.follow_progress') }}
@ -27,7 +33,12 @@
{{ $t('user_card.follow') }} {{ $t('user_card.follow') }}
</template> </template>
</button> </button>
<button v-else class="btn btn-default follow-card-follow-button pressed" @click="unfollowUser" :disabled="inProgress"> <button
v-else
class="btn btn-default follow-card-follow-button pressed"
:disabled="inProgress"
@click="unfollowUser"
>
<template v-if="inProgress"> <template v-if="inProgress">
{{ $t('user_card.follow_progress') }} {{ $t('user_card.follow_progress') }}
</template> </template>

View file

@ -1,8 +1,18 @@
<template> <template>
<basic-user-card :user="user"> <basic-user-card :user="user">
<div class="follow-request-card-content-container"> <div class="follow-request-card-content-container">
<button class="btn btn-default" @click="approveUser">{{ $t('user_card.approve') }}</button> <button
<button class="btn btn-default" @click="denyUser">{{ $t('user_card.deny') }}</button> class="btn btn-default"
@click="approveUser"
>
{{ $t('user_card.approve') }}
</button>
<button
class="btn btn-default"
@click="denyUser"
>
{{ $t('user_card.deny') }}
</button>
</div> </div>
</basic-user-card> </basic-user-card>
</template> </template>

View file

@ -4,7 +4,12 @@
{{ $t('nav.friend_requests') }} {{ $t('nav.friend_requests') }}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<FollowRequestCard v-for="request in requests" :key="request.id" :user="request" class="list-item"/> <FollowRequestCard
v-for="request in requests"
:key="request.id"
:user="request"
class="list-item"
/>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,23 +1,43 @@
<template> <template>
<div class="font-control style-control" :class="{ custom: isCustom }"> <div
<label :for="preset === 'custom' ? name : name + '-font-switcher'" class="label"> class="font-control style-control"
:class="{ custom: isCustom }"
>
<label
:for="preset === 'custom' ? name : name + '-font-switcher'"
class="label"
>
{{ label }} {{ label }}
</label> </label>
<input <input
v-if="typeof fallback !== 'undefined'" v-if="typeof fallback !== 'undefined'"
:id="name + '-o'"
class="opt exlcude-disabled" class="opt exlcude-disabled"
type="checkbox" type="checkbox"
:id="name + '-o'"
:checked="present" :checked="present"
@input="$emit('input', typeof value === 'undefined' ? fallback : undefined)"> @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
<label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label> >
<label :for="name + '-font-switcher'" class="select" :disabled="!present"> <label
<select v-if="typeof fallback !== 'undefined'"
class="opt-l"
:for="name + '-o'"
/>
<label
:for="name + '-font-switcher'"
class="select"
:disabled="!present" :disabled="!present"
>
<select
:id="name + '-font-switcher'"
v-model="preset" v-model="preset"
:disabled="!present"
class="font-switcher" class="font-switcher"
:id="name + '-font-switcher'"> >
<option v-for="option in availableOptions" :value="option"> <option
v-for="option in availableOptions"
:key="option"
:value="option"
>
{{ option === 'custom' ? $t('settings.style.fonts.custom') : option }} {{ option === 'custom' ? $t('settings.style.fonts.custom') : option }}
</option> </option>
</select> </select>
@ -25,10 +45,11 @@
</label> </label>
<input <input
v-if="isCustom" v-if="isCustom"
:id="name"
v-model="family"
class="custom-font" class="custom-font"
type="text" type="text"
:id="name" >
v-model="family">
</div> </div>
</template> </template>

View file

@ -1,5 +1,9 @@
<template> <template>
<Timeline :title="$t('nav.timeline')" v-bind:timeline="timeline" v-bind:timeline-name="'friends'"/> <Timeline
:title="$t('nav.timeline')"
:timeline="timeline"
:timeline-name="'friends'"
/>
</template> </template>
<script src="./friends_timeline.js"></script> <script src="./friends_timeline.js"></script>

View file

@ -1,13 +1,22 @@
<template> <template>
<div ref="galleryContainer" style="width: 100%;"> <div
<div class="gallery-row" v-for="row in rows" :style="rowHeight(row.length)" :class="{ 'contain-fit': useContainFit, 'cover-fit': !useContainFit }"> ref="galleryContainer"
style="width: 100%;"
>
<div
v-for="(row, index) in rows"
:key="index"
class="gallery-row"
:style="rowHeight(row.length)"
:class="{ 'contain-fit': useContainFit, 'cover-fit': !useContainFit }"
>
<attachment <attachment
v-for="attachment in row" v-for="attachment in row"
:setMedia="setMedia" :key="attachment.id"
:set-media="setMedia"
:nsfw="nsfw" :nsfw="nsfw"
:attachment="attachment" :attachment="attachment"
:allowPlay="false" :allow-play="false"
:key="attachment.id"
/> />
</div> </div>
</div> </div>

View file

@ -2,20 +2,57 @@
<div class="image-cropper"> <div class="image-cropper">
<div v-if="dataUrl"> <div v-if="dataUrl">
<div class="image-cropper-image-container"> <div class="image-cropper-image-container">
<img ref="img" :src="dataUrl" alt="" @load.stop="createCropper" /> <img
ref="img"
:src="dataUrl"
alt=""
@load.stop="createCropper"
>
</div> </div>
<div class="image-cropper-buttons-wrapper"> <div class="image-cropper-buttons-wrapper">
<button class="btn" type="button" :disabled="submitting" @click="submit()" v-text="saveText"></button> <button
<button class="btn" type="button" :disabled="submitting" @click="destroy" v-text="cancelText"></button> class="btn"
<button class="btn" type="button" :disabled="submitting" @click="submit(false)" v-text="saveWithoutCroppingText"></button> type="button"
<i class="icon-spin4 animate-spin" v-if="submitting"></i> :disabled="submitting"
@click="submit()"
v-text="saveText"
/>
<button
class="btn"
type="button"
:disabled="submitting"
@click="destroy"
v-text="cancelText"
/>
<button
class="btn"
type="button"
:disabled="submitting"
@click="submit(false)"
v-text="saveWithoutCroppingText"
/>
<i
v-if="submitting"
class="icon-spin4 animate-spin"
/>
</div> </div>
<div class="alert error" v-if="submitError"> <div
v-if="submitError"
class="alert error"
>
{{ submitErrorMsg }} {{ submitErrorMsg }}
<i class="button-icon icon-cancel" @click="clearError"></i> <i
class="button-icon icon-cancel"
@click="clearError"
/>
</div> </div>
</div> </div>
<input ref="input" type="file" class="image-cropper-img-input" :accept="mimes"> <input
ref="input"
type="file"
class="image-cropper-img-input"
:accept="mimes"
>
</div> </div>
</template> </template>

View file

@ -1,16 +1,35 @@
<template> <template>
<div class="importer"> <div class="importer">
<form> <form>
<input type="file" ref="input" v-on:change="change" /> <input
ref="input"
type="file"
@change="change"
>
</form> </form>
<i class="icon-spin4 animate-spin importer-uploading" v-if="submitting"></i> <i
<button class="btn btn-default" v-else @click="submit">{{submitButtonLabel}}</button> v-if="submitting"
class="icon-spin4 animate-spin importer-uploading"
/>
<button
v-else
class="btn btn-default"
@click="submit"
>
{{ submitButtonLabel }}
</button>
<div v-if="success"> <div v-if="success">
<i class="icon-cross" @click="dismiss"></i> <i
class="icon-cross"
@click="dismiss"
/>
<p>{{ successMessage }}</p> <p>{{ successMessage }}</p>
</div> </div>
<div v-else-if="error"> <div v-else-if="error">
<i class="icon-cross" @click="dismiss"></i> <i
class="icon-cross"
@click="dismiss"
/>
<p>{{ errorMessage }}</p> <p>{{ errorMessage }}</p>
</div> </div>
</div> </div>

View file

@ -1,9 +1,13 @@
<template> <template>
<div v-if="show" class="instance-specific-panel"> <div
v-if="show"
class="instance-specific-panel"
>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-body"> <div class="panel-body">
<div v-html="instanceSpecificPanelContent"> <!-- eslint-disable vue/no-v-html -->
</div> <div v-html="instanceSpecificPanelContent" />
<!-- eslint-enable vue/no-v-html -->
</div> </div>
</div> </div>
</div> </div>

View file

@ -7,17 +7,29 @@
</div> </div>
<tab-switcher <tab-switcher
ref="tabSwitcher" ref="tabSwitcher"
:onSwitch="onModeSwitch" :on-switch="onModeSwitch"
> >
<span data-tab-dummy data-filter="mentions" :label="$t('nav.mentions')"/> <span
<span data-tab-dummy data-filter="likes+repeats" :label="$t('interactions.favs_repeats')"/> data-tab-dummy
<span data-tab-dummy data-filter="follows" :label="$t('interactions.follows')"/> data-filter="mentions"
:label="$t('nav.mentions')"
/>
<span
data-tab-dummy
data-filter="likes+repeats"
:label="$t('interactions.favs_repeats')"
/>
<span
data-tab-dummy
data-filter="follows"
:label="$t('interactions.follows')"
/>
</tab-switcher> </tab-switcher>
<Notifications <Notifications
ref="notifications" ref="notifications"
:noHeading="true" :no-heading="true"
:minimalMode="true" :minimal-mode="true"
:filterMode="filterMode" :filter-mode="filterMode"
/> />
</div> </div>
</template> </template>

View file

@ -3,9 +3,19 @@
<label for="interface-language-switcher"> <label for="interface-language-switcher">
{{ $t('settings.interfaceLanguage') }} {{ $t('settings.interfaceLanguage') }}
</label> </label>
<label for="interface-language-switcher" class='select'> <label
<select id="interface-language-switcher" v-model="language"> for="interface-language-switcher"
<option v-for="(langCode, i) in languageCodes" :value="langCode"> class="select"
>
<select
id="interface-language-switcher"
v-model="language"
>
<option
v-for="(langCode, i) in languageCodes"
:key="langCode"
:value="langCode"
>
{{ languageNames[i] }} {{ languageNames[i] }}
</option> </option>
</select> </select>

View file

@ -1,13 +1,25 @@
<template> <template>
<div> <div>
<a class="link-preview-card" :href="card.url" target="_blank" rel="noopener"> <a
<div class="card-image" :class="{ 'small-image': size === 'small' }" v-if="useImage"> class="link-preview-card"
<img :src="card.image"></img> :href="card.url"
target="_blank"
rel="noopener"
>
<div
v-if="useImage"
class="card-image"
:class="{ 'small-image': size === 'small' }"
>
<img :src="card.image">
</div> </div>
<div class="card-content"> <div class="card-content">
<span class="card-host faint">{{ card.provider_name }}</span> <span class="card-host faint">{{ card.provider_name }}</span>
<h4 class="card-title">{{ card.title }}</h4> <h4 class="card-title">{{ card.title }}</h4>
<p class="card-description" v-if="useDescription">{{ card.description }}</p> <p
v-if="useDescription"
class="card-description"
>{{ card.description }}</p>
</div> </div>
</a> </a>
</div> </div>

View file

@ -1,9 +1,19 @@
<template> <template>
<div class="list"> <div class="list">
<div v-for="item in items" class="list-item" :key="getKey(item)"> <div
<slot name="item" :item="item" /> v-for="item in items"
:key="getKey(item)"
class="list-item"
>
<slot
name="item"
:item="item"
/>
</div> </div>
<div class="list-empty-content faint" v-if="items.length === 0 && !!$slots.empty"> <div
v-if="items.length === 0 && !!$slots.empty"
class="list-empty-content faint"
>
<slot name="empty" /> <slot name="empty" />
</div> </div>
</div> </div>

View file

@ -2,38 +2,62 @@
<div class="login panel panel-default"> <div class="login panel panel-default">
<!-- Default panel contents --> <!-- Default panel contents -->
<div class="panel-heading">{{$t('login.login')}}</div> <div class="panel-heading">
{{ $t('login.login') }}
</div>
<div class="panel-body"> <div class="panel-body">
<form class='login-form' @submit.prevent='submit'> <form
class="login-form"
@submit.prevent="submit"
>
<template v-if="isPasswordAuth"> <template v-if="isPasswordAuth">
<div class='form-group'> <div class="form-group">
<label for='username'>{{$t('login.username')}}</label> <label for="username">{{ $t('login.username') }}</label>
<input :disabled="loggingIn" v-model='user.username' <input
class='form-control' id='username' id="username"
:placeholder="$t('login.placeholder')"> v-model="user.username"
:disabled="loggingIn"
class="form-control"
:placeholder="$t('login.placeholder')"
>
</div> </div>
<div class='form-group'> <div class="form-group">
<label for='password'>{{$t('login.password')}}</label> <label for="password">{{ $t('login.password') }}</label>
<input :disabled="loggingIn" v-model='user.password' <input
ref='passwordInput' class='form-control' id='password' type='password'> id="password"
ref="passwordInput"
v-model="user.password"
:disabled="loggingIn"
class="form-control"
type="password"
>
</div> </div>
</template> </template>
<div class="form-group" v-if="isTokenAuth"> <div
v-if="isTokenAuth"
class="form-group"
>
<p>{{ $t('login.description') }}</p> <p>{{ $t('login.description') }}</p>
</div> </div>
<div class='form-group'> <div class="form-group">
<div class='login-bottom'> <div class="login-bottom">
<div> <div>
<router-link :to="{name: 'registration'}" <router-link
v-if='registrationOpen' v-if="registrationOpen"
class='register'> :to="{name: 'registration'}"
class="register"
>
{{ $t('login.register') }} {{ $t('login.register') }}
</router-link> </router-link>
</div> </div>
<button :disabled="loggingIn" type='submit' class='btn btn-default'> <button
:disabled="loggingIn"
type="submit"
class="btn btn-default"
>
{{ $t('login.login') }} {{ $t('login.login') }}
</button> </button>
</div> </div>
@ -41,10 +65,16 @@
</form> </form>
</div> </div>
<div v-if="error" class='form-group'> <div
<div class='alert error'> v-if="error"
class="form-group"
>
<div class="alert error">
{{ error }} {{ error }}
<i class="button-icon icon-cancel" @click="clearError"></i> <i
class="button-icon icon-cancel"
@click="clearError"
/>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,25 +1,33 @@
<template> <template>
<div class="modal-view media-modal-view" v-if="showing" @click.prevent="hide"> <div
<img class="modal-image" v-if="type === 'image'" :src="currentMedia.url"></img> v-if="showing"
<VideoAttachment class="modal-view media-modal-view"
@click.prevent="hide"
>
<img
v-if="type === 'image'"
class="modal-image" class="modal-image"
:src="currentMedia.url"
>
<VideoAttachment
v-if="type === 'video'" v-if="type === 'video'"
class="modal-image"
:attachment="currentMedia" :attachment="currentMedia"
:controls="true" :controls="true"
@click.stop.native=""> @click.stop.native=""
</VideoAttachment> />
<button <button
v-if="canNavigate"
:title="$t('media_modal.previous')" :title="$t('media_modal.previous')"
class="modal-view-button-arrow modal-view-button-arrow--prev" class="modal-view-button-arrow modal-view-button-arrow--prev"
v-if="canNavigate"
@click.stop.prevent="goPrev" @click.stop.prevent="goPrev"
> >
<i class="icon-left-open arrow-icon" /> <i class="icon-left-open arrow-icon" />
</button> </button>
<button <button
v-if="canNavigate"
:title="$t('media_modal.next')" :title="$t('media_modal.next')"
class="modal-view-button-arrow modal-view-button-arrow--next" class="modal-view-button-arrow modal-view-button-arrow--next"
v-if="canNavigate"
@click.stop.prevent="goNext" @click.stop.prevent="goNext"
> >
<i class="icon-right-open arrow-icon" /> <i class="icon-right-open arrow-icon" />

View file

@ -1,9 +1,29 @@
<template> <template>
<div class="media-upload" @drop.prevent @dragover.prevent="fileDrag" @drop="fileDrop"> <div
<label class="btn btn-default" :title="$t('tool_tip.media_upload')"> class="media-upload"
<i class="icon-spin4 animate-spin" v-if="uploading"></i> @drop.prevent
<i class="icon-upload" v-if="!uploading"></i> @dragover.prevent="fileDrag"
<input type="file" v-if="uploadReady" @change="change" style="position: fixed; top: -100em" multiple="true"></input> @drop="fileDrop"
>
<label
class="btn btn-default"
:title="$t('tool_tip.media_upload')"
>
<i
v-if="uploading"
class="icon-spin4 animate-spin"
/>
<i
v-if="!uploading"
class="icon-upload"
/>
<input
v-if="uploadReady"
type="file"
style="position: fixed; top: -100em"
multiple="true"
@change="change"
>
</label> </label>
</div> </div>
</template> </template>

View file

@ -1,5 +1,9 @@
<template> <template>
<Timeline :title="$t('nav.interactions')" v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/> <Timeline
:title="$t('nav.interactions')"
:timeline="timeline"
:timeline-name="'mentions'"
/>
</template> </template>
<script src="./mentions.js"></script> <script src="./mentions.js"></script>

View file

@ -2,39 +2,62 @@
<div class="login panel panel-default"> <div class="login panel panel-default">
<!-- Default panel contents --> <!-- Default panel contents -->
<div class="panel-heading">{{$t('login.heading.recovery')}}</div> <div class="panel-heading">
{{ $t('login.heading.recovery') }}
<div class="panel-body">
<form class='login-form' @submit.prevent='submit'>
<div class='form-group'>
<label for='code'>{{$t('login.recovery_code')}}</label>
<input v-model='code' class='form-control' id='code'>
</div> </div>
<div class='form-group'> <div class="panel-body">
<div class='login-bottom'> <form
class="login-form"
@submit.prevent="submit"
>
<div class="form-group">
<label for="code">{{ $t('login.recovery_code') }}</label>
<input
id="code"
v-model="code"
class="form-control"
>
</div>
<div class="form-group">
<div class="login-bottom">
<div> <div>
<a href="#" @click.prevent="requireTOTP"> <a
href="#"
@click.prevent="requireTOTP"
>
{{ $t('login.enter_two_factor_code') }} {{ $t('login.enter_two_factor_code') }}
</a> </a>
<br /> <br>
<a href="#" @click.prevent="abortMFA"> <a
href="#"
@click.prevent="abortMFA"
>
{{ $t('general.cancel') }} {{ $t('general.cancel') }}
</a> </a>
</div> </div>
<button type='submit' class='btn btn-default'> <button
type="submit"
class="btn btn-default"
>
{{ $t('general.verify') }} {{ $t('general.verify') }}
</button> </button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<div v-if="error" class='form-group'> <div
<div class='alert error'> v-if="error"
class="form-group"
>
<div class="alert error">
{{ error }} {{ error }}
<i class="button-icon icon-cancel" @click="clearError"></i> <i
class="button-icon icon-cancel"
@click="clearError"
/>
</div> </div>
</div> </div>
</div> </div>

View file

@ -7,26 +7,42 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form class='login-form' @submit.prevent='submit'> <form
<div class='form-group'> class="login-form"
<label for='code'> @submit.prevent="submit"
>
<div class="form-group">
<label for="code">
{{ $t('login.authentication_code') }} {{ $t('login.authentication_code') }}
</label> </label>
<input v-model='code' class='form-control' id='code'> <input
id="code"
v-model="code"
class="form-control"
>
</div> </div>
<div class='form-group'> <div class="form-group">
<div class='login-bottom'> <div class="login-bottom">
<div> <div>
<a href="#" @click.prevent="requireRecovery"> <a
href="#"
@click.prevent="requireRecovery"
>
{{ $t('login.enter_recovery_code') }} {{ $t('login.enter_recovery_code') }}
</a> </a>
<br /> <br>
<a href="#" @click.prevent="abortMFA"> <a
href="#"
@click.prevent="abortMFA"
>
{{ $t('general.cancel') }} {{ $t('general.cancel') }}
</a> </a>
</div> </div>
<button type='submit' class='btn btn-default'> <button
type="submit"
class="btn btn-default"
>
{{ $t('general.verify') }} {{ $t('general.verify') }}
</button> </button>
</div> </div>
@ -34,10 +50,16 @@
</form> </form>
</div> </div>
<div v-if="error" class='form-group'> <div
<div class='alert error'> v-if="error"
class="form-group"
>
<div class="alert error">
{{ error }} {{ error }}
<i class="button-icon icon-cancel" @click="clearError"></i> <i
class="button-icon icon-cancel"
@click="clearError"
/>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,22 +1,47 @@
<template> <template>
<div> <div>
<nav class='nav-bar container' id="nav"> <nav
<div class='mobile-inner-nav' @click="scrollToTop()"> id="nav"
<div class='item'> class="nav-bar container"
<a href="#" class="mobile-nav-button" @click.stop.prevent="toggleMobileSidebar()"> >
<i class="button-icon icon-menu"></i> <div
class="mobile-inner-nav"
@click="scrollToTop()"
>
<div class="item">
<a
href="#"
class="mobile-nav-button"
@click.stop.prevent="toggleMobileSidebar()"
>
<i class="button-icon icon-menu" />
</a> </a>
<router-link class="site-name" :to="{ name: 'root' }" active-class="home">{{sitename}}</router-link> <router-link
class="site-name"
:to="{ name: 'root' }"
active-class="home"
>
{{ sitename }}
</router-link>
</div> </div>
<div class='item right'> <div class="item right">
<a class="mobile-nav-button" v-if="currentUser" href="#" @click.stop.prevent="openMobileNotifications()"> <a
<i class="button-icon icon-bell-alt"></i> v-if="currentUser"
<div class="alert-dot" v-if="unseenNotificationsCount"></div> class="mobile-nav-button"
href="#"
@click.stop.prevent="openMobileNotifications()"
>
<i class="button-icon icon-bell-alt" />
<div
v-if="unseenNotificationsCount"
class="alert-dot"
/>
</a> </a>
</div> </div>
</div> </div>
</nav> </nav>
<div v-if="currentUser" <div
v-if="currentUser"
class="mobile-notifications-drawer" class="mobile-notifications-drawer"
:class="{ 'closed': !notificationsOpen }" :class="{ 'closed': !notificationsOpen }"
@touchstart.stop="notificationsTouchStart" @touchstart.stop="notificationsTouchStart"
@ -24,15 +49,27 @@
> >
<div class="mobile-notifications-header"> <div class="mobile-notifications-header">
<span class="title">{{ $t('notifications.notifications') }}</span> <span class="title">{{ $t('notifications.notifications') }}</span>
<a class="mobile-nav-button" @click.stop.prevent="closeMobileNotifications()"> <a
class="mobile-nav-button"
@click.stop.prevent="closeMobileNotifications()"
>
<i class="button-icon icon-cancel" /> <i class="button-icon icon-cancel" />
</a> </a>
</div> </div>
<div class="mobile-notifications" @scroll="onScroll"> <div
<Notifications ref="notifications" :noHeading="true"/> class="mobile-notifications"
@scroll="onScroll"
>
<Notifications
ref="notifications"
:no-heading="true"
/>
</div> </div>
</div> </div>
<SideDrawer ref="sideDrawer" :logout="logout"/> <SideDrawer
ref="sideDrawer"
:logout="logout"
/>
<MobilePostStatusModal /> <MobilePostStatusModal />
</div> </div>
</template> </template>

View file

@ -1,13 +1,21 @@
<template> <template>
<div v-if="currentUser"> <div v-if="currentUser">
<div <div
class="post-form-modal-view modal-view"
v-show="postFormOpen" v-show="postFormOpen"
class="post-form-modal-view modal-view"
@click="closePostForm" @click="closePostForm"
> >
<div class="post-form-modal-panel panel" @click.stop=""> <div
<div class="panel-heading">{{$t('post_status.new_status')}}</div> class="post-form-modal-panel panel"
<PostStatusForm class="panel-body" @posted="closePostForm" /> @click.stop=""
>
<div class="panel-heading">
{{ $t('post_status.new_status') }}
</div>
<PostStatusForm
class="panel-body"
@posted="closePostForm"
/>
</div> </div>
</div> </div>
<button <button

View file

@ -1,8 +1,10 @@
<template> <template>
<div class='block' style='position: relative'> <div
class="block"
style="position: relative"
>
<Popper <Popper
trigger="click" trigger="click"
@hide='showDropDown = false'
append-to-body append-to-body
:options="{ :options="{
placement: 'bottom-end', placement: 'bottom-end',
@ -10,70 +12,151 @@
arrow: { enabled: true }, arrow: { enabled: true },
offset: { offset: '0, 5px' }, offset: { offset: '0, 5px' },
} }
}"> }"
@hide="showDropDown = false"
>
<div class="popper-wrapper"> <div class="popper-wrapper">
<div class="dropdown-menu"> <div class="dropdown-menu">
<span v-if='user.is_local'> <span v-if="user.is_local">
<button class="dropdown-item" @click='toggleRight("admin")'> <button
class="dropdown-item"
@click="toggleRight(&quot;admin&quot;)"
>
{{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }} {{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }}
</button> </button>
<button class="dropdown-item" @click='toggleRight("moderator")'> <button
class="dropdown-item"
@click="toggleRight(&quot;moderator&quot;)"
>
{{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }} {{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }}
</button> </button>
<div role="separator" class="dropdown-divider"></div> <div
role="separator"
class="dropdown-divider"
/>
</span> </span>
<button class="dropdown-item" @click='toggleActivationStatus()'> <button
class="dropdown-item"
@click="toggleActivationStatus()"
>
{{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }} {{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }}
</button> </button>
<button class="dropdown-item" @click='deleteUserDialog(true)'> <button
class="dropdown-item"
@click="deleteUserDialog(true)"
>
{{ $t('user_card.admin_menu.delete_account') }} {{ $t('user_card.admin_menu.delete_account') }}
</button> </button>
<div role="separator" class="dropdown-divider" v-if='hasTagPolicy'></div> <div
<span v-if='hasTagPolicy'> v-if="hasTagPolicy"
<button class="dropdown-item" @click='toggleTag(tags.FORCE_NSFW)'> role="separator"
class="dropdown-divider"
/>
<span v-if="hasTagPolicy">
<button
class="dropdown-item"
@click="toggleTag(tags.FORCE_NSFW)"
>
{{ $t('user_card.admin_menu.force_nsfw') }} {{ $t('user_card.admin_menu.force_nsfw') }}
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }"></span> <span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }"
/>
</button> </button>
<button class="dropdown-item" @click='toggleTag(tags.STRIP_MEDIA)'> <button
class="dropdown-item"
@click="toggleTag(tags.STRIP_MEDIA)"
>
{{ $t('user_card.admin_menu.strip_media') }} {{ $t('user_card.admin_menu.strip_media') }}
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }"></span> <span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }"
/>
</button> </button>
<button class="dropdown-item" @click='toggleTag(tags.FORCE_UNLISTED)'> <button
class="dropdown-item"
@click="toggleTag(tags.FORCE_UNLISTED)"
>
{{ $t('user_card.admin_menu.force_unlisted') }} {{ $t('user_card.admin_menu.force_unlisted') }}
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }"></span> <span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }"
/>
</button> </button>
<button class="dropdown-item" @click='toggleTag(tags.SANDBOX)'> <button
class="dropdown-item"
@click="toggleTag(tags.SANDBOX)"
>
{{ $t('user_card.admin_menu.sandbox') }} {{ $t('user_card.admin_menu.sandbox') }}
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }"></span> <span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }"
/>
</button> </button>
<button class="dropdown-item" v-if='user.is_local' @click='toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)'> <button
v-if="user.is_local"
class="dropdown-item"
@click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)"
>
{{ $t('user_card.admin_menu.disable_remote_subscription') }} {{ $t('user_card.admin_menu.disable_remote_subscription') }}
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_REMOTE_SUBSCRIPTION) }"></span> <span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_REMOTE_SUBSCRIPTION) }"
/>
</button> </button>
<button class="dropdown-item" v-if='user.is_local' @click='toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)'> <button
v-if="user.is_local"
class="dropdown-item"
@click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)"
>
{{ $t('user_card.admin_menu.disable_any_subscription') }} {{ $t('user_card.admin_menu.disable_any_subscription') }}
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_ANY_SUBSCRIPTION) }"></span> <span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_ANY_SUBSCRIPTION) }"
/>
</button> </button>
<button class="dropdown-item" v-if='user.is_local' @click='toggleTag(tags.QUARANTINE)'> <button
v-if="user.is_local"
class="dropdown-item"
@click="toggleTag(tags.QUARANTINE)"
>
{{ $t('user_card.admin_menu.quarantine') }} {{ $t('user_card.admin_menu.quarantine') }}
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.QUARANTINE) }"></span> <span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.QUARANTINE) }"
/>
</button> </button>
</span> </span>
</div> </div>
</div> </div>
<button slot="reference" v-bind:class="{ pressed: showDropDown }" @click='toggleMenu'> <button
slot="reference"
:class="{ pressed: showDropDown }"
@click="toggleMenu"
>
{{ $t('user_card.admin_menu.moderation') }} {{ $t('user_card.admin_menu.moderation') }}
</button> </button>
</Popper> </Popper>
<portal to="modal"> <portal to="modal">
<DialogModal v-if="showDeleteUserDialog" :onCancel='deleteUserDialog.bind(this, false)'> <DialogModal
<template slot="header">{{ $t('user_card.admin_menu.delete_user') }}</template> v-if="showDeleteUserDialog"
:on-cancel="deleteUserDialog.bind(this, false)"
>
<template slot="header">
{{ $t('user_card.admin_menu.delete_user') }}
</template>
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p> <p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
<template slot="footer"> <template slot="footer">
<button class="btn btn-default" @click='deleteUserDialog(false)'> <button
class="btn btn-default"
@click="deleteUserDialog(false)"
>
{{ $t('general.cancel') }} {{ $t('general.cancel') }}
</button> </button>
<button class="btn btn-default danger" @click='deleteUser()'> <button
class="btn btn-default danger"
@click="deleteUser()"
>
{{ $t('user_card.admin_menu.delete_user') }} {{ $t('user_card.admin_menu.delete_user') }}
</button> </button>
</template> </template>

View file

@ -1,7 +1,12 @@
<template> <template>
<basic-user-card :user="user"> <basic-user-card :user="user">
<div class="mute-card-content-container"> <div class="mute-card-content-container">
<button class="btn btn-default" @click="unmuteUser" :disabled="progress" v-if="muted"> <button
v-if="muted"
class="btn btn-default"
:disabled="progress"
@click="unmuteUser"
>
<template v-if="progress"> <template v-if="progress">
{{ $t('user_card.unmute_progress') }} {{ $t('user_card.unmute_progress') }}
</template> </template>
@ -9,7 +14,12 @@
{{ $t('user_card.unmute') }} {{ $t('user_card.unmute') }}
</template> </template>
</button> </button>
<button class="btn btn-default" @click="muteUser" :disabled="progress" v-else> <button
v-else
class="btn btn-default"
:disabled="progress"
@click="muteUser"
>
<template v-if="progress"> <template v-if="progress">
{{ $t('user_card.mute_progress') }} {{ $t('user_card.mute_progress') }}
</template> </template>

View file

@ -2,25 +2,28 @@
<div class="nav-panel"> <div class="nav-panel">
<div class="panel panel-default"> <div class="panel panel-default">
<ul> <ul>
<li v-if='currentUser'> <li v-if="currentUser">
<router-link :to="{ name: 'friends' }"> <router-link :to="{ name: 'friends' }">
{{ $t("nav.timeline") }} {{ $t("nav.timeline") }}
</router-link> </router-link>
</li> </li>
<li v-if='currentUser'> <li v-if="currentUser">
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }"> <router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
{{ $t("nav.interactions") }} {{ $t("nav.interactions") }}
</router-link> </router-link>
</li> </li>
<li v-if='currentUser'> <li v-if="currentUser">
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }"> <router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
{{ $t("nav.dms") }} {{ $t("nav.dms") }}
</router-link> </router-link>
</li> </li>
<li v-if='currentUser && currentUser.locked'> <li v-if="currentUser && currentUser.locked">
<router-link :to="{ name: 'friend-requests' }"> <router-link :to="{ name: 'friend-requests' }">
{{ $t("nav.friend_requests") }} {{ $t("nav.friend_requests") }}
<span v-if='followRequestCount > 0' class="badge follow-request-count"> <span
v-if="followRequestCount > 0"
class="badge follow-request-count"
>
{{ followRequestCount }} {{ followRequestCount }}
</span> </span>
</router-link> </router-link>

View file

@ -3,49 +3,104 @@
v-if="notification.type === 'mention'" v-if="notification.type === 'mention'"
:compact="true" :compact="true"
:statusoid="notification.status" :statusoid="notification.status"
/>
<div
v-else
class="non-mention"
:class="[userClass, { highlighted: userStyle }]"
:style="[ userStyle ]"
> >
</status> <a
<div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]" v-else> class="avatar-container"
<a class='avatar-container' :href="notification.from_profile.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded"> :href="notification.from_profile.statusnet_profile_url"
<UserAvatar :compact="true" :betterShadow="betterShadow" :user="notification.from_profile"/> @click.stop.prevent.capture="toggleUserExpanded"
>
<UserAvatar
:compact="true"
:better-shadow="betterShadow"
:user="notification.from_profile"
/>
</a> </a>
<div class='notification-right'> <div class="notification-right">
<UserCard :user="getUser(notification)" :rounded="true" :bordered="true" v-if="userExpanded" /> <UserCard
v-if="userExpanded"
:user="getUser(notification)"
:rounded="true"
:bordered="true"
/>
<span class="notification-details"> <span class="notification-details">
<div class="name-and-action"> <div class="name-and-action">
<span class="username" v-if="!!notification.from_profile.name_html" :title="'@'+notification.from_profile.screen_name" v-html="notification.from_profile.name_html"></span> <!-- eslint-disable vue/no-v-html -->
<span class="username" v-else :title="'@'+notification.from_profile.screen_name">{{ notification.from_profile.name }}</span> <span
v-if="!!notification.from_profile.name_html"
class="username"
:title="'@'+notification.from_profile.screen_name"
v-html="notification.from_profile.name_html"
/>
<!-- eslint-enable vue/no-v-html -->
<span
v-else
class="username"
:title="'@'+notification.from_profile.screen_name"
>{{ notification.from_profile.name }}</span>
<span v-if="notification.type === 'like'"> <span v-if="notification.type === 'like'">
<i class="fa icon-star lit"></i> <i class="fa icon-star lit" />
<small>{{ $t('notifications.favorited_you') }}</small> <small>{{ $t('notifications.favorited_you') }}</small>
</span> </span>
<span v-if="notification.type === 'repeat'"> <span v-if="notification.type === 'repeat'">
<i class="fa icon-retweet lit" :title="$t('tool_tip.repeat')"></i> <i
class="fa icon-retweet lit"
:title="$t('tool_tip.repeat')"
/>
<small>{{ $t('notifications.repeated_you') }}</small> <small>{{ $t('notifications.repeated_you') }}</small>
</span> </span>
<span v-if="notification.type === 'follow'"> <span v-if="notification.type === 'follow'">
<i class="fa icon-user-plus lit"></i> <i class="fa icon-user-plus lit" />
<small>{{ $t('notifications.followed_you') }}</small> <small>{{ $t('notifications.followed_you') }}</small>
</span> </span>
</div> </div>
<div class="timeago" v-if="notification.type === 'follow'"> <div
v-if="notification.type === 'follow'"
class="timeago"
>
<span class="faint"> <span class="faint">
<Timeago :time="notification.created_at" :auto-update="240"></Timeago> <Timeago
:time="notification.created_at"
:auto-update="240"
/>
</span> </span>
</div> </div>
<div class="timeago" v-else> <div
<router-link v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }" class="faint-link"> v-else
<Timeago :time="notification.created_at" :auto-update="240"></Timeago> class="timeago"
>
<router-link
v-if="notification.status"
:to="{ name: 'conversation', params: { id: notification.status.id } }"
class="faint-link"
>
<Timeago
:time="notification.created_at"
:auto-update="240"
/>
</router-link> </router-link>
</div> </div>
</span> </span>
<div class="follow-text" v-if="notification.type === 'follow'"> <div
v-if="notification.type === 'follow'"
class="follow-text"
>
<router-link :to="userProfileLink(notification.from_profile)"> <router-link :to="userProfileLink(notification.from_profile)">
@{{ notification.from_profile.screen_name }} @{{ notification.from_profile.screen_name }}
</router-link> </router-link>
</div> </div>
<template v-else> <template v-else>
<status class="faint" :compact="true" :statusoid="notification.action" :noHeading="true"></status> <status
class="faint"
:compact="true"
:statusoid="notification.action"
:no-heading="true"
/>
</template> </template>
</div> </div>
</div> </div>

View file

@ -1,32 +1,66 @@
<template> <template>
<div :class="{ minimal: minimalMode }" class="notifications"> <div
:class="{ minimal: minimalMode }"
class="notifications"
>
<div :class="mainClass"> <div :class="mainClass">
<div v-if="!noHeading" class="panel-heading"> <div
v-if="!noHeading"
class="panel-heading"
>
<div class="title"> <div class="title">
{{ $t('notifications.notifications') }} {{ $t('notifications.notifications') }}
<span class="badge badge-notification unseen-count" v-if="unseenCount">{{unseenCount}}</span> <span
v-if="unseenCount"
class="badge badge-notification unseen-count"
>{{ unseenCount }}</span>
</div> </div>
<div @click.prevent class="loadmore-error alert error" v-if="error"> <div
v-if="error"
class="loadmore-error alert error"
@click.prevent
>
{{ $t('timeline.error_fetching') }} {{ $t('timeline.error_fetching') }}
</div> </div>
<button v-if="unseenCount" @click.prevent="markAsSeen" class="read-button">{{$t('notifications.read')}}</button> <button
v-if="unseenCount"
class="read-button"
@click.prevent="markAsSeen"
>
{{ $t('notifications.read') }}
</button>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div v-for="notification in visibleNotifications" :key="notification.id" class="notification" :class='{"unseen": !minimalMode && !notification.seen}'> <div
<div class="notification-overlay"></div> v-for="notification in visibleNotifications"
<notification :notification="notification"></notification> :key="notification.id"
class="notification"
:class="{&quot;unseen&quot;: !minimalMode && !notification.seen}"
>
<div class="notification-overlay" />
<notification :notification="notification" />
</div> </div>
</div> </div>
<div class="panel-footer"> <div class="panel-footer">
<div v-if="bottomedOut" class="new-status-notification text-center panel-footer faint"> <div
v-if="bottomedOut"
class="new-status-notification text-center panel-footer faint"
>
{{ $t('notifications.no_more_notifications') }} {{ $t('notifications.no_more_notifications') }}
</div> </div>
<a v-else-if="!loading" href="#" v-on:click.prevent="fetchOlderNotifications()"> <a
v-else-if="!loading"
href="#"
@click.prevent="fetchOlderNotifications()"
>
<div class="new-status-notification text-center panel-footer"> <div class="new-status-notification text-center panel-footer">
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }} {{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }}
</div> </div>
</a> </a>
<div v-else class="new-status-notification text-center panel-footer"> <div
v-else
class="new-status-notification text-center panel-footer"
>
<i class="icon-spin3 animate-spin" /> <i class="icon-spin3 animate-spin" />
</div> </div>
</div> </div>

View file

@ -1,26 +1,38 @@
<template> <template>
<div class="opacity-control style-control" :class="{ disabled: !present || disabled }"> <div
<label :for="name" class="label"> class="opacity-control style-control"
:class="{ disabled: !present || disabled }"
>
<label
:for="name"
class="label"
>
{{ $t('settings.style.common.opacity') }} {{ $t('settings.style.common.opacity') }}
</label> </label>
<input <input
v-if="typeof fallback !== 'undefined'" v-if="typeof fallback !== 'undefined'"
class="opt exclude-disabled"
:id="name + '-o'" :id="name + '-o'"
class="opt exclude-disabled"
type="checkbox" type="checkbox"
:checked="present" :checked="present"
@input="$emit('input', !present ? fallback : undefined)"> @input="$emit('input', !present ? fallback : undefined)"
<label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label> >
<label
v-if="typeof fallback !== 'undefined'"
class="opt-l"
:for="name + '-o'"
/>
<input <input
:id="name" :id="name"
class="input-number" class="input-number"
type="number" type="number"
:value="value || fallback" :value="value || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
@input="$emit('input', $event.target.value)"
max="1" max="1"
min="0" min="0"
step=".05"> step=".05"
@input="$emit('input', $event.target.value)"
>
</div> </div>
</template> </template>

View file

@ -1,11 +1,18 @@
<template> <template>
<div class="poll" v-bind:class="containerClass">
<div <div
class="poll-option" class="poll"
:class="containerClass"
>
<div
v-for="(option, index) in options" v-for="(option, index) in options"
:key="index" :key="index"
class="poll-option"
>
<div
v-if="showResults"
:title="resultTitle(option)"
class="option-result"
> >
<div v-if="showResults" :title="resultTitle(option)" class="option-result">
<div class="option-result-label"> <div class="option-result-label">
<span class="result-percentage"> <span class="result-percentage">
{{ percentageForOption(option.votes_count) }}% {{ percentageForOption(option.votes_count) }}%
@ -15,10 +22,12 @@
<div <div
class="result-fill" class="result-fill"
:style="{ 'width': `${percentageForOption(option.votes_count)}%` }" :style="{ 'width': `${percentageForOption(option.votes_count)}%` }"
/>
</div>
<div
v-else
@click="activateOption(index)"
> >
</div>
</div>
<div v-else @click="activateOption(index)">
<input <input
v-if="poll.multiple" v-if="poll.multiple"
type="checkbox" type="checkbox"
@ -41,8 +50,8 @@
v-if="!showResults" v-if="!showResults"
class="btn btn-default poll-vote-button" class="btn btn-default poll-vote-button"
type="button" type="button"
@click="vote"
:disabled="isDisabled" :disabled="isDisabled"
@click="vote"
> >
{{ $t('polls.vote') }} {{ $t('polls.vote') }}
</button> </button>
@ -50,7 +59,11 @@
{{ totalVotesCount }} {{ $t("polls.votes") }}&nbsp;·&nbsp; {{ totalVotesCount }} {{ $t("polls.votes") }}&nbsp;·&nbsp;
</div> </div>
<i18n :path="expired ? 'polls.expired' : 'polls.expires_in'"> <i18n :path="expired ? 'polls.expired' : 'polls.expires_in'">
<Timeago :time="this.expiresAt" :auto-update="60" :now-threshold="0" /> <Timeago
:time="expiresAt"
:auto-update="60"
:now-threshold="0"
/>
</i18n> </i18n>
</div> </div>
</div> </div>

View file

@ -1,20 +1,33 @@
<template> <template>
<div class="poll-form" v-if="visible"> <div
<div class="poll-option" v-for="(option, index) in options" :key="index"> v-if="visible"
class="poll-form"
>
<div
v-for="(option, index) in options"
:key="index"
class="poll-option"
>
<div class="input-container"> <div class="input-container">
<input <input
:id="`poll-${index}`"
v-model="options[index]"
class="poll-option-input" class="poll-option-input"
type="text" type="text"
:placeholder="$t('polls.option')" :placeholder="$t('polls.option')"
:maxlength="maxLength" :maxlength="maxLength"
:id="`poll-${index}`"
v-model="options[index]"
@change="updatePollToParent" @change="updatePollToParent"
@keydown.enter.stop.prevent="nextOption(index)" @keydown.enter.stop.prevent="nextOption(index)"
> >
</div> </div>
<div class="icon-container" v-if="options.length > 2"> <div
<i class="icon-cancel" @click="deleteOption(index)"></i> v-if="options.length > 2"
class="icon-container"
>
<i
class="icon-cancel"
@click="deleteOption(index)"
/>
</div> </div>
</div> </div>
<a <a
@ -26,22 +39,35 @@
{{ $t("polls.add_option") }} {{ $t("polls.add_option") }}
</a> </a>
<div class="poll-type-expiry"> <div class="poll-type-expiry">
<div class="poll-type" :title="$t('polls.type')"> <div
<label for="poll-type-selector" class="select"> class="poll-type"
<select class="select" v-model="pollType" @change="updatePollToParent"> :title="$t('polls.type')"
>
<label
for="poll-type-selector"
class="select"
>
<select
v-model="pollType"
class="select"
@change="updatePollToParent"
>
<option value="single">{{ $t('polls.single_choice') }}</option> <option value="single">{{ $t('polls.single_choice') }}</option>
<option value="multiple">{{ $t('polls.multiple_choices') }}</option> <option value="multiple">{{ $t('polls.multiple_choices') }}</option>
</select> </select>
<i class="icon-down-open" /> <i class="icon-down-open" />
</label> </label>
</div> </div>
<div class="poll-expiry" :title="$t('polls.expiry')"> <div
class="poll-expiry"
:title="$t('polls.expiry')"
>
<input <input
v-model="expiryAmount"
type="number" type="number"
class="expiry-amount hide-number-spinner" class="expiry-amount hide-number-spinner"
:min="minExpirationInCurrentUnit" :min="minExpirationInCurrentUnit"
:max="maxExpirationInCurrentUnit" :max="maxExpirationInCurrentUnit"
v-model="expiryAmount"
@change="expiryAmountChange" @change="expiryAmountChange"
> >
<label class="expiry-unit select"> <label class="expiry-unit select">
@ -49,7 +75,11 @@
v-model="expiryUnit" v-model="expiryUnit"
@change="expiryAmountChange" @change="expiryAmountChange"
> >
<option v-for="unit in expiryUnits" :value="unit"> <option
v-for="unit in expiryUnits"
:key="unit"
:value="unit"
>
{{ $t(`time.${unit}_short`, ['']) }} {{ $t(`time.${unit}_short`, ['']) }}
</option> </option>
</select> </select>

View file

@ -1,53 +1,80 @@
<template> <template>
<div class="post-status-form"> <div class="post-status-form">
<form @submit.prevent="postStatus(newStatus)" autocomplete="off"> <form
autocomplete="off"
@submit.prevent="postStatus(newStatus)"
>
<div class="form-group"> <div class="form-group">
<i18n <i18n
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private'" v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private'"
path="post_status.account_not_locked_warning" path="post_status.account_not_locked_warning"
tag="p" tag="p"
class="visibility-notice"> class="visibility-notice"
<router-link :to="{ name: 'user-settings' }">{{ $t('post_status.account_not_locked_warning_link') }}</router-link> >
<router-link :to="{ name: 'user-settings' }">
{{ $t('post_status.account_not_locked_warning_link') }}
</router-link>
</i18n> </i18n>
<p v-if="!hideScopeNotice && newStatus.visibility === 'public'" class="visibility-notice notice-dismissible"> <p
v-if="!hideScopeNotice && newStatus.visibility === 'public'"
class="visibility-notice notice-dismissible"
>
<span>{{ $t('post_status.scope_notice.public') }}</span> <span>{{ $t('post_status.scope_notice.public') }}</span>
<a v-on:click.prevent="dismissScopeNotice()" class="button-icon dismiss"> <a
<i class='icon-cancel'></i> class="button-icon dismiss"
@click.prevent="dismissScopeNotice()"
>
<i class="icon-cancel" />
</a> </a>
</p> </p>
<p v-else-if="!hideScopeNotice && newStatus.visibility === 'unlisted'" class="visibility-notice notice-dismissible"> <p
v-else-if="!hideScopeNotice && newStatus.visibility === 'unlisted'"
class="visibility-notice notice-dismissible"
>
<span>{{ $t('post_status.scope_notice.unlisted') }}</span> <span>{{ $t('post_status.scope_notice.unlisted') }}</span>
<a v-on:click.prevent="dismissScopeNotice()" class="button-icon dismiss"> <a
<i class='icon-cancel'></i> class="button-icon dismiss"
@click.prevent="dismissScopeNotice()"
>
<i class="icon-cancel" />
</a> </a>
</p> </p>
<p v-else-if="!hideScopeNotice && newStatus.visibility === 'private' && $store.state.users.currentUser.locked" class="visibility-notice notice-dismissible"> <p
v-else-if="!hideScopeNotice && newStatus.visibility === 'private' && $store.state.users.currentUser.locked"
class="visibility-notice notice-dismissible"
>
<span>{{ $t('post_status.scope_notice.private') }}</span> <span>{{ $t('post_status.scope_notice.private') }}</span>
<a v-on:click.prevent="dismissScopeNotice()" class="button-icon dismiss"> <a
<i class='icon-cancel'></i> class="button-icon dismiss"
@click.prevent="dismissScopeNotice()"
>
<i class="icon-cancel" />
</a> </a>
</p> </p>
<p v-else-if="newStatus.visibility === 'direct'" class="visibility-notice"> <p
v-else-if="newStatus.visibility === 'direct'"
class="visibility-notice"
>
<span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span> <span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span>
<span v-else>{{ $t('post_status.direct_warning_to_all') }}</span> <span v-else>{{ $t('post_status.direct_warning_to_all') }}</span>
</p> </p>
<EmojiInput <EmojiInput
v-if="newStatus.spoilerText || alwaysShowSubject" v-if="newStatus.spoilerText || alwaysShowSubject"
:suggest="emojiSuggestor"
v-model="newStatus.spoilerText" v-model="newStatus.spoilerText"
:suggest="emojiSuggestor"
class="form-control" class="form-control"
> >
<input <input
v-model="newStatus.spoilerText"
type="text" type="text"
:placeholder="$t('post_status.content_warning')" :placeholder="$t('post_status.content_warning')"
v-model="newStatus.spoilerText"
class="form-post-subject" class="form-post-subject"
/> >
</EmojiInput> </EmojiInput>
<EmojiInput <EmojiInput
:suggest="emojiUserSuggestor"
v-model="newStatus.status" v-model="newStatus.status"
:suggest="emojiUserSuggestor"
class="form-control main-input" class="form-control main-input"
> >
<textarea <textarea
@ -55,16 +82,15 @@
v-model="newStatus.status" v-model="newStatus.status"
:placeholder="$t('post_status.default')" :placeholder="$t('post_status.default')"
rows="1" rows="1"
:disabled="posting"
class="form-post-body"
@keydown.meta.enter="postStatus(newStatus)" @keydown.meta.enter="postStatus(newStatus)"
@keyup.ctrl.enter="postStatus(newStatus)" @keyup.ctrl.enter="postStatus(newStatus)"
@drop="fileDrop" @drop="fileDrop"
@dragover.prevent="fileDrag" @dragover.prevent="fileDrag"
@input="resize" @input="resize"
@paste="paste" @paste="paste"
:disabled="posting" />
class="form-post-body"
>
</textarea>
<p <p
v-if="hasStatusLengthLimit" v-if="hasStatusLengthLimit"
class="character-counter faint" class="character-counter faint"
@ -74,70 +100,151 @@
</p> </p>
</EmojiInput> </EmojiInput>
<div class="visibility-tray"> <div class="visibility-tray">
<div class="text-format" v-if="postFormats.length > 1"> <scope-selector
<label for="post-content-type" class="select"> :show-all="showAllScopes"
<select id="post-content-type" v-model="newStatus.contentType" class="form-control"> :user-default="userDefaultScope"
<option v-for="postFormat in postFormats" :key="postFormat" :value="postFormat"> :original-scope="copyMessageScope"
:initial-scope="newStatus.visibility"
:on-scope-change="changeVis"
/>
<div
v-if="postFormats.length > 1"
class="text-format"
>
<label
for="post-content-type"
class="select"
>
<select
id="post-content-type"
v-model="newStatus.contentType"
class="form-control"
>
<option
v-for="postFormat in postFormats"
:key="postFormat"
:value="postFormat"
>
{{ $t(`post_status.content_type["${postFormat}"]`) }} {{ $t(`post_status.content_type["${postFormat}"]`) }}
</option> </option>
</select> </select>
<i class="icon-down-open"></i> <i class="icon-down-open" />
</label> </label>
</div> </div>
<div class="text-format" v-if="postFormats.length === 1"> <div
v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'"
class="text-format"
>
<span class="only-format"> <span class="only-format">
{{ $t(`post_status.content_type["${postFormats[0]}"]`) }} {{ $t(`post_status.content_type["${postFormats[0]}"]`) }}
</span> </span>
</div> </div>
<scope-selector
:showAll="showAllScopes"
:userDefault="userDefaultScope"
:originalScope="copyMessageScope"
:initialScope="newStatus.visibility"
:onScopeChange="changeVis"/>
</div> </div>
</div> </div>
<poll-form <poll-form
ref="pollForm"
v-if="pollsAvailable" v-if="pollsAvailable"
ref="pollForm"
:visible="pollFormVisible" :visible="pollFormVisible"
@update-poll="setPoll" @update-poll="setPoll"
/> />
<div class='form-bottom'> <div class="form-bottom">
<div class='form-bottom-left'> <div class="form-bottom-left">
<media-upload ref="mediaUpload" @uploading="disableSubmit" @uploaded="addMediaFile" @upload-failed="uploadFailed" :drop-files="dropFiles"></media-upload> <media-upload
<div v-if="pollsAvailable" class="poll-icon"> ref="mediaUpload"
:drop-files="dropFiles"
@uploading="disableSubmit"
@uploaded="addMediaFile"
@upload-failed="uploadFailed"
/>
<div
v-if="pollsAvailable"
class="poll-icon"
>
<i <i
:title="$t('polls.add_poll')" :title="$t('polls.add_poll')"
@click="togglePollForm"
class="icon-chart-bar btn btn-default" class="icon-chart-bar btn btn-default"
:class="pollFormVisible && 'selected'" :class="pollFormVisible && 'selected'"
@click="togglePollForm"
/> />
</div> </div>
</div> </div>
<button v-if="posting" disabled class="btn btn-default">{{$t('post_status.posting')}}</button> <button
<button v-else-if="isOverLengthLimit" disabled class="btn btn-default">{{$t('general.submit')}}</button> v-if="posting"
<button v-else :disabled="submitDisabled" type="submit" class="btn btn-default">{{$t('general.submit')}}</button> 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>
<div class='alert error' v-if="error"> <div
v-if="error"
class="alert error"
>
Error: {{ error }} Error: {{ error }}
<i class="button-icon icon-cancel" @click="clearError"></i> <i
class="button-icon icon-cancel"
@click="clearError"
/>
</div> </div>
<div class="attachments"> <div class="attachments">
<div class="media-upload-wrapper" v-for="file in newStatus.files"> <div
<i class="fa button-icon icon-cancel" @click="removeMediaFile(file)"></i> v-for="file in newStatus.files"
:key="file.url"
class="media-upload-wrapper"
>
<i
class="fa button-icon icon-cancel"
@click="removeMediaFile(file)"
/>
<div class="media-upload-container attachment"> <div class="media-upload-container attachment">
<img class="thumbnail media-upload" :src="file.url" v-if="type(file) === 'image'"></img> <img
<video v-if="type(file) === 'video'" :src="file.url" controls></video> v-if="type(file) === 'image'"
<audio v-if="type(file) === 'audio'" :src="file.url" controls></audio> class="thumbnail media-upload"
<a v-if="type(file) === 'unknown'" :href="file.url">{{file.url}}</a> :src="file.url"
>
<video
v-if="type(file) === 'video'"
:src="file.url"
controls
/>
<audio
v-if="type(file) === 'audio'"
:src="file.url"
controls
/>
<a
v-if="type(file) === 'unknown'"
:href="file.url"
>{{ file.url }}</a>
</div> </div>
</div> </div>
</div> </div>
<div class="upload_settings" v-if="newStatus.files.length > 0"> <div
<input type="checkbox" id="filesSensitive" v-model="newStatus.nsfw"> v-if="newStatus.files.length > 0"
class="upload_settings"
>
<input
id="filesSensitive"
v-model="newStatus.nsfw"
type="checkbox"
>
<label for="filesSensitive">{{ $t('post_status.attachments_sensitive') }}</label> <label for="filesSensitive">{{ $t('post_status.attachments_sensitive') }}</label>
</div> </div>
</form> </form>
@ -170,7 +277,6 @@
.visibility-tray { .visibility-tray {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-direction: row-reverse;
padding-top: 5px; padding-top: 5px;
} }
} }
@ -218,7 +324,6 @@
cursor: pointer; cursor: pointer;
} }
.error { .error {
text-align: center; text-align: center;
} }

View file

@ -1,5 +1,8 @@
<template> <template>
<button :disabled="progress || disabled" @click="onClick"> <button
:disabled="progress || disabled"
@click="onClick"
>
<template v-if="progress"> <template v-if="progress">
<slot name="progress" /> <slot name="progress" />
</template> </template>

View file

@ -1,5 +1,9 @@
<template> <template>
<Timeline :title="$t('nav.twkn')" v-bind:timeline="timeline" v-bind:timeline-name="'publicAndExternal'"/> <Timeline
:title="$t('nav.twkn')"
:timeline="timeline"
:timeline-name="'publicAndExternal'"
/>
</template> </template>
<script src="./public_and_external_timeline.js"></script> <script src="./public_and_external_timeline.js"></script>

View file

@ -1,5 +1,9 @@
<template> <template>
<Timeline :title="$t('nav.public_tl')" v-bind:timeline="timeline" v-bind:timeline-name="'public'"/> <Timeline
:title="$t('nav.public_tl')"
:timeline="timeline"
:timeline-name="'public'"
/>
</template> </template>
<script src="./public_timeline.js"></script> <script src="./public_timeline.js"></script>

View file

@ -1,36 +1,49 @@
<template> <template>
<div class="range-control style-control" :class="{ disabled: !present || disabled }"> <div
<label :for="name" class="label"> class="range-control style-control"
:class="{ disabled: !present || disabled }"
>
<label
:for="name"
class="label"
>
{{ label }} {{ label }}
</label> </label>
<input <input
v-if="typeof fallback !== 'undefined'" v-if="typeof fallback !== 'undefined'"
class="opt exclude-disabled"
:id="name + '-o'" :id="name + '-o'"
class="opt exclude-disabled"
type="checkbox" type="checkbox"
:checked="present" :checked="present"
@input="$emit('input', !present ? fallback : undefined)"> @input="$emit('input', !present ? fallback : undefined)"
<label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label> >
<label
v-if="typeof fallback !== 'undefined'"
class="opt-l"
:for="name + '-o'"
/>
<input <input
:id="name" :id="name"
class="input-number" class="input-number"
type="range" type="range"
:value="value || fallback" :value="value || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
@input="$emit('input', $event.target.value)"
:max="max || hardMax || 100" :max="max || hardMax || 100"
:min="min || hardMin || 0" :min="min || hardMin || 0"
:step="step || 1"> :step="step || 1"
@input="$emit('input', $event.target.value)"
>
<input <input
:id="name" :id="name"
class="input-number" class="input-number"
type="number" type="number"
:value="value || fallback" :value="value || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
@input="$emit('input', $event.target.value)"
:max="hardMax" :max="hardMax"
:min="hardMin" :min="hardMin"
:step="step || 1"> :step="step || 1"
@input="$emit('input', $event.target.value)"
>
</div> </div>
</template> </template>

View file

@ -4,14 +4,32 @@
{{ $t('registration.registration') }} {{ $t('registration.registration') }}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form v-on:submit.prevent='submit(user)' class='registration-form'> <form
<div class='container'> class="registration-form"
<div class='text-fields'> @submit.prevent="submit(user)"
<div class='form-group' :class="{ 'form-group--error': $v.user.username.$error }"> >
<label class='form--label' for='sign-up-username'>{{$t('login.username')}}</label> <div class="container">
<input :disabled="isPending" v-model.trim='$v.user.username.$model' class='form-control' id='sign-up-username' :placeholder="$t('registration.username_placeholder')"> <div class="text-fields">
<div
class="form-group"
:class="{ 'form-group--error': $v.user.username.$error }"
>
<label
class="form--label"
for="sign-up-username"
>{{ $t('login.username') }}</label>
<input
id="sign-up-username"
v-model.trim="$v.user.username.$model"
:disabled="isPending"
class="form-control"
:placeholder="$t('registration.username_placeholder')"
>
</div> </div>
<div class="form-error" v-if="$v.user.username.$dirty"> <div
v-if="$v.user.username.$dirty"
class="form-error"
>
<ul> <ul>
<li v-if="!$v.user.username.required"> <li v-if="!$v.user.username.required">
<span>{{ $t('registration.validations.username_required') }}</span> <span>{{ $t('registration.validations.username_required') }}</span>
@ -19,11 +37,26 @@
</ul> </ul>
</div> </div>
<div class='form-group' :class="{ 'form-group--error': $v.user.fullname.$error }"> <div
<label class='form--label' for='sign-up-fullname'>{{$t('registration.fullname')}}</label> class="form-group"
<input :disabled="isPending" v-model.trim='$v.user.fullname.$model' class='form-control' id='sign-up-fullname' :placeholder="$t('registration.fullname_placeholder')"> :class="{ 'form-group--error': $v.user.fullname.$error }"
>
<label
class="form--label"
for="sign-up-fullname"
>{{ $t('registration.fullname') }}</label>
<input
id="sign-up-fullname"
v-model.trim="$v.user.fullname.$model"
:disabled="isPending"
class="form-control"
:placeholder="$t('registration.fullname_placeholder')"
>
</div> </div>
<div class="form-error" v-if="$v.user.fullname.$dirty"> <div
v-if="$v.user.fullname.$dirty"
class="form-error"
>
<ul> <ul>
<li v-if="!$v.user.fullname.required"> <li v-if="!$v.user.fullname.required">
<span>{{ $t('registration.validations.fullname_required') }}</span> <span>{{ $t('registration.validations.fullname_required') }}</span>
@ -31,11 +64,26 @@
</ul> </ul>
</div> </div>
<div class='form-group' :class="{ 'form-group--error': $v.user.email.$error }"> <div
<label class='form--label' for='email'>{{$t('registration.email')}}</label> class="form-group"
<input :disabled="isPending" v-model='$v.user.email.$model' class='form-control' id='email' type="email"> :class="{ 'form-group--error': $v.user.email.$error }"
>
<label
class="form--label"
for="email"
>{{ $t('registration.email') }}</label>
<input
id="email"
v-model="$v.user.email.$model"
:disabled="isPending"
class="form-control"
type="email"
>
</div> </div>
<div class="form-error" v-if="$v.user.email.$dirty"> <div
v-if="$v.user.email.$dirty"
class="form-error"
>
<ul> <ul>
<li v-if="!$v.user.email.required"> <li v-if="!$v.user.email.required">
<span>{{ $t('registration.validations.email_required') }}</span> <span>{{ $t('registration.validations.email_required') }}</span>
@ -43,16 +91,40 @@
</ul> </ul>
</div> </div>
<div class='form-group'> <div class="form-group">
<label class='form--label' for='bio'>{{$t('registration.bio')}} ({{$t('general.optional')}})</label> <label
<textarea :disabled="isPending" v-model='user.bio' class='form-control' id='bio' :placeholder="bioPlaceholder"></textarea> class="form--label"
for="bio"
>{{ $t('registration.bio') }} ({{ $t('general.optional') }})</label>
<textarea
id="bio"
v-model="user.bio"
:disabled="isPending"
class="form-control"
:placeholder="bioPlaceholder"
/>
</div> </div>
<div class='form-group' :class="{ 'form-group--error': $v.user.password.$error }"> <div
<label class='form--label' for='sign-up-password'>{{$t('login.password')}}</label> class="form-group"
<input :disabled="isPending" v-model='user.password' class='form-control' id='sign-up-password' type='password'> :class="{ 'form-group--error': $v.user.password.$error }"
>
<label
class="form--label"
for="sign-up-password"
>{{ $t('login.password') }}</label>
<input
id="sign-up-password"
v-model="user.password"
:disabled="isPending"
class="form-control"
type="password"
>
</div> </div>
<div class="form-error" v-if="$v.user.password.$dirty"> <div
v-if="$v.user.password.$dirty"
class="form-error"
>
<ul> <ul>
<li v-if="!$v.user.password.required"> <li v-if="!$v.user.password.required">
<span>{{ $t('registration.validations.password_required') }}</span> <span>{{ $t('registration.validations.password_required') }}</span>
@ -60,11 +132,26 @@
</ul> </ul>
</div> </div>
<div class='form-group' :class="{ 'form-group--error': $v.user.confirm.$error }"> <div
<label class='form--label' for='sign-up-password-confirmation'>{{$t('registration.password_confirm')}}</label> class="form-group"
<input :disabled="isPending" v-model='user.confirm' class='form-control' id='sign-up-password-confirmation' type='password'> :class="{ 'form-group--error': $v.user.confirm.$error }"
>
<label
class="form--label"
for="sign-up-password-confirmation"
>{{ $t('registration.password_confirm') }}</label>
<input
id="sign-up-password-confirmation"
v-model="user.confirm"
:disabled="isPending"
class="form-control"
type="password"
>
</div> </div>
<div class="form-error" v-if="$v.user.confirm.$dirty"> <div
v-if="$v.user.confirm.$dirty"
class="form-error"
>
<ul> <ul>
<li v-if="!$v.user.confirm.required"> <li v-if="!$v.user.confirm.required">
<span>{{ $t('registration.validations.password_confirmation_required') }}</span> <span>{{ $t('registration.validations.password_confirmation_required') }}</span>
@ -75,35 +162,75 @@
</ul> </ul>
</div> </div>
<div class="form-group" id="captcha-group" v-if="captcha.type != 'none'"> <div
<label class='form--label' for='captcha-label'>{{$t('captcha')}}</label> v-if="captcha.type != 'none'"
id="captcha-group"
class="form-group"
>
<label
class="form--label"
for="captcha-label"
>{{ $t('captcha') }}</label>
<template v-if="captcha.type == 'kocaptcha'"> <template v-if="captcha.type == 'kocaptcha'">
<img v-bind:src="captcha.url" v-on:click="setCaptcha"> <img
:src="captcha.url"
@click="setCaptcha"
>
<sub>{{ $t('registration.new_captcha') }}</sub> <sub>{{ $t('registration.new_captcha') }}</sub>
<input :disabled="isPending" <input
v-model='captcha.solution' id="captcha-answer"
class='form-control' id='captcha-answer' type='text' autocomplete="off"> v-model="captcha.solution"
:disabled="isPending"
class="form-control"
type="text"
autocomplete="off"
>
</template> </template>
</div> </div>
<div class='form-group' v-if='token' > <div
<label for='token'>{{$t('registration.token')}}</label> v-if="token"
<input disabled='true' v-model='token' class='form-control' id='token' type='text'> class="form-group"
>
<label for="token">{{ $t('registration.token') }}</label>
<input
id="token"
v-model="token"
disabled="true"
class="form-control"
type="text"
>
</div> </div>
<div class='form-group'> <div class="form-group">
<button :disabled="isPending" type='submit' class='btn btn-default'>{{$t('general.submit')}}</button> <button
:disabled="isPending"
type="submit"
class="btn btn-default"
>
{{ $t('general.submit') }}
</button>
</div> </div>
</div> </div>
<div class='terms-of-service' v-html="termsOfService"> <!-- eslint-disable vue/no-v-html -->
<div
class="terms-of-service"
v-html="termsOfService"
/>
<!-- eslint-enable vue/no-v-html -->
</div> </div>
</div> <div
<div v-if="serverValidationErrors.length" class='form-group'> v-if="serverValidationErrors.length"
<div class='alert error'> class="form-group"
<span v-for="error in serverValidationErrors">{{error}}</span> >
<div class="alert error">
<span
v-for="error in serverValidationErrors"
:key="error"
>{{ error }}</span>
</div> </div>
</div> </div>
</form> </form>

View file

@ -1,9 +1,23 @@
<template> <template>
<div class="remote-follow"> <div class="remote-follow">
<form method="POST" :action='subscribeUrl'> <form
<input type="hidden" name="nickname" :value="user.screen_name"> method="POST"
<input type="hidden" name="profile" value=""> :action="subscribeUrl"
<button click="submit" class="remote-button"> >
<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') }} {{ $t('user_card.remote_follow') }}
</button> </button>
</form> </form>

View file

@ -1,16 +1,29 @@
<template> <template>
<div v-if="loggedIn"> <div v-if="loggedIn">
<template v-if="visibility !== 'private' && visibility !== 'direct'"> <template v-if="visibility !== 'private' && visibility !== 'direct'">
<i :class='classes' class='button-icon retweet-button icon-retweet rt-active' v-on:click.prevent='retweet()' :title="$t('tool_tip.repeat')"></i> <i
<span v-if='!hidePostStatsLocal && status.repeat_num > 0'>{{status.repeat_num}}</span> :class="classes"
class="button-icon retweet-button icon-retweet rt-active"
:title="$t('tool_tip.repeat')"
@click.prevent="retweet()"
/>
<span v-if="!hidePostStatsLocal && status.repeat_num > 0">{{ status.repeat_num }}</span>
</template> </template>
<template v-else> <template v-else>
<i :class='classes' class='button-icon icon-lock' :title="$t('timeline.no_retweet_hint')"></i> <i
:class="classes"
class="button-icon icon-lock"
:title="$t('timeline.no_retweet_hint')"
/>
</template> </template>
</div> </div>
<div v-else-if="!loggedIn"> <div v-else-if="!loggedIn">
<i :class='classes' class='button-icon icon-retweet' :title="$t('tool_tip.repeat')"></i> <i
<span v-if='!hidePostStatsLocal && status.repeat_num > 0'>{{status.repeat_num}}</span> :class="classes"
class="button-icon icon-retweet"
:title="$t('tool_tip.repeat')"
/>
<span v-if="!hidePostStatsLocal && status.repeat_num > 0">{{ status.repeat_num }}</span>
</div> </div>
</template> </template>

View file

@ -1,29 +1,36 @@
<template> <template>
<div v-if="!showNothing" class="scope-selector"> <div
<i class="icon-mail-alt" v-if="!showNothing"
class="scope-selector"
>
<i
v-if="showDirect"
class="icon-mail-alt"
:class="css.direct" :class="css.direct"
:title="$t('post_status.scope.direct')" :title="$t('post_status.scope.direct')"
v-if="showDirect" @click="changeVis('direct')"
@click="changeVis('direct')"> />
</i> <i
<i class="icon-lock" v-if="showPrivate"
class="icon-lock"
:class="css.private" :class="css.private"
:title="$t('post_status.scope.private')" :title="$t('post_status.scope.private')"
v-if="showPrivate" @click="changeVis('private')"
v-on:click="changeVis('private')"> />
</i> <i
<i class="icon-lock-open-alt" v-if="showUnlisted"
class="icon-lock-open-alt"
:class="css.unlisted" :class="css.unlisted"
:title="$t('post_status.scope.unlisted')" :title="$t('post_status.scope.unlisted')"
v-if="showUnlisted" @click="changeVis('unlisted')"
@click="changeVis('unlisted')"> />
</i> <i
<i class="icon-globe" v-if="showPublic"
class="icon-globe"
:class="css.public" :class="css.public"
:title="$t('post_status.scope.public')" :title="$t('post_status.scope.public')"
v-if="showPublic" @click="changeVis('public')"
@click="changeVis('public')"> />
</i>
</div> </div>
</template> </template>

View file

@ -1,23 +1,52 @@
<template> <template>
<div class="selectable-list"> <div class="selectable-list">
<div class="selectable-list-header" v-if="items.length > 0"> <div
v-if="items.length > 0"
class="selectable-list-header"
>
<div class="selectable-list-checkbox-wrapper"> <div class="selectable-list-checkbox-wrapper">
<Checkbox :checked="allSelected" @change="toggleAll" :indeterminate="someSelected">{{ $t('selectable_list.select_all') }}</Checkbox> <Checkbox
:checked="allSelected"
:indeterminate="someSelected"
@change="toggleAll"
>
{{ $t('selectable_list.select_all') }}
</Checkbox>
</div> </div>
<div class="selectable-list-header-actions"> <div class="selectable-list-header-actions">
<slot name="header" :selected="filteredSelected" /> <slot
name="header"
:selected="filteredSelected"
/>
</div> </div>
</div> </div>
<List :items="items" :getKey="getKey"> <List
<template slot="item" slot-scope="{item}"> :items="items"
<div class="selectable-list-item-inner" :class="{ 'selectable-list-item-selected-inner': isSelected(item) }"> :get-key="getKey"
>
<template
slot="item"
slot-scope="{item}"
>
<div
class="selectable-list-item-inner"
:class="{ 'selectable-list-item-selected-inner': isSelected(item) }"
>
<div class="selectable-list-checkbox-wrapper"> <div class="selectable-list-checkbox-wrapper">
<Checkbox :checked="isSelected(item)" @change="checked => toggle(checked, item)" /> <Checkbox
:checked="isSelected(item)"
@change="checked => toggle(checked, item)"
/>
</div> </div>
<slot name="item" :item="item" /> <slot
name="item"
:item="item"
/>
</div> </div>
</template> </template>
<template slot="empty"><slot name="empty" /></template> <template slot="empty">
<slot name="empty" />
</template>
</List> </List>
</div> </div>
</template> </template>

View file

@ -7,11 +7,19 @@
<transition name="fade"> <transition name="fade">
<template v-if="currentSaveStateNotice"> <template v-if="currentSaveStateNotice">
<div @click.prevent class="alert error" v-if="currentSaveStateNotice.error"> <div
v-if="currentSaveStateNotice.error"
class="alert error"
@click.prevent
>
{{ $t('settings.saving_err') }} {{ $t('settings.saving_err') }}
</div> </div>
<div @click.prevent class="alert transparent" v-if="!currentSaveStateNotice.error"> <div
v-if="!currentSaveStateNotice.error"
class="alert transparent"
@click.prevent
>
{{ $t('settings.saving_ok') }} {{ $t('settings.saving_ok') }}
</div> </div>
</template> </template>
@ -28,7 +36,11 @@
<interface-language-switcher /> <interface-language-switcher />
</li> </li>
<li v-if="instanceSpecificPanelPresent"> <li v-if="instanceSpecificPanelPresent">
<input type="checkbox" id="hideISP" v-model="hideISPLocal"> <input
id="hideISP"
v-model="hideISPLocal"
type="checkbox"
>
<label for="hideISP">{{ $t('settings.hide_isp') }}</label> <label for="hideISP">{{ $t('settings.hide_isp') }}</label>
</li> </li>
</ul> </ul>
@ -37,29 +49,57 @@
<h2>{{ $t('nav.timeline') }}</h2> <h2>{{ $t('nav.timeline') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<input type="checkbox" id="hideMutedPosts" v-model="hideMutedPostsLocal"> <input
id="hideMutedPosts"
v-model="hideMutedPostsLocal"
type="checkbox"
>
<label for="hideMutedPosts">{{ $t('settings.hide_muted_posts') }} {{ $t('settings.instance_default', { value: hideMutedPostsDefault }) }}</label> <label for="hideMutedPosts">{{ $t('settings.hide_muted_posts') }} {{ $t('settings.instance_default', { value: hideMutedPostsDefault }) }}</label>
</li> </li>
<li> <li>
<input type="checkbox" id="collapseMessageWithSubject" v-model="collapseMessageWithSubjectLocal"> <input
id="collapseMessageWithSubject"
v-model="collapseMessageWithSubjectLocal"
type="checkbox"
>
<label for="collapseMessageWithSubject">{{ $t('settings.collapse_subject') }} {{ $t('settings.instance_default', { value: collapseMessageWithSubjectDefault }) }}</label> <label for="collapseMessageWithSubject">{{ $t('settings.collapse_subject') }} {{ $t('settings.instance_default', { value: collapseMessageWithSubjectDefault }) }}</label>
</li> </li>
<li> <li>
<input type="checkbox" id="streaming" v-model="streamingLocal"> <input
id="streaming"
v-model="streamingLocal"
type="checkbox"
>
<label for="streaming">{{ $t('settings.streaming') }}</label> <label for="streaming">{{ $t('settings.streaming') }}</label>
<ul class="setting-list suboptions" :class="[{disabled: !streamingLocal}]"> <ul
class="setting-list suboptions"
:class="[{disabled: !streamingLocal}]"
>
<li> <li>
<input :disabled="!streamingLocal" type="checkbox" id="pauseOnUnfocused" v-model="pauseOnUnfocusedLocal"> <input
id="pauseOnUnfocused"
v-model="pauseOnUnfocusedLocal"
:disabled="!streamingLocal"
type="checkbox"
>
<label for="pauseOnUnfocused">{{ $t('settings.pause_on_unfocused') }}</label> <label for="pauseOnUnfocused">{{ $t('settings.pause_on_unfocused') }}</label>
</li> </li>
</ul> </ul>
</li> </li>
<li> <li>
<input type="checkbox" id="autoload" v-model="autoLoadLocal"> <input
id="autoload"
v-model="autoLoadLocal"
type="checkbox"
>
<label for="autoload">{{ $t('settings.autoload') }}</label> <label for="autoload">{{ $t('settings.autoload') }}</label>
</li> </li>
<li> <li>
<input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal"> <input
id="hoverPreview"
v-model="hoverPreviewLocal"
type="checkbox"
>
<label for="hoverPreview">{{ $t('settings.reply_link_preview') }}</label> <label for="hoverPreview">{{ $t('settings.reply_link_preview') }}</label>
</li> </li>
</ul> </ul>
@ -69,13 +109,21 @@
<h2>{{ $t('settings.composing') }}</h2> <h2>{{ $t('settings.composing') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<input type="checkbox" id="scopeCopy" v-model="scopeCopyLocal"> <input
id="scopeCopy"
v-model="scopeCopyLocal"
type="checkbox"
>
<label for="scopeCopy"> <label for="scopeCopy">
{{ $t('settings.scope_copy') }} {{ $t('settings.instance_default', { value: scopeCopyDefault }) }} {{ $t('settings.scope_copy') }} {{ $t('settings.instance_default', { value: scopeCopyDefault }) }}
</label> </label>
</li> </li>
<li> <li>
<input type="checkbox" id="subjectHide" v-model="alwaysShowSubjectInputLocal"> <input
id="subjectHide"
v-model="alwaysShowSubjectInputLocal"
type="checkbox"
>
<label for="subjectHide"> <label for="subjectHide">
{{ $t('settings.subject_input_always_show') }} {{ $t('settings.instance_default', { value: alwaysShowSubjectInputDefault }) }} {{ $t('settings.subject_input_always_show') }} {{ $t('settings.instance_default', { value: alwaysShowSubjectInputDefault }) }}
</label> </label>
@ -83,8 +131,14 @@
<li> <li>
<div> <div>
{{ $t('settings.subject_line_behavior') }} {{ $t('settings.subject_line_behavior') }}
<label for="subjectLineBehavior" class="select"> <label
<select id="subjectLineBehavior" v-model="subjectLineBehaviorLocal"> for="subjectLineBehavior"
class="select"
>
<select
id="subjectLineBehavior"
v-model="subjectLineBehaviorLocal"
>
<option value="email"> <option value="email">
{{ $t('settings.subject_line_email') }} {{ $t('settings.subject_line_email') }}
{{ subjectLineBehaviorDefault == 'email' ? $t('settings.instance_default_simple') : '' }} {{ subjectLineBehaviorDefault == 'email' ? $t('settings.instance_default_simple') : '' }}
@ -105,9 +159,19 @@
<li v-if="postFormats.length > 0"> <li v-if="postFormats.length > 0">
<div> <div>
{{ $t('settings.post_status_content_type') }} {{ $t('settings.post_status_content_type') }}
<label for="postContentType" class="select"> <label
<select id="postContentType" v-model="postContentTypeLocal"> for="postContentType"
<option v-for="postFormat in postFormats" :key="postFormat" :value="postFormat"> class="select"
>
<select
id="postContentType"
v-model="postContentTypeLocal"
>
<option
v-for="postFormat in postFormats"
:key="postFormat"
:value="postFormat"
>
{{ $t(`post_status.content_type["${postFormat}"]`) }} {{ $t(`post_status.content_type["${postFormat}"]`) }}
{{ postContentTypeDefault === postFormat ? $t('settings.instance_default_simple') : '' }} {{ postContentTypeDefault === postFormat ? $t('settings.instance_default_simple') : '' }}
</option> </option>
@ -117,13 +181,21 @@
</div> </div>
</li> </li>
<li> <li>
<input type="checkbox" id="minimalScopesMode" v-model="minimalScopesModeLocal"> <input
id="minimalScopesMode"
v-model="minimalScopesModeLocal"
type="checkbox"
>
<label for="minimalScopesMode"> <label for="minimalScopesMode">
{{ $t('settings.minimal_scopes_mode') }} {{ $t('settings.instance_default', { value: minimalScopesModeDefault }) }} {{ $t('settings.minimal_scopes_mode') }} {{ $t('settings.instance_default', { value: minimalScopesModeDefault }) }}
</label> </label>
</li> </li>
<li> <li>
<input type="checkbox" id="autohideFloatingPostButton" v-model="autohideFloatingPostButtonLocal"> <input
id="autohideFloatingPostButton"
v-model="autohideFloatingPostButtonLocal"
type="checkbox"
>
<label for="autohideFloatingPostButton">{{ $t('settings.autohide_floating_post_button') }}</label> <label for="autohideFloatingPostButton">{{ $t('settings.autohide_floating_post_button') }}</label>
</li> </li>
</ul> </ul>
@ -133,54 +205,110 @@
<h2>{{ $t('settings.attachments') }}</h2> <h2>{{ $t('settings.attachments') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<input type="checkbox" id="hideAttachments" v-model="hideAttachmentsLocal"> <input
id="hideAttachments"
v-model="hideAttachmentsLocal"
type="checkbox"
>
<label for="hideAttachments">{{ $t('settings.hide_attachments_in_tl') }}</label> <label for="hideAttachments">{{ $t('settings.hide_attachments_in_tl') }}</label>
</li> </li>
<li> <li>
<input type="checkbox" id="hideAttachmentsInConv" v-model="hideAttachmentsInConvLocal"> <input
id="hideAttachmentsInConv"
v-model="hideAttachmentsInConvLocal"
type="checkbox"
>
<label for="hideAttachmentsInConv">{{ $t('settings.hide_attachments_in_convo') }}</label> <label for="hideAttachmentsInConv">{{ $t('settings.hide_attachments_in_convo') }}</label>
</li> </li>
<li> <li>
<label for="maxThumbnails">{{ $t('settings.max_thumbnails') }}</label> <label for="maxThumbnails">{{ $t('settings.max_thumbnails') }}</label>
<input class="number-input" type="number" id="maxThumbnails" v-model.number="maxThumbnails" min="0" step="1"> <input
id="maxThumbnails"
v-model.number="maxThumbnails"
class="number-input"
type="number"
min="0"
step="1"
>
</li> </li>
<li> <li>
<input type="checkbox" id="hideNsfw" v-model="hideNsfwLocal"> <input
id="hideNsfw"
v-model="hideNsfwLocal"
type="checkbox"
>
<label for="hideNsfw">{{ $t('settings.nsfw_clickthrough') }}</label> <label for="hideNsfw">{{ $t('settings.nsfw_clickthrough') }}</label>
</li> </li>
<ul class="setting-list suboptions"> <ul class="setting-list suboptions">
<li> <li>
<input :disabled="!hideNsfwLocal" type="checkbox" id="preloadImage" v-model="preloadImage"> <input
id="preloadImage"
v-model="preloadImage"
:disabled="!hideNsfwLocal"
type="checkbox"
>
<label for="preloadImage">{{ $t('settings.preload_images') }}</label> <label for="preloadImage">{{ $t('settings.preload_images') }}</label>
</li> </li>
<li> <li>
<input :disabled="!hideNsfwLocal" type="checkbox" id="useOneClickNsfw" v-model="useOneClickNsfw"> <input
id="useOneClickNsfw"
v-model="useOneClickNsfw"
:disabled="!hideNsfwLocal"
type="checkbox"
>
<label for="useOneClickNsfw">{{ $t('settings.use_one_click_nsfw') }}</label> <label for="useOneClickNsfw">{{ $t('settings.use_one_click_nsfw') }}</label>
</li> </li>
</ul> </ul>
<li> <li>
<input type="checkbox" id="stopGifs" v-model="stopGifs"> <input
id="stopGifs"
v-model="stopGifs"
type="checkbox"
>
<label for="stopGifs">{{ $t('settings.stop_gifs') }}</label> <label for="stopGifs">{{ $t('settings.stop_gifs') }}</label>
</li> </li>
<li> <li>
<input type="checkbox" id="loopVideo" v-model="loopVideoLocal"> <input
id="loopVideo"
v-model="loopVideoLocal"
type="checkbox"
>
<label for="loopVideo">{{ $t('settings.loop_video') }}</label> <label for="loopVideo">{{ $t('settings.loop_video') }}</label>
<ul class="setting-list suboptions" :class="[{disabled: !streamingLocal}]"> <ul
class="setting-list suboptions"
:class="[{disabled: !streamingLocal}]"
>
<li> <li>
<input :disabled="!loopVideoLocal || !loopSilentAvailable" type="checkbox" id="loopVideoSilentOnly" v-model="loopVideoSilentOnlyLocal"> <input
id="loopVideoSilentOnly"
v-model="loopVideoSilentOnlyLocal"
:disabled="!loopVideoLocal || !loopSilentAvailable"
type="checkbox"
>
<label for="loopVideoSilentOnly">{{ $t('settings.loop_video_silent_only') }}</label> <label for="loopVideoSilentOnly">{{ $t('settings.loop_video_silent_only') }}</label>
<div v-if="!loopSilentAvailable" class="unavailable"> <div
v-if="!loopSilentAvailable"
class="unavailable"
>
<i class="icon-globe" />! {{ $t('settings.limited_availability') }} <i class="icon-globe" />! {{ $t('settings.limited_availability') }}
</div> </div>
</li> </li>
</ul> </ul>
</li> </li>
<li> <li>
<input type="checkbox" id="playVideosInModal" v-model="playVideosInModal"> <input
id="playVideosInModal"
v-model="playVideosInModal"
type="checkbox"
>
<label for="playVideosInModal">{{ $t('settings.play_videos_in_modal') }}</label> <label for="playVideosInModal">{{ $t('settings.play_videos_in_modal') }}</label>
</li> </li>
<li> <li>
<input type="checkbox" id="useContainFit" v-model="useContainFit"> <input
id="useContainFit"
v-model="useContainFit"
type="checkbox"
>
<label for="useContainFit">{{ $t('settings.use_contain_fit') }}</label> <label for="useContainFit">{{ $t('settings.use_contain_fit') }}</label>
</li> </li>
</ul> </ul>
@ -190,7 +318,11 @@
<h2>{{ $t('settings.notifications') }}</h2> <h2>{{ $t('settings.notifications') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<input type="checkbox" id="webPushNotifications" v-model="webPushNotificationsLocal"> <input
id="webPushNotifications"
v-model="webPushNotificationsLocal"
type="checkbox"
>
<label for="webPushNotifications"> <label for="webPushNotifications">
{{ $t('settings.enable_web_push_notifications') }} {{ $t('settings.enable_web_push_notifications') }}
</label> </label>
@ -201,7 +333,7 @@
<div :label="$t('settings.theme')"> <div :label="$t('settings.theme')">
<div class="setting-item"> <div class="setting-item">
<style-switcher></style-switcher> <style-switcher />
</div> </div>
</div> </div>
@ -211,25 +343,41 @@
<span class="label">{{ $t('settings.notification_visibility') }}</span> <span class="label">{{ $t('settings.notification_visibility') }}</span>
<ul class="option-list"> <ul class="option-list">
<li> <li>
<input type="checkbox" id="notification-visibility-likes" v-model="notificationVisibilityLocal.likes"> <input
id="notification-visibility-likes"
v-model="notificationVisibilityLocal.likes"
type="checkbox"
>
<label for="notification-visibility-likes"> <label for="notification-visibility-likes">
{{ $t('settings.notification_visibility_likes') }} {{ $t('settings.notification_visibility_likes') }}
</label> </label>
</li> </li>
<li> <li>
<input type="checkbox" id="notification-visibility-repeats" v-model="notificationVisibilityLocal.repeats"> <input
id="notification-visibility-repeats"
v-model="notificationVisibilityLocal.repeats"
type="checkbox"
>
<label for="notification-visibility-repeats"> <label for="notification-visibility-repeats">
{{ $t('settings.notification_visibility_repeats') }} {{ $t('settings.notification_visibility_repeats') }}
</label> </label>
</li> </li>
<li> <li>
<input type="checkbox" id="notification-visibility-follows" v-model="notificationVisibilityLocal.follows"> <input
id="notification-visibility-follows"
v-model="notificationVisibilityLocal.follows"
type="checkbox"
>
<label for="notification-visibility-follows"> <label for="notification-visibility-follows">
{{ $t('settings.notification_visibility_follows') }} {{ $t('settings.notification_visibility_follows') }}
</label> </label>
</li> </li>
<li> <li>
<input type="checkbox" id="notification-visibility-mentions" v-model="notificationVisibilityLocal.mentions"> <input
id="notification-visibility-mentions"
v-model="notificationVisibilityLocal.mentions"
type="checkbox"
>
<label for="notification-visibility-mentions"> <label for="notification-visibility-mentions">
{{ $t('settings.notification_visibility_mentions') }} {{ $t('settings.notification_visibility_mentions') }}
</label> </label>
@ -238,9 +386,18 @@
</div> </div>
<div> <div>
{{ $t('settings.replies_in_timeline') }} {{ $t('settings.replies_in_timeline') }}
<label for="replyVisibility" class="select"> <label
<select id="replyVisibility" v-model="replyVisibilityLocal"> for="replyVisibility"
<option value="all" selected>{{$t('settings.reply_visibility_all')}}</option> class="select"
>
<select
id="replyVisibility"
v-model="replyVisibilityLocal"
>
<option
value="all"
selected
>{{ $t('settings.reply_visibility_all') }}</option>
<option value="following">{{ $t('settings.reply_visibility_following') }}</option> <option value="following">{{ $t('settings.reply_visibility_following') }}</option>
<option value="self">{{ $t('settings.reply_visibility_self') }}</option> <option value="self">{{ $t('settings.reply_visibility_self') }}</option>
</select> </select>
@ -248,13 +405,21 @@
</label> </label>
</div> </div>
<div> <div>
<input type="checkbox" id="hidePostStats" v-model="hidePostStatsLocal"> <input
id="hidePostStats"
v-model="hidePostStatsLocal"
type="checkbox"
>
<label for="hidePostStats"> <label for="hidePostStats">
{{ $t('settings.hide_post_stats') }} {{ $t('settings.instance_default', { value: hidePostStatsDefault }) }} {{ $t('settings.hide_post_stats') }} {{ $t('settings.instance_default', { value: hidePostStatsDefault }) }}
</label> </label>
</div> </div>
<div> <div>
<input type="checkbox" id="hideUserStats" v-model="hideUserStatsLocal"> <input
id="hideUserStats"
v-model="hideUserStatsLocal"
type="checkbox"
>
<label for="hideUserStats"> <label for="hideUserStats">
{{ $t('settings.hide_user_stats') }} {{ $t('settings.instance_default', { value: hideUserStatsDefault }) }} {{ $t('settings.hide_user_stats') }} {{ $t('settings.instance_default', { value: hideUserStatsDefault }) }}
</label> </label>
@ -263,10 +428,17 @@
<div class="setting-item"> <div class="setting-item">
<div> <div>
<p>{{ $t('settings.filtering_explanation') }}</p> <p>{{ $t('settings.filtering_explanation') }}</p>
<textarea id="muteWords" v-model="muteWordsString"></textarea> <textarea
id="muteWords"
v-model="muteWordsString"
/>
</div> </div>
<div> <div>
<input type="checkbox" id="hideFilteredStatuses" v-model="hideFilteredStatusesLocal"> <input
id="hideFilteredStatuses"
v-model="hideFilteredStatusesLocal"
type="checkbox"
>
<label for="hideFilteredStatuses"> <label for="hideFilteredStatuses">
{{ $t('settings.hide_filtered_statuses') }} {{ $t('settings.instance_default', { value: hideFilteredStatusesDefault }) }} {{ $t('settings.hide_filtered_statuses') }} {{ $t('settings.instance_default', { value: hideFilteredStatusesDefault }) }}
</label> </label>
@ -280,7 +452,10 @@
<p>{{ $t('settings.version.backend_version') }}</p> <p>{{ $t('settings.version.backend_version') }}</p>
<ul class="option-list"> <ul class="option-list">
<li> <li>
<a :href="backendVersionLink" target="_blank">{{backendVersion}}</a> <a
:href="backendVersionLink"
target="_blank"
>{{ backendVersion }}</a>
</li> </li>
</ul> </ul>
</li> </li>
@ -288,7 +463,10 @@
<p>{{ $t('settings.version.frontend_version') }}</p> <p>{{ $t('settings.version.frontend_version') }}</p>
<ul class="option-list"> <ul class="option-list">
<li> <li>
<a :href="frontendVersionLink" target="_blank">{{frontendVersion}}</a> <a
:href="frontendVersionLink"
target="_blank"
>{{ frontendVersion }}</a>
</li> </li>
</ul> </ul>
</li> </li>

View file

@ -1,12 +1,19 @@
<template> <template>
<div class="shadow-control" :class="{ disabled: !present }"> <div
class="shadow-control"
:class="{ disabled: !present }"
>
<div class="shadow-preview-container"> <div class="shadow-preview-container">
<div :disabled="!present" class="y-shift-control"> <div
:disabled="!present"
class="y-shift-control"
>
<input <input
v-model="selected.y" v-model="selected.y"
:disabled="!present" :disabled="!present"
class="input-number" class="input-number"
type="number"> type="number"
>
<div class="wrap"> <div class="wrap">
<input <input
v-model="selected.y" v-model="selected.y"
@ -14,18 +21,26 @@
class="input-range" class="input-range"
type="range" type="range"
max="20" max="20"
min="-20"> min="-20"
>
</div> </div>
</div> </div>
<div class="preview-window"> <div class="preview-window">
<div class="preview-block" :style="style"></div> <div
class="preview-block"
:style="style"
/>
</div> </div>
<div :disabled="!present" class="x-shift-control"> <div
:disabled="!present"
class="x-shift-control"
>
<input <input
v-model="selected.x" v-model="selected.x"
:disabled="!present" :disabled="!present"
class="input-number" class="input-number"
type="number"> type="number"
>
<div class="wrap"> <div class="wrap">
<input <input
v-model="selected.x" v-model="selected.x"
@ -33,97 +48,155 @@
class="input-range" class="input-range"
type="range" type="range"
max="20" max="20"
min="-20"> min="-20"
>
</div> </div>
</div> </div>
</div> </div>
<div class="shadow-tweak"> <div class="shadow-tweak">
<div :disabled="usingFallback" class="id-control style-control"> <div
<label for="shadow-switcher" class="select" :disabled="!ready || usingFallback"> :disabled="usingFallback"
<select class="id-control style-control"
v-model="selectedId" class="shadow-switcher" >
<label
for="shadow-switcher"
class="select"
:disabled="!ready || usingFallback" :disabled="!ready || usingFallback"
id="shadow-switcher"> >
<option v-for="(shadow, index) in cValue" :value="index"> <select
id="shadow-switcher"
v-model="selectedId"
class="shadow-switcher"
:disabled="!ready || usingFallback"
>
<option
v-for="(shadow, index) in cValue"
:key="index"
:value="index"
>
{{ $t('settings.style.shadows.shadow_id', { value: index }) }} {{ $t('settings.style.shadows.shadow_id', { value: index }) }}
</option> </option>
</select> </select>
<i class="icon-down-open" /> <i class="icon-down-open" />
</label> </label>
<button class="btn btn-default" :disabled="!ready || !present" @click="del"> <button
class="btn btn-default"
:disabled="!ready || !present"
@click="del"
>
<i class="icon-cancel" /> <i class="icon-cancel" />
</button> </button>
<button class="btn btn-default" :disabled="!moveUpValid" @click="moveUp"> <button
class="btn btn-default"
:disabled="!moveUpValid"
@click="moveUp"
>
<i class="icon-up-open" /> <i class="icon-up-open" />
</button> </button>
<button class="btn btn-default" :disabled="!moveDnValid" @click="moveDn"> <button
class="btn btn-default"
:disabled="!moveDnValid"
@click="moveDn"
>
<i class="icon-down-open" /> <i class="icon-down-open" />
</button> </button>
<button class="btn btn-default" :disabled="usingFallback" @click="add"> <button
class="btn btn-default"
:disabled="usingFallback"
@click="add"
>
<i class="icon-plus" /> <i class="icon-plus" />
</button> </button>
</div> </div>
<div :disabled="!present" class="inset-control style-control"> <div
<label for="inset" class="label"> :disabled="!present"
class="inset-control style-control"
>
<label
for="inset"
class="label"
>
{{ $t('settings.style.shadows.inset') }} {{ $t('settings.style.shadows.inset') }}
</label> </label>
<input <input
id="inset"
v-model="selected.inset" v-model="selected.inset"
:disabled="!present" :disabled="!present"
name="inset" name="inset"
id="inset"
class="input-inset" class="input-inset"
type="checkbox"> type="checkbox"
<label class="checkbox-label" for="inset"></label> >
<label
class="checkbox-label"
for="inset"
/>
</div> </div>
<div :disabled="!present" class="blur-control style-control"> <div
<label for="spread" class="label"> :disabled="!present"
class="blur-control style-control"
>
<label
for="spread"
class="label"
>
{{ $t('settings.style.shadows.blur') }} {{ $t('settings.style.shadows.blur') }}
</label> </label>
<input <input
id="blur"
v-model="selected.blur" v-model="selected.blur"
:disabled="!present" :disabled="!present"
name="blur" name="blur"
id="blur"
class="input-range" class="input-range"
type="range" type="range"
max="20" max="20"
min="0"> min="0"
>
<input <input
v-model="selected.blur" v-model="selected.blur"
:disabled="!present" :disabled="!present"
class="input-number" class="input-number"
type="number" type="number"
min="0"> min="0"
>
</div> </div>
<div :disabled="!present" class="spread-control style-control"> <div
<label for="spread" class="label"> :disabled="!present"
class="spread-control style-control"
>
<label
for="spread"
class="label"
>
{{ $t('settings.style.shadows.spread') }} {{ $t('settings.style.shadows.spread') }}
</label> </label>
<input <input
id="spread"
v-model="selected.spread" v-model="selected.spread"
:disabled="!present" :disabled="!present"
name="spread" name="spread"
id="spread"
class="input-range" class="input-range"
type="range" type="range"
max="20" max="20"
min="-20"> min="-20"
>
<input <input
v-model="selected.spread" v-model="selected.spread"
:disabled="!present" :disabled="!present"
class="input-number" class="input-number"
type="number"> type="number"
>
</div> </div>
<ColorInput <ColorInput
v-model="selected.color" v-model="selected.color"
:disabled="!present" :disabled="!present"
:label="$t('settings.style.common.color')" :label="$t('settings.style.common.color')"
name="shadow"/> name="shadow"
/>
<OpacityInput <OpacityInput
v-model="selected.alpha" v-model="selected.alpha"
:disabled="!present"/> :disabled="!present"
/>
<p> <p>
{{ $t('settings.style.shadows.hint') }} {{ $t('settings.style.shadows.hint') }}
</p> </p>

View file

@ -1,63 +1,98 @@
<template> <template>
<div class="side-drawer-container" <div
class="side-drawer-container"
:class="{ 'side-drawer-container-closed': closed, 'side-drawer-container-open': !closed }" :class="{ 'side-drawer-container-closed': closed, 'side-drawer-container-open': !closed }"
> >
<div class="side-drawer-darken" :class="{ 'side-drawer-darken-closed': closed}" /> <div
<div class="side-drawer" class="side-drawer-darken"
:class="{ 'side-drawer-darken-closed': closed}"
/>
<div
class="side-drawer"
:class="{'side-drawer-closed': closed}" :class="{'side-drawer-closed': closed}"
@touchstart="touchStart" @touchstart="touchStart"
@touchmove="touchMove" @touchmove="touchMove"
> >
<div class="side-drawer-heading" @click="toggleDrawer"> <div
<UserCard :user="currentUser" :hideBio="true" v-if="currentUser"/> class="side-drawer-heading"
<div class="side-drawer-logo-wrapper" v-else> @click="toggleDrawer"
<img :src="logo"/> >
<UserCard
v-if="currentUser"
:user="currentUser"
:hide-bio="true"
/>
<div
v-else
class="side-drawer-logo-wrapper"
>
<img :src="logo">
<span>{{ sitename }}</span> <span>{{ sitename }}</span>
</div> </div>
</div> </div>
<ul> <ul>
<li v-if="!currentUser" @click="toggleDrawer"> <li
v-if="!currentUser"
@click="toggleDrawer"
>
<router-link :to="{ name: 'login' }"> <router-link :to="{ name: 'login' }">
{{ $t("login.login") }} {{ $t("login.login") }}
</router-link> </router-link>
</li> </li>
<li v-if="currentUser" @click="toggleDrawer"> <li
v-if="currentUser"
@click="toggleDrawer"
>
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }"> <router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
{{ $t("nav.dms") }} {{ $t("nav.dms") }}
</router-link> </router-link>
</li> </li>
<li v-if="currentUser" @click="toggleDrawer"> <li
v-if="currentUser"
@click="toggleDrawer"
>
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }"> <router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
{{ $t("nav.interactions") }} {{ $t("nav.interactions") }}
</router-link> </router-link>
</li> </li>
</ul> </ul>
<ul> <ul>
<li v-if="currentUser" @click="toggleDrawer"> <li
v-if="currentUser"
@click="toggleDrawer"
>
<router-link :to="{ name: 'friends' }"> <router-link :to="{ name: 'friends' }">
{{ $t("nav.timeline") }} {{ $t("nav.timeline") }}
</router-link> </router-link>
</li> </li>
<li v-if="currentUser && currentUser.locked" @click="toggleDrawer"> <li
<router-link to='/friend-requests'> v-if="currentUser && currentUser.locked"
@click="toggleDrawer"
>
<router-link to="/friend-requests">
{{ $t("nav.friend_requests") }} {{ $t("nav.friend_requests") }}
<span v-if='followRequestCount > 0' class="badge follow-request-count"> <span
v-if="followRequestCount > 0"
class="badge follow-request-count"
>
{{ followRequestCount }} {{ followRequestCount }}
</span> </span>
</router-link> </router-link>
</li> </li>
<li @click="toggleDrawer"> <li @click="toggleDrawer">
<router-link to='/main/public'> <router-link to="/main/public">
{{ $t("nav.public_tl") }} {{ $t("nav.public_tl") }}
</router-link> </router-link>
</li> </li>
<li @click="toggleDrawer"> <li @click="toggleDrawer">
<router-link to='/main/all'> <router-link to="/main/all">
{{ $t("nav.twkn") }} {{ $t("nav.twkn") }}
</router-link> </router-link>
</li> </li>
<li v-if="currentUser && chat" @click="toggleDrawer"> <li
v-if="currentUser && chat"
@click="toggleDrawer"
>
<router-link :to="{ name: 'chat' }"> <router-link :to="{ name: 'chat' }">
{{ $t("nav.chat") }} {{ $t("nav.chat") }}
</router-link> </router-link>
@ -69,7 +104,10 @@
{{ $t("nav.user_search") }} {{ $t("nav.user_search") }}
</router-link> </router-link>
</li> </li>
<li v-if="currentUser && suggestionsEnabled" @click="toggleDrawer"> <li
v-if="currentUser && suggestionsEnabled"
@click="toggleDrawer"
>
<router-link :to="{ name: 'who-to-follow' }"> <router-link :to="{ name: 'who-to-follow' }">
{{ $t("nav.who_to_follow") }} {{ $t("nav.who_to_follow") }}
</router-link> </router-link>
@ -84,17 +122,24 @@
{{ $t("nav.about") }} {{ $t("nav.about") }}
</router-link> </router-link>
</li> </li>
<li v-if="currentUser" @click="toggleDrawer"> <li
<a @click="doLogout" href="#"> v-if="currentUser"
@click="toggleDrawer"
>
<a
href="#"
@click="doLogout"
>
{{ $t("login.logout") }} {{ $t("login.logout") }}
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="side-drawer-click-outside" <div
@click.stop.prevent="toggleDrawer" class="side-drawer-click-outside"
:class="{'side-drawer-click-outside-closed': closed}" :class="{'side-drawer-click-outside-closed': closed}"
></div> @click.stop.prevent="toggleDrawer"
/>
</div> </div>
</template> </template>

View file

@ -173,12 +173,13 @@ const Status = {
if (this.status.type === 'retweet') { if (this.status.type === 'retweet') {
return false return false
} }
var checkFollowing = this.$store.state.config.replyVisibility === 'following' const checkFollowing = this.$store.state.config.replyVisibility === 'following'
for (var i = 0; i < this.status.attentions.length; ++i) { for (var i = 0; i < this.status.attentions.length; ++i) {
if (this.status.user.id === this.status.attentions[i].id) { if (this.status.user.id === this.status.attentions[i].id) {
continue continue
} }
if (checkFollowing && this.$store.getters.findUser(this.status.attentions[i].id).following) { const taggedUser = this.$store.getters.findUser(this.status.attentions[i].id)
if (checkFollowing && taggedUser && taggedUser.following) {
return false return false
} }
if (this.status.attentions[i].id === this.$store.state.users.currentUser.id) { if (this.status.attentions[i].id === this.$store.state.users.currentUser.id) {
@ -221,7 +222,7 @@ const Status = {
? this.$store.state.instance.subjectLineBehavior ? this.$store.state.instance.subjectLineBehavior
: this.$store.state.config.subjectLineBehavior : this.$store.state.config.subjectLineBehavior
const startsWithRe = decodedSummary.match(/^re[: ]/i) const startsWithRe = decodedSummary.match(/^re[: ]/i)
if (behavior !== 'noop' && startsWithRe || behavior === 'masto') { if ((behavior !== 'noop' && startsWithRe) || behavior === 'masto') {
return decodedSummary return decodedSummary
} else if (behavior === 'email') { } else if (behavior === 'email') {
return 're: '.concat(decodedSummary) return 're: '.concat(decodedSummary)

View file

@ -1,8 +1,19 @@
<template> <template>
<div class="status-el" v-if="!hideStatus" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"> <!-- eslint-disable vue/no-v-html -->
<div v-if="error" class="alert error"> <div
v-if="!hideStatus"
class="status-el"
:class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"
>
<div
v-if="error"
class="alert error"
>
{{ error }} {{ error }}
<i class="button-icon icon-cancel" @click="clearError"></i> <i
class="button-icon icon-cancel"
@click="clearError"
/>
</div> </div>
<template v-if="muted && !isPreview"> <template v-if="muted && !isPreview">
<div class="media status container muted"> <div class="media status container muted">
@ -12,179 +23,409 @@
</router-link> </router-link>
</small> </small>
<small class="muteWords">{{ muteWordHits.join(', ') }}</small> <small class="muteWords">{{ muteWordHits.join(', ') }}</small>
<a href="#" class="unmute" @click.prevent="toggleMute"><i class="button-icon icon-eye-off"></i></a> <a
href="#"
class="unmute"
@click.prevent="toggleMute"
><i class="button-icon icon-eye-off" /></a>
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div v-if="showPinned && statusoid.pinned" class="status-pin"> <div
<i class="fa icon-pin faint"></i> v-if="showPinned && statusoid.pinned"
class="status-pin"
>
<i class="fa icon-pin faint" />
<span class="faint">{{ $t('status.pinned') }}</span> <span class="faint">{{ $t('status.pinned') }}</span>
</div> </div>
<div v-if="retweet && !noHeading && !inConversation" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info"> <div
<UserAvatar class="media-left" v-if="retweet" :betterShadow="betterShadow" :user="statusoid.user"/> v-if="retweet && !noHeading && !inConversation"
:class="[repeaterClass, { highlighted: repeaterStyle }]"
:style="[repeaterStyle]"
class="media container retweet-info"
>
<UserAvatar
v-if="retweet"
class="media-left"
:better-shadow="betterShadow"
:user="statusoid.user"
/>
<div class="media-body faint"> <div class="media-body faint">
<span class="user-name"> <span class="user-name">
<router-link v-if="retweeterHtml" :to="retweeterProfileLink" v-html="retweeterHtml"/> <router-link
<router-link v-else :to="retweeterProfileLink">{{retweeter}}</router-link> v-if="retweeterHtml"
:to="retweeterProfileLink"
v-html="retweeterHtml"
/>
<router-link
v-else
:to="retweeterProfileLink"
>{{ retweeter }}</router-link>
</span> </span>
<i class='fa icon-retweet retweeted' :title="$t('tool_tip.repeat')"></i> <i
class="fa icon-retweet retweeted"
:title="$t('tool_tip.repeat')"
/>
{{ $t('timeline.repeated') }} {{ $t('timeline.repeated') }}
</div> </div>
</div> </div>
<div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet && !inConversation }]" :style="[ userStyle ]" class="media status" :data-tags="tags"> <div
<div v-if="!noHeading" class="media-left"> :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet && !inConversation }]"
<router-link :to="userProfileLink" @click.stop.prevent.capture.native="toggleUserExpanded"> :style="[ userStyle ]"
<UserAvatar :compact="compact" :betterShadow="betterShadow" :user="status.user"/> class="media status"
:data-tags="tags"
>
<div
v-if="!noHeading"
class="media-left"
>
<router-link
:to="userProfileLink"
@click.stop.prevent.capture.native="toggleUserExpanded"
>
<UserAvatar
:compact="compact"
:better-shadow="betterShadow"
:user="status.user"
/>
</router-link> </router-link>
</div> </div>
<div class="status-body"> <div class="status-body">
<UserCard :user="status.user" :rounded="true" :bordered="true" class="status-usercard" v-if="userExpanded"/> <UserCard
<div v-if="!noHeading" class="media-heading"> v-if="userExpanded"
:user="status.user"
:rounded="true"
:bordered="true"
class="status-usercard"
/>
<div
v-if="!noHeading"
class="media-heading"
>
<div class="heading-name-row"> <div class="heading-name-row">
<div class="name-and-account-name"> <div class="name-and-account-name">
<h4 class="user-name" v-if="status.user.name_html" v-html="status.user.name_html"></h4> <h4
<h4 class="user-name" v-else>{{status.user.name}}</h4> v-if="status.user.name_html"
<router-link class="account-name" :to="userProfileLink"> class="user-name"
v-html="status.user.name_html"
/>
<h4
v-else
class="user-name"
>
{{ status.user.name }}
</h4>
<router-link
class="account-name"
:to="userProfileLink"
>
{{ status.user.screen_name }} {{ status.user.screen_name }}
</router-link> </router-link>
</div> </div>
<span class="heading-right"> <span class="heading-right">
<router-link class="timeago faint-link" :to="{ name: 'conversation', params: { id: status.id } }"> <router-link
<Timeago :time="status.created_at" :auto-update="60"></Timeago> class="timeago faint-link"
:to="{ name: 'conversation', params: { id: status.id } }"
>
<Timeago
:time="status.created_at"
:auto-update="60"
/>
</router-link> </router-link>
<div class="button-icon visibility-icon" v-if="status.visibility"> <div
<i :class="visibilityIcon(status.visibility)" :title="status.visibility | capitalize"></i> v-if="status.visibility"
class="button-icon visibility-icon"
>
<i
:class="visibilityIcon(status.visibility)"
:title="status.visibility | capitalize"
/>
</div> </div>
<a :href="status.external_url" target="_blank" v-if="!status.is_local && !isPreview" class="source_url" title="Source"> <a
<i class="button-icon icon-link-ext-alt"></i> v-if="!status.is_local && !isPreview"
:href="status.external_url"
target="_blank"
class="source_url"
title="Source"
>
<i class="button-icon icon-link-ext-alt" />
</a> </a>
<template v-if="expandable && !isPreview"> <template v-if="expandable && !isPreview">
<a href="#" @click.prevent="toggleExpanded" title="Expand"> <a
<i class="button-icon icon-plus-squared"></i> href="#"
title="Expand"
@click.prevent="toggleExpanded"
>
<i class="button-icon icon-plus-squared" />
</a> </a>
</template> </template>
<a href="#" @click.prevent="toggleMute" v-if="unmuted"><i class="button-icon icon-eye-off"></i></a> <a
v-if="unmuted"
href="#"
@click.prevent="toggleMute"
><i class="button-icon icon-eye-off" /></a>
</span> </span>
</div> </div>
<div class="heading-reply-row"> <div class="heading-reply-row">
<div v-if="isReply" class="reply-to-and-accountname"> <div
<a class="reply-to" v-if="isReply"
href="#" @click.prevent="gotoOriginal(status.in_reply_to_status_id)" class="reply-to-and-accountname"
>
<a
class="reply-to"
href="#"
:aria-label="$t('tool_tip.reply')" :aria-label="$t('tool_tip.reply')"
@click.prevent="gotoOriginal(status.in_reply_to_status_id)"
@mouseenter.prevent.stop="replyEnter(status.in_reply_to_status_id, $event)" @mouseenter.prevent.stop="replyEnter(status.in_reply_to_status_id, $event)"
@mouseleave.prevent.stop="replyLeave()" @mouseleave.prevent.stop="replyLeave()"
> >
<i class="button-icon icon-reply" v-if="!isPreview"></i> <i
v-if="!isPreview"
class="button-icon icon-reply"
/>
<span class="faint-link reply-to-text">{{ $t('status.reply_to') }}</span> <span class="faint-link reply-to-text">{{ $t('status.reply_to') }}</span>
</a> </a>
<router-link :to="replyProfileLink"> <router-link :to="replyProfileLink">
{{ replyToName }} {{ replyToName }}
</router-link> </router-link>
<span class="faint replies-separator" v-if="replies && replies.length"> <span
v-if="replies && replies.length"
class="faint replies-separator"
>
- -
</span> </span>
</div> </div>
<div class="replies" v-if="inConversation && !isPreview"> <div
<span class="faint" v-if="replies && replies.length">{{$t('status.replies_list')}}</span> v-if="inConversation && !isPreview"
<span class="reply-link faint" v-if="replies" v-for="reply in replies"> class="replies"
<a href="#" @click.prevent="gotoOriginal(reply.id)" @mouseenter="replyEnter(reply.id, $event)" @mouseout="replyLeave()">{{reply.name}}</a> >
<span
v-if="replies && replies.length"
class="faint"
>{{ $t('status.replies_list') }}</span>
<template v-if="replies">
<span
v-for="reply in replies"
:key="reply.id"
class="reply-link faint"
>
<a
href="#"
@click.prevent="gotoOriginal(reply.id)"
@mouseenter="replyEnter(reply.id, $event)"
@mouseout="replyLeave()"
>{{ reply.name }}</a>
</span> </span>
</template>
</div>
</div> </div>
</div> </div>
<div
</div> v-if="showPreview"
class="status-preview-container"
<div v-if="showPreview" class="status-preview-container"> >
<status class="status-preview" <status
v-if="preview" v-if="preview"
:isPreview="true" class="status-preview"
:is-preview="true"
:statusoid="preview" :statusoid="preview"
:compact="true" :compact="true"
/> />
<div v-else class="status-preview status-preview-loading"> <div
<i class="icon-spin4 animate-spin"></i> v-else
class="status-preview status-preview-loading"
>
<i class="icon-spin4 animate-spin" />
</div> </div>
</div> </div>
<div class="status-content-wrapper" :class="{ 'tall-status': !showingLongSubject }" v-if="longSubject"> <div
<a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="!showingLongSubject" href="#" @click.prevent="showingLongSubject=true">{{$t("general.show_more")}}</a> v-if="longSubject"
<div @click.prevent="linkClicked" class="status-content media-body" v-html="contentHtml"></div> class="status-content-wrapper"
<a v-if="showingLongSubject" href="#" class="status-unhider" @click.prevent="showingLongSubject=false">{{$t("general.show_less")}}</a> :class="{ 'tall-status': !showingLongSubject }"
>
<a
v-if="!showingLongSubject"
class="tall-status-hider"
:class="{ 'tall-status-hider_focused': isFocused }"
href="#"
@click.prevent="showingLongSubject=true"
>{{ $t("general.show_more") }}</a>
<div
class="status-content media-body"
@click.prevent="linkClicked"
v-html="contentHtml"
/>
<a
v-if="showingLongSubject"
href="#"
class="status-unhider"
@click.prevent="showingLongSubject=false"
>{{ $t("general.show_less") }}</a>
</div> </div>
<div :class="{'tall-status': hideTallStatus}" class="status-content-wrapper" v-else> <div
<a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="hideTallStatus" href="#" @click.prevent="toggleShowMore">{{$t("general.show_more")}}</a> v-else
<div @click.prevent="linkClicked" class="status-content media-body" v-html="contentHtml" v-if="!hideSubjectStatus"></div> :class="{'tall-status': hideTallStatus}"
<div @click.prevent="linkClicked" class="status-content media-body" v-html="status.summary_html" v-else></div> class="status-content-wrapper"
<a v-if="hideSubjectStatus" href="#" class="cw-status-hider" @click.prevent="toggleShowMore">{{$t("general.show_more")}}</a> >
<a v-if="showingMore" href="#" class="status-unhider" @click.prevent="toggleShowMore">{{$t("general.show_less")}}</a> <a
v-if="hideTallStatus"
class="tall-status-hider"
:class="{ 'tall-status-hider_focused': isFocused }"
href="#"
@click.prevent="toggleShowMore"
>{{ $t("general.show_more") }}</a>
<div
v-if="!hideSubjectStatus"
class="status-content media-body"
@click.prevent="linkClicked"
v-html="contentHtml"
/>
<div
v-else
class="status-content media-body"
@click.prevent="linkClicked"
v-html="status.summary_html"
/>
<a
v-if="hideSubjectStatus"
href="#"
class="cw-status-hider"
@click.prevent="toggleShowMore"
>{{ $t("general.show_more") }}</a>
<a
v-if="showingMore"
href="#"
class="status-unhider"
@click.prevent="toggleShowMore"
>{{ $t("general.show_less") }}</a>
</div> </div>
<div v-if="status.poll && status.poll.options"> <div v-if="status.poll && status.poll.options">
<poll :base-poll="status.poll" /> <poll :base-poll="status.poll" />
</div> </div>
<div v-if="status.attachments && (!hideSubjectStatus || showingLongSubject)" class="attachments media-body"> <div
v-if="status.attachments && (!hideSubjectStatus || showingLongSubject)"
class="attachments media-body"
>
<attachment <attachment
class="non-gallery"
v-for="attachment in nonGalleryAttachments" v-for="attachment in nonGalleryAttachments"
:key="attachment.id"
class="non-gallery"
:size="attachmentSize" :size="attachmentSize"
:nsfw="nsfwClickthrough" :nsfw="nsfwClickthrough"
:attachment="attachment" :attachment="attachment"
:allowPlay="true" :allow-play="true"
:setMedia="setMedia()" :set-media="setMedia()"
:key="attachment.id"
/> />
<gallery <gallery
v-if="galleryAttachments.length > 0" v-if="galleryAttachments.length > 0"
:nsfw="nsfwClickthrough" :nsfw="nsfwClickthrough"
:attachments="galleryAttachments" :attachments="galleryAttachments"
:setMedia="setMedia()" :set-media="setMedia()"
/> />
</div> </div>
<div v-if="status.card && !hideSubjectStatus && !noHeading" class="link-preview media-body"> <div
<link-preview :card="status.card" :size="attachmentSize" :nsfw="nsfwClickthrough" /> v-if="status.card && !hideSubjectStatus && !noHeading"
class="link-preview media-body"
>
<link-preview
:card="status.card"
:size="attachmentSize"
:nsfw="nsfwClickthrough"
/>
</div> </div>
<transition name="fade"> <transition name="fade">
<div class="favs-repeated-users" v-if="isFocused && combinedFavsAndRepeatsUsers.length > 0"> <div
v-if="isFocused && combinedFavsAndRepeatsUsers.length > 0"
class="favs-repeated-users"
>
<div class="stats"> <div class="stats">
<div class="stat-count" v-if="statusFromGlobalRepository.rebloggedBy && statusFromGlobalRepository.rebloggedBy.length > 0"> <div
v-if="statusFromGlobalRepository.rebloggedBy && statusFromGlobalRepository.rebloggedBy.length > 0"
class="stat-count"
>
<a class="stat-title">{{ $t('status.repeats') }}</a> <a class="stat-title">{{ $t('status.repeats') }}</a>
<div class="stat-number">{{ statusFromGlobalRepository.rebloggedBy.length }}</div> <div class="stat-number">
{{ statusFromGlobalRepository.rebloggedBy.length }}
</div> </div>
<div class="stat-count" v-if="statusFromGlobalRepository.favoritedBy && statusFromGlobalRepository.favoritedBy.length > 0"> </div>
<div
v-if="statusFromGlobalRepository.favoritedBy && statusFromGlobalRepository.favoritedBy.length > 0"
class="stat-count"
>
<a class="stat-title">{{ $t('status.favorites') }}</a> <a class="stat-title">{{ $t('status.favorites') }}</a>
<div class="stat-number">{{ statusFromGlobalRepository.favoritedBy.length }}</div> <div class="stat-number">
{{ statusFromGlobalRepository.favoritedBy.length }}
</div>
</div> </div>
<div class="avatar-row"> <div class="avatar-row">
<AvatarList :users="combinedFavsAndRepeatsUsers"></AvatarList> <AvatarList :users="combinedFavsAndRepeatsUsers" />
</div> </div>
</div> </div>
</div> </div>
</transition> </transition>
<div v-if="!noHeading && !isPreview" class='status-actions media-body'> <div
v-if="!noHeading && !isPreview"
class="status-actions media-body"
>
<div> <div>
<i class="button-icon icon-reply" v-on:click.prevent="toggleReplying" :title="$t('tool_tip.reply')" :class="{'button-icon-active': replying}" v-if="loggedIn"/> <i
<i class="button-icon button-icon-disabled icon-reply" :title="$t('tool_tip.reply')" v-else /> v-if="loggedIn"
class="button-icon icon-reply"
:title="$t('tool_tip.reply')"
:class="{'button-icon-active': replying}"
@click.prevent="toggleReplying"
/>
<i
v-else
class="button-icon button-icon-disabled icon-reply"
:title="$t('tool_tip.reply')"
/>
<span v-if="status.replies_count > 0">{{ status.replies_count }}</span> <span v-if="status.replies_count > 0">{{ status.replies_count }}</span>
</div> </div>
<retweet-button :visibility='status.visibility' :loggedIn='loggedIn' :status='status'></retweet-button> <retweet-button
<favorite-button :loggedIn='loggedIn' :status='status'></favorite-button> :visibility="status.visibility"
<extra-buttons :status="status" @onError="showError" @onSuccess="clearError"></extra-buttons> :logged-in="loggedIn"
:status="status"
/>
<favorite-button
:logged-in="loggedIn"
:status="status"
/>
<extra-buttons
:status="status"
@onError="showError"
@onSuccess="clearError"
/>
</div> </div>
</div> </div>
</div> </div>
<div class="container" v-if="replying"> <div
<post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" :copy-message-scope="status.visibility" :subject="replySubject" v-on:posted="toggleReplying"/> v-if="replying"
class="container"
>
<post-status-form
class="reply-body"
:reply-to="status.id"
:attentions="status.attentions"
:replied-user="status.user"
:copy-message-scope="status.visibility"
:subject="replySubject"
@posted="toggleReplying"
/>
</div> </div>
</template> </template>
</div> </div>
<!-- eslint-enable vue/no-v-html -->
</template> </template>
<script src="./status.js" ></script> <script src="./status.js" ></script>
@ -453,6 +694,7 @@ $status-margin: 0.75em;
.status-content { .status-content {
font-family: var(--postFont, sans-serif); font-family: var(--postFont, sans-serif);
line-height: 1.4em; line-height: 1.4em;
white-space: pre-wrap;
img, video { img, video {
max-width: 100%; max-width: 100%;

View file

@ -1,7 +1,19 @@
<template> <template>
<div class='still-image' :class='{ animated: animated }' > <div
<canvas ref="canvas" v-if="animated"></canvas> class="still-image"
<img ref="src" :src="src" :referrerpolicy="referrerpolicy" v-on:load="onLoad" @error="onError"/> :class="{ animated: animated }"
>
<canvas
v-if="animated"
ref="canvas"
/>
<img
ref="src"
:src="src"
:referrerpolicy="referrerpolicy"
@load="onLoad"
@error="onError"
>
</div> </div>
</template> </template>

View file

@ -37,10 +37,22 @@
</i18n> </i18n>
<div class="icons"> <div class="icons">
<i style="color: var(--cBlue)" class="button-icon icon-reply"/> <i
<i style="color: var(--cGreen)" class="button-icon icon-retweet"/> style="color: var(--cBlue)"
<i style="color: var(--cOrange)" class="button-icon icon-star"/> class="button-icon icon-reply"
<i style="color: var(--cRed)" class="button-icon icon-cancel"/> />
<i
style="color: var(--cGreen)"
class="button-icon icon-retweet"
/>
<i
style="color: var(--cOrange)"
class="button-icon icon-star"
/>
<i
style="color: var(--cRed)"
class="button-icon icon-cancel"
/>
</div> </div>
</div> </div>
</div> </div>
@ -50,23 +62,34 @@
:^) :^)
</div> </div>
<div class="content"> <div class="content">
<i18n path="settings.style.preview.fine_print" tag="span" class="faint"> <i18n
path="settings.style.preview.fine_print"
tag="span"
class="faint"
>
<a style="color: var(--faintLink)"> <a style="color: var(--faintLink)">
{{ $t('settings.style.preview.faint_link') }} {{ $t('settings.style.preview.faint_link') }}
</a> </a>
</i18n> </i18n>
</div> </div>
</div> </div>
<div class="separator"></div> <div class="separator" />
<span class="alert error"> <span class="alert error">
{{ $t('settings.style.preview.error') }} {{ $t('settings.style.preview.error') }}
</span> </span>
<input :value="$t('settings.style.preview.input')" type="text"> <input
:value="$t('settings.style.preview.input')"
type="text"
>
<div class="actions"> <div class="actions">
<span class="checkbox"> <span class="checkbox">
<input checked="very yes" type="checkbox" id="preview_checkbox"> <input
id="preview_checkbox"
checked="very yes"
type="checkbox"
>
<label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label> <label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
</span> </span>
<button class="btn"> <button class="btn">

View file

@ -3,23 +3,34 @@
<div class="presets-container"> <div class="presets-container">
<div class="save-load"> <div class="save-load">
<export-import <export-import
:exportObject='exportedTheme' :export-object="exportedTheme"
:exportLabel='$t("settings.export_theme")' :export-label="$t(&quot;settings.export_theme&quot;)"
:importLabel='$t("settings.import_theme")' :import-label="$t(&quot;settings.import_theme&quot;)"
:importFailedText='$t("settings.invalid_theme_imported")' :import-failed-text="$t(&quot;settings.invalid_theme_imported&quot;)"
:onImport='onImport' :on-import="onImport"
:validator='importValidator'> :validator="importValidator"
>
<template slot="before"> <template slot="before">
<div class="presets"> <div class="presets">
{{ $t('settings.presets') }} {{ $t('settings.presets') }}
<label for="preset-switcher" class='select'> <label
<select id="preset-switcher" v-model="selected" class="preset-switcher"> for="preset-switcher"
<option v-for="style in availableStyles" class="select"
>
<select
id="preset-switcher"
v-model="selected"
class="preset-switcher"
>
<option
v-for="style in availableStyles"
:key="style.name"
:value="style" :value="style"
:style="{ :style="{
backgroundColor: style[1] || style.theme.colors.bg, backgroundColor: style[1] || style.theme.colors.bg,
color: style[3] || style.theme.colors.text color: style[3] || style.theme.colors.text
}"> }"
>
{{ style[0] || style.name }} {{ style[0] || style.name }}
</option> </option>
</select> </select>
@ -33,36 +44,41 @@
<span class="keep-option"> <span class="keep-option">
<input <input
id="keep-color" id="keep-color"
v-model="keepColor"
type="checkbox" type="checkbox"
v-model="keepColor"> >
<label for="keep-color">{{ $t('settings.style.switcher.keep_color') }}</label> <label for="keep-color">{{ $t('settings.style.switcher.keep_color') }}</label>
</span> </span>
<span class="keep-option"> <span class="keep-option">
<input <input
id="keep-shadows" id="keep-shadows"
v-model="keepShadows"
type="checkbox" type="checkbox"
v-model="keepShadows"> >
<label for="keep-shadows">{{ $t('settings.style.switcher.keep_shadows') }}</label> <label for="keep-shadows">{{ $t('settings.style.switcher.keep_shadows') }}</label>
</span> </span>
<span class="keep-option"> <span class="keep-option">
<input <input
id="keep-opacity" id="keep-opacity"
v-model="keepOpacity"
type="checkbox" type="checkbox"
v-model="keepOpacity"> >
<label for="keep-opacity">{{ $t('settings.style.switcher.keep_opacity') }}</label> <label for="keep-opacity">{{ $t('settings.style.switcher.keep_opacity') }}</label>
</span> </span>
<span class="keep-option"> <span class="keep-option">
<input <input
id="keep-roundness" id="keep-roundness"
v-model="keepRoundness"
type="checkbox" type="checkbox"
v-model="keepRoundness"> >
<label for="keep-roundness">{{ $t('settings.style.switcher.keep_roundness') }}</label> <label for="keep-roundness">{{ $t('settings.style.switcher.keep_roundness') }}</label>
</span> </span>
<span class="keep-option"> <span class="keep-option">
<input <input
id="keep-fonts" id="keep-fonts"
v-model="keepFonts"
type="checkbox" type="checkbox"
v-model="keepFonts"> >
<label for="keep-fonts">{{ $t('settings.style.switcher.keep_fonts') }}</label> <label for="keep-fonts">{{ $t('settings.style.switcher.keep_fonts') }}</label>
</span> </span>
<p>{{ $t('settings.style.switcher.save_load_hint') }}</p> <p>{{ $t('settings.style.switcher.save_load_hint') }}</p>
@ -75,127 +91,382 @@
<keep-alive> <keep-alive>
<tab-switcher key="style-tweak"> <tab-switcher key="style-tweak">
<div :label="$t('settings.style.common_colors._tab_label')" class="color-container"> <div
:label="$t('settings.style.common_colors._tab_label')"
class="color-container"
>
<div class="tab-header"> <div class="tab-header">
<p>{{ $t('settings.theme_help') }}</p> <p>{{ $t('settings.theme_help') }}</p>
<button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button> <button
<button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button> class="btn"
@click="clearOpacity"
>
{{ $t('settings.style.switcher.clear_opacity') }}
</button>
<button
class="btn"
@click="clearV1"
>
{{ $t('settings.style.switcher.clear_all') }}
</button>
</div> </div>
<p>{{ $t('settings.theme_help_v2_1') }}</p> <p>{{ $t('settings.theme_help_v2_1') }}</p>
<h4>{{ $t('settings.style.common_colors.main') }}</h4> <h4>{{ $t('settings.style.common_colors.main') }}</h4>
<div class="color-item"> <div class="color-item">
<ColorInput name="bgColor" v-model="bgColorLocal" :label="$t('settings.background')"/> <ColorInput
<OpacityInput name="bgOpacity" v-model="bgOpacityLocal" :fallback="previewTheme.opacity.bg || 1"/> v-model="bgColorLocal"
<ColorInput name="textColor" v-model="textColorLocal" :label="$t('settings.text')"/> name="bgColor"
:label="$t('settings.background')"
/>
<OpacityInput
v-model="bgOpacityLocal"
name="bgOpacity"
:fallback="previewTheme.opacity.bg || 1"
/>
<ColorInput
v-model="textColorLocal"
name="textColor"
:label="$t('settings.text')"
/>
<ContrastRatio :contrast="previewContrast.bgText" /> <ContrastRatio :contrast="previewContrast.bgText" />
<ColorInput name="linkColor" v-model="linkColorLocal" :label="$t('settings.links')"/> <ColorInput
v-model="linkColorLocal"
name="linkColor"
:label="$t('settings.links')"
/>
<ContrastRatio :contrast="previewContrast.bgLink" /> <ContrastRatio :contrast="previewContrast.bgLink" />
</div> </div>
<div class="color-item"> <div class="color-item">
<ColorInput name="fgColor" v-model="fgColorLocal" :label="$t('settings.foreground')"/> <ColorInput
<ColorInput name="fgTextColor" v-model="fgTextColorLocal" :label="$t('settings.text')" :fallback="previewTheme.colors.fgText"/> v-model="fgColorLocal"
<ColorInput name="fgLinkColor" v-model="fgLinkColorLocal" :label="$t('settings.links')" :fallback="previewTheme.colors.fgLink"/> name="fgColor"
:label="$t('settings.foreground')"
/>
<ColorInput
v-model="fgTextColorLocal"
name="fgTextColor"
:label="$t('settings.text')"
:fallback="previewTheme.colors.fgText"
/>
<ColorInput
v-model="fgLinkColorLocal"
name="fgLinkColor"
:label="$t('settings.links')"
:fallback="previewTheme.colors.fgLink"
/>
<p>{{ $t('settings.style.common_colors.foreground_hint') }}</p> <p>{{ $t('settings.style.common_colors.foreground_hint') }}</p>
</div> </div>
<h4>{{ $t('settings.style.common_colors.rgbo') }}</h4> <h4>{{ $t('settings.style.common_colors.rgbo') }}</h4>
<div class="color-item"> <div class="color-item">
<ColorInput name="cRedColor" v-model="cRedColorLocal" :label="$t('settings.cRed')"/> <ColorInput
v-model="cRedColorLocal"
name="cRedColor"
:label="$t('settings.cRed')"
/>
<ContrastRatio :contrast="previewContrast.bgRed" /> <ContrastRatio :contrast="previewContrast.bgRed" />
<ColorInput name="cBlueColor" v-model="cBlueColorLocal" :label="$t('settings.cBlue')"/> <ColorInput
v-model="cBlueColorLocal"
name="cBlueColor"
:label="$t('settings.cBlue')"
/>
<ContrastRatio :contrast="previewContrast.bgBlue" /> <ContrastRatio :contrast="previewContrast.bgBlue" />
</div> </div>
<div class="color-item"> <div class="color-item">
<ColorInput name="cGreenColor" v-model="cGreenColorLocal" :label="$t('settings.cGreen')"/> <ColorInput
v-model="cGreenColorLocal"
name="cGreenColor"
:label="$t('settings.cGreen')"
/>
<ContrastRatio :contrast="previewContrast.bgGreen" /> <ContrastRatio :contrast="previewContrast.bgGreen" />
<ColorInput name="cOrangeColor" v-model="cOrangeColorLocal" :label="$t('settings.cOrange')"/> <ColorInput
v-model="cOrangeColorLocal"
name="cOrangeColor"
:label="$t('settings.cOrange')"
/>
<ContrastRatio :contrast="previewContrast.bgOrange" /> <ContrastRatio :contrast="previewContrast.bgOrange" />
</div> </div>
<p>{{ $t('settings.theme_help_v2_2') }}</p> <p>{{ $t('settings.theme_help_v2_2') }}</p>
</div> </div>
<div :label="$t('settings.style.advanced_colors._tab_label')" class="color-container"> <div
:label="$t('settings.style.advanced_colors._tab_label')"
class="color-container"
>
<div class="tab-header"> <div class="tab-header">
<p>{{ $t('settings.theme_help') }}</p> <p>{{ $t('settings.theme_help') }}</p>
<button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button> <button
<button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button> class="btn"
@click="clearOpacity"
>
{{ $t('settings.style.switcher.clear_opacity') }}
</button>
<button
class="btn"
@click="clearV1"
>
{{ $t('settings.style.switcher.clear_all') }}
</button>
</div> </div>
<div class="color-item"> <div class="color-item">
<h4>{{ $t('settings.style.advanced_colors.alert') }}</h4> <h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
<ColorInput name="alertError" v-model="alertErrorColorLocal" :label="$t('settings.style.advanced_colors.alert_error')" :fallback="previewTheme.colors.alertError"/> <ColorInput
v-model="alertErrorColorLocal"
name="alertError"
:label="$t('settings.style.advanced_colors.alert_error')"
:fallback="previewTheme.colors.alertError"
/>
<ContrastRatio :contrast="previewContrast.alertError" /> <ContrastRatio :contrast="previewContrast.alertError" />
</div> </div>
<div class="color-item"> <div class="color-item">
<h4>{{ $t('settings.style.advanced_colors.badge') }}</h4> <h4>{{ $t('settings.style.advanced_colors.badge') }}</h4>
<ColorInput name="badgeNotification" v-model="badgeNotificationColorLocal" :label="$t('settings.style.advanced_colors.badge_notification')" :fallback="previewTheme.colors.badgeNotification"/> <ColorInput
v-model="badgeNotificationColorLocal"
name="badgeNotification"
:label="$t('settings.style.advanced_colors.badge_notification')"
:fallback="previewTheme.colors.badgeNotification"
/>
</div> </div>
<div class="color-item"> <div class="color-item">
<h4>{{ $t('settings.style.advanced_colors.panel_header') }}</h4> <h4>{{ $t('settings.style.advanced_colors.panel_header') }}</h4>
<ColorInput name="panelColor" v-model="panelColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/> <ColorInput
<OpacityInput name="panelOpacity" v-model="panelOpacityLocal" :fallback="previewTheme.opacity.panel || 1"/> v-model="panelColorLocal"
<ColorInput name="panelTextColor" v-model="panelTextColorLocal" :fallback="previewTheme.colors.panelText" :label="$t('settings.text')"/> name="panelColor"
<ContrastRatio :contrast="previewContrast.panelText" large="1"/> :fallback="fgColorLocal"
<ColorInput name="panelLinkColor" v-model="panelLinkColorLocal" :fallback="previewTheme.colors.panelLink" :label="$t('settings.links')"/> :label="$t('settings.background')"
<ContrastRatio :contrast="previewContrast.panelLink" large="1"/> />
<OpacityInput
v-model="panelOpacityLocal"
name="panelOpacity"
:fallback="previewTheme.opacity.panel || 1"
/>
<ColorInput
v-model="panelTextColorLocal"
name="panelTextColor"
:fallback="previewTheme.colors.panelText"
:label="$t('settings.text')"
/>
<ContrastRatio
:contrast="previewContrast.panelText"
large="1"
/>
<ColorInput
v-model="panelLinkColorLocal"
name="panelLinkColor"
:fallback="previewTheme.colors.panelLink"
:label="$t('settings.links')"
/>
<ContrastRatio
:contrast="previewContrast.panelLink"
large="1"
/>
</div> </div>
<div class="color-item"> <div class="color-item">
<h4>{{ $t('settings.style.advanced_colors.top_bar') }}</h4> <h4>{{ $t('settings.style.advanced_colors.top_bar') }}</h4>
<ColorInput name="topBarColor" v-model="topBarColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/> <ColorInput
<ColorInput name="topBarTextColor" v-model="topBarTextColorLocal" :fallback="previewTheme.colors.topBarText" :label="$t('settings.text')"/> v-model="topBarColorLocal"
name="topBarColor"
:fallback="fgColorLocal"
:label="$t('settings.background')"
/>
<ColorInput
v-model="topBarTextColorLocal"
name="topBarTextColor"
:fallback="previewTheme.colors.topBarText"
:label="$t('settings.text')"
/>
<ContrastRatio :contrast="previewContrast.topBarText" /> <ContrastRatio :contrast="previewContrast.topBarText" />
<ColorInput name="topBarLinkColor" v-model="topBarLinkColorLocal" :fallback="previewTheme.colors.topBarLink" :label="$t('settings.links')"/> <ColorInput
v-model="topBarLinkColorLocal"
name="topBarLinkColor"
:fallback="previewTheme.colors.topBarLink"
:label="$t('settings.links')"
/>
<ContrastRatio :contrast="previewContrast.topBarLink" /> <ContrastRatio :contrast="previewContrast.topBarLink" />
</div> </div>
<div class="color-item"> <div class="color-item">
<h4>{{ $t('settings.style.advanced_colors.inputs') }}</h4> <h4>{{ $t('settings.style.advanced_colors.inputs') }}</h4>
<ColorInput name="inputColor" v-model="inputColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/> <ColorInput
<OpacityInput name="inputOpacity" v-model="inputOpacityLocal" :fallback="previewTheme.opacity.input || 1"/> v-model="inputColorLocal"
<ColorInput name="inputTextColor" v-model="inputTextColorLocal" :fallback="previewTheme.colors.inputText" :label="$t('settings.text')"/> name="inputColor"
:fallback="fgColorLocal"
:label="$t('settings.background')"
/>
<OpacityInput
v-model="inputOpacityLocal"
name="inputOpacity"
:fallback="previewTheme.opacity.input || 1"
/>
<ColorInput
v-model="inputTextColorLocal"
name="inputTextColor"
:fallback="previewTheme.colors.inputText"
:label="$t('settings.text')"
/>
<ContrastRatio :contrast="previewContrast.inputText" /> <ContrastRatio :contrast="previewContrast.inputText" />
</div> </div>
<div class="color-item"> <div class="color-item">
<h4>{{ $t('settings.style.advanced_colors.buttons') }}</h4> <h4>{{ $t('settings.style.advanced_colors.buttons') }}</h4>
<ColorInput name="btnColor" v-model="btnColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/> <ColorInput
<OpacityInput name="btnOpacity" v-model="btnOpacityLocal" :fallback="previewTheme.opacity.btn || 1"/> v-model="btnColorLocal"
<ColorInput name="btnTextColor" v-model="btnTextColorLocal" :fallback="previewTheme.colors.btnText" :label="$t('settings.text')"/> name="btnColor"
:fallback="fgColorLocal"
:label="$t('settings.background')"
/>
<OpacityInput
v-model="btnOpacityLocal"
name="btnOpacity"
:fallback="previewTheme.opacity.btn || 1"
/>
<ColorInput
v-model="btnTextColorLocal"
name="btnTextColor"
:fallback="previewTheme.colors.btnText"
:label="$t('settings.text')"
/>
<ContrastRatio :contrast="previewContrast.btnText" /> <ContrastRatio :contrast="previewContrast.btnText" />
</div> </div>
<div class="color-item"> <div class="color-item">
<h4>{{ $t('settings.style.advanced_colors.borders') }}</h4> <h4>{{ $t('settings.style.advanced_colors.borders') }}</h4>
<ColorInput name="borderColor" v-model="borderColorLocal" :fallback="previewTheme.colors.border" :label="$t('settings.style.common.color')"/> <ColorInput
<OpacityInput name="borderOpacity" v-model="borderOpacityLocal" :fallback="previewTheme.opacity.border || 1"/> v-model="borderColorLocal"
name="borderColor"
:fallback="previewTheme.colors.border"
:label="$t('settings.style.common.color')"
/>
<OpacityInput
v-model="borderOpacityLocal"
name="borderOpacity"
:fallback="previewTheme.opacity.border || 1"
/>
</div> </div>
<div class="color-item"> <div class="color-item">
<h4>{{ $t('settings.style.advanced_colors.faint_text') }}</h4> <h4>{{ $t('settings.style.advanced_colors.faint_text') }}</h4>
<ColorInput name="faintColor" v-model="faintColorLocal" :fallback="previewTheme.colors.faint || 1" :label="$t('settings.text')"/> <ColorInput
<ColorInput name="faintLinkColor" v-model="faintLinkColorLocal" :fallback="previewTheme.colors.faintLink" :label="$t('settings.links')"/> v-model="faintColorLocal"
<ColorInput name="panelFaintColor" v-model="panelFaintColorLocal" :fallback="previewTheme.colors.panelFaint" :label="$t('settings.style.advanced_colors.panel_header')"/> name="faintColor"
<OpacityInput name="faintOpacity" v-model="faintOpacityLocal" :fallback="previewTheme.opacity.faint || 0.5"/> :fallback="previewTheme.colors.faint || 1"
:label="$t('settings.text')"
/>
<ColorInput
v-model="faintLinkColorLocal"
name="faintLinkColor"
:fallback="previewTheme.colors.faintLink"
:label="$t('settings.links')"
/>
<ColorInput
v-model="panelFaintColorLocal"
name="panelFaintColor"
:fallback="previewTheme.colors.panelFaint"
:label="$t('settings.style.advanced_colors.panel_header')"
/>
<OpacityInput
v-model="faintOpacityLocal"
name="faintOpacity"
:fallback="previewTheme.opacity.faint || 0.5"
/>
</div> </div>
</div> </div>
<div :label="$t('settings.style.radii._tab_label')" class="radius-container"> <div
:label="$t('settings.style.radii._tab_label')"
class="radius-container"
>
<div class="tab-header"> <div class="tab-header">
<p>{{ $t('settings.radii_help') }}</p> <p>{{ $t('settings.radii_help') }}</p>
<button class="btn" @click="clearRoundness">{{$t('settings.style.switcher.clear_all')}}</button> <button
class="btn"
@click="clearRoundness"
>
{{ $t('settings.style.switcher.clear_all') }}
</button>
</div> </div>
<RangeInput name="btnRadius" :label="$t('settings.btnRadius')" v-model="btnRadiusLocal" :fallback="previewTheme.radii.btn" max="16" hardMin="0"/> <RangeInput
<RangeInput name="inputRadius" :label="$t('settings.inputRadius')" v-model="inputRadiusLocal" :fallback="previewTheme.radii.input" max="9" hardMin="0"/> v-model="btnRadiusLocal"
<RangeInput name="checkboxRadius" :label="$t('settings.checkboxRadius')" v-model="checkboxRadiusLocal" :fallback="previewTheme.radii.checkbox" max="16" hardMin="0"/> name="btnRadius"
<RangeInput name="panelRadius" :label="$t('settings.panelRadius')" v-model="panelRadiusLocal" :fallback="previewTheme.radii.panel" max="50" hardMin="0"/> :label="$t('settings.btnRadius')"
<RangeInput name="avatarRadius" :label="$t('settings.avatarRadius')" v-model="avatarRadiusLocal" :fallback="previewTheme.radii.avatar" max="28" hardMin="0"/> :fallback="previewTheme.radii.btn"
<RangeInput name="avatarAltRadius" :label="$t('settings.avatarAltRadius')" v-model="avatarAltRadiusLocal" :fallback="previewTheme.radii.avatarAlt" max="28" hardMin="0"/> max="16"
<RangeInput name="attachmentRadius" :label="$t('settings.attachmentRadius')" v-model="attachmentRadiusLocal" :fallback="previewTheme.radii.attachment" max="50" hardMin="0"/> hard-min="0"
<RangeInput name="tooltipRadius" :label="$t('settings.tooltipRadius')" v-model="tooltipRadiusLocal" :fallback="previewTheme.radii.tooltip" max="50" hardMin="0"/> />
<RangeInput
v-model="inputRadiusLocal"
name="inputRadius"
:label="$t('settings.inputRadius')"
:fallback="previewTheme.radii.input"
max="9"
hard-min="0"
/>
<RangeInput
v-model="checkboxRadiusLocal"
name="checkboxRadius"
:label="$t('settings.checkboxRadius')"
:fallback="previewTheme.radii.checkbox"
max="16"
hard-min="0"
/>
<RangeInput
v-model="panelRadiusLocal"
name="panelRadius"
:label="$t('settings.panelRadius')"
:fallback="previewTheme.radii.panel"
max="50"
hard-min="0"
/>
<RangeInput
v-model="avatarRadiusLocal"
name="avatarRadius"
:label="$t('settings.avatarRadius')"
:fallback="previewTheme.radii.avatar"
max="28"
hard-min="0"
/>
<RangeInput
v-model="avatarAltRadiusLocal"
name="avatarAltRadius"
:label="$t('settings.avatarAltRadius')"
:fallback="previewTheme.radii.avatarAlt"
max="28"
hard-min="0"
/>
<RangeInput
v-model="attachmentRadiusLocal"
name="attachmentRadius"
:label="$t('settings.attachmentRadius')"
:fallback="previewTheme.radii.attachment"
max="50"
hard-min="0"
/>
<RangeInput
v-model="tooltipRadiusLocal"
name="tooltipRadius"
:label="$t('settings.tooltipRadius')"
:fallback="previewTheme.radii.tooltip"
max="50"
hard-min="0"
/>
</div> </div>
<div :label="$t('settings.style.shadows._tab_label')" class="shadow-container"> <div
:label="$t('settings.style.shadows._tab_label')"
class="shadow-container"
>
<div class="tab-header shadow-selector"> <div class="tab-header shadow-selector">
<div class="select-container"> <div class="select-container">
{{ $t('settings.style.shadows.component') }} {{ $t('settings.style.shadows.component') }}
<label for="shadow-switcher" class="select"> <label
<select id="shadow-switcher" v-model="shadowSelected" class="shadow-switcher"> for="shadow-switcher"
<option v-for="shadow in shadowsAvailable" class="select"
:value="shadow"> >
<select
id="shadow-switcher"
v-model="shadowSelected"
class="shadow-switcher"
>
<option
v-for="shadow in shadowsAvailable"
:key="shadow"
:value="shadow"
>
{{ $t('settings.style.shadows.components.' + shadow) }} {{ $t('settings.style.shadows.components.' + shadow) }}
</option> </option>
</select> </select>
@ -203,70 +474,118 @@
</label> </label>
</div> </div>
<div class="override"> <div class="override">
<label for="override" class="label"> <label
for="override"
class="label"
>
{{ $t('settings.style.shadows.override') }} {{ $t('settings.style.shadows.override') }}
</label> </label>
<input <input
id="override"
v-model="currentShadowOverriden" v-model="currentShadowOverriden"
name="override" name="override"
id="override"
class="input-override" class="input-override"
type="checkbox"> type="checkbox"
<label class="checkbox-label" for="override"></label> >
<label
class="checkbox-label"
for="override"
/>
</div> </div>
<button class="btn" @click="clearShadows">{{$t('settings.style.switcher.clear_all')}}</button> <button
class="btn"
@click="clearShadows"
>
{{ $t('settings.style.switcher.clear_all') }}
</button>
</div> </div>
<shadow-control :ready="!!currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/> <shadow-control
v-model="currentShadow"
:ready="!!currentShadowFallback"
:fallback="currentShadowFallback"
/>
<div v-if="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'"> <div v-if="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'">
<i18n path="settings.style.shadows.filter_hint.always_drop_shadow" tag="p"> <i18n
path="settings.style.shadows.filter_hint.always_drop_shadow"
tag="p"
>
<code>filter: drop-shadow()</code> <code>filter: drop-shadow()</code>
</i18n> </i18n>
<p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p> <p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p>
<i18n path="settings.style.shadows.filter_hint.drop_shadow_syntax" tag="p"> <i18n
path="settings.style.shadows.filter_hint.drop_shadow_syntax"
tag="p"
>
<code>drop-shadow</code> <code>drop-shadow</code>
<code>spread-radius</code> <code>spread-radius</code>
<code>inset</code> <code>inset</code>
</i18n> </i18n>
<i18n path="settings.style.shadows.filter_hint.inset_classic" tag="p"> <i18n
path="settings.style.shadows.filter_hint.inset_classic"
tag="p"
>
<code>box-shadow</code> <code>box-shadow</code>
</i18n> </i18n>
<p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p> <p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p>
</div> </div>
</div> </div>
<div :label="$t('settings.style.fonts._tab_label')" class="fonts-container"> <div
:label="$t('settings.style.fonts._tab_label')"
class="fonts-container"
>
<div class="tab-header"> <div class="tab-header">
<p>{{ $t('settings.style.fonts.help') }}</p> <p>{{ $t('settings.style.fonts.help') }}</p>
<button class="btn" @click="clearFonts">{{$t('settings.style.switcher.clear_all')}}</button> <button
class="btn"
@click="clearFonts"
>
{{ $t('settings.style.switcher.clear_all') }}
</button>
</div> </div>
<FontControl <FontControl
name="ui"
v-model="fontsLocal.interface" v-model="fontsLocal.interface"
name="ui"
:label="$t('settings.style.fonts.components.interface')" :label="$t('settings.style.fonts.components.interface')"
:fallback="previewTheme.fonts.interface" :fallback="previewTheme.fonts.interface"
no-inherit="1"/> no-inherit="1"
/>
<FontControl <FontControl
name="input"
v-model="fontsLocal.input" v-model="fontsLocal.input"
name="input"
:label="$t('settings.style.fonts.components.input')" :label="$t('settings.style.fonts.components.input')"
:fallback="previewTheme.fonts.input"/> :fallback="previewTheme.fonts.input"
/>
<FontControl <FontControl
name="post"
v-model="fontsLocal.post" v-model="fontsLocal.post"
name="post"
:label="$t('settings.style.fonts.components.post')" :label="$t('settings.style.fonts.components.post')"
:fallback="previewTheme.fonts.post"/> :fallback="previewTheme.fonts.post"
/>
<FontControl <FontControl
name="postCode"
v-model="fontsLocal.postCode" v-model="fontsLocal.postCode"
name="postCode"
:label="$t('settings.style.fonts.components.postCode')" :label="$t('settings.style.fonts.components.postCode')"
:fallback="previewTheme.fonts.postCode"/> :fallback="previewTheme.fonts.postCode"
/>
</div> </div>
</tab-switcher> </tab-switcher>
</keep-alive> </keep-alive>
<div class="apply-container"> <div class="apply-container">
<button class="btn submit" :disabled="!themeValid" @click="setCustomTheme">{{$t('general.apply')}}</button> <button
<button class="btn" @click="clearAll">{{$t('settings.style.switcher.reset')}}</button> class="btn submit"
:disabled="!themeValid"
@click="setCustomTheme"
>
{{ $t('general.apply') }}
</button>
<button
class="btn"
@click="clearAll"
>
{{ $t('settings.style.switcher.reset') }}
</button>
</div> </div>
</div> </div>
</template> </template>

View file

@ -10,6 +10,12 @@ export default Vue.component('tab-switcher', {
active: this.$slots.default.findIndex(_ => _.tag) active: this.$slots.default.findIndex(_ => _.tag)
} }
}, },
beforeUpdate () {
const currentSlot = this.$slots.default[this.active]
if (!currentSlot.tag) {
this.active = this.$slots.default.findIndex(_ => _.tag)
}
},
methods: { methods: {
activateTab (index, dataset) { activateTab (index, dataset) {
return () => { return () => {
@ -20,12 +26,6 @@ export default Vue.component('tab-switcher', {
} }
} }
}, },
beforeUpdate () {
const currentSlot = this.$slots.default[this.active]
if (!currentSlot.tag) {
this.active = this.$slots.default.findIndex(_ => _.tag)
}
},
render (h) { render (h) {
const tabs = this.$slots.default const tabs = this.$slots.default
.map((slot, index) => { .map((slot, index) => {

View file

@ -1,5 +1,10 @@
<template> <template>
<Timeline :title="tag" :timeline="timeline" :timeline-name="'tag'" :tag="tag" /> <Timeline
:title="tag"
:timeline="timeline"
:timeline-name="'tag'"
:tag="tag"
/>
</template> </template>
<script src='./tag_timeline.js'></script> <script src='./tag_timeline.js'></script>

View file

@ -2,8 +2,12 @@
<div> <div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-body"> <div class="panel-body">
<div v-html="content" class="tos-content"> <!-- eslint-disable vue/no-v-html -->
</div> <div
class="tos-content"
v-html="content"
/>
<!-- eslint-enable vue/no-v-html -->
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,5 +1,8 @@
<template> <template>
<time :datetime="time" :title="localeDateString"> <time
:datetime="time"
:title="localeDateString"
>
{{ $t(relativeTime.key, [relativeTime.num]) }} {{ $t(relativeTime.key, [relativeTime.num]) }}
</time> </time>
</template> </template>
@ -16,12 +19,6 @@ export default {
interval: null interval: null
} }
}, },
created () {
this.refreshRelativeTimeObject()
},
destroyed () {
clearTimeout(this.interval)
},
computed: { computed: {
localeDateString () { localeDateString () {
return typeof this.time === 'string' return typeof this.time === 'string'
@ -29,6 +26,12 @@ export default {
: this.time.toLocaleString() : this.time.toLocaleString()
} }
}, },
created () {
this.refreshRelativeTimeObject()
},
destroyed () {
clearTimeout(this.interval)
},
methods: { methods: {
refreshRelativeTimeObject () { refreshRelativeTimeObject () {
const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1 const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1

View file

@ -86,7 +86,7 @@ const Timeline = {
if (this.newStatusCount === 0) return if (this.newStatusCount === 0) return
if (this.timeline.flushMarker !== 0) { if (this.timeline.flushMarker !== 0) {
this.$store.commit('clearTimeline', { timeline: this.timelineName }) this.$store.commit('clearTimeline', { timeline: this.timelineName, excludeUserId: true })
this.$store.commit('queueFlush', { timeline: this.timelineName, id: 0 }) this.$store.commit('queueFlush', { timeline: this.timelineName, id: 0 })
this.fetchOlderStatuses() this.fetchOlderStatuses()
} else { } else {

View file

@ -4,13 +4,25 @@
<div class="title"> <div class="title">
{{ title }} {{ title }}
</div> </div>
<div @click.prevent class="loadmore-error alert error" v-if="timelineError"> <div
v-if="timelineError"
class="loadmore-error alert error"
@click.prevent
>
{{ $t('timeline.error_fetching') }} {{ $t('timeline.error_fetching') }}
</div> </div>
<button @click.prevent="showNewStatuses" class="loadmore-button" v-if="timeline.newStatusCount > 0 && !timelineError"> <button
v-if="timeline.newStatusCount > 0 && !timelineError"
class="loadmore-button"
@click.prevent="showNewStatuses"
>
{{ $t('timeline.show_new') }}{{ newStatusCountStr }} {{ $t('timeline.show_new') }}{{ newStatusCountStr }}
</button> </button>
<div @click.prevent class="loadmore-text faint" v-if="!timeline.newStatusCount > 0 && !timelineError"> <div
v-if="!timeline.newStatusCount > 0 && !timelineError"
class="loadmore-text faint"
@click.prevent
>
{{ $t('timeline.up_to_date') }} {{ $t('timeline.up_to_date') }}
</div> </div>
</div> </div>
@ -18,24 +30,37 @@
<div class="timeline"> <div class="timeline">
<conversation <conversation
v-for="status in timeline.visibleStatuses" v-for="status in timeline.visibleStatuses"
class="status-fadein"
:key="status.id" :key="status.id"
class="status-fadein"
:statusoid="status" :statusoid="status"
:collapsable="true" :collapsable="true"
/> />
</div> </div>
</div> </div>
<div :class="classes.footer"> <div :class="classes.footer">
<div v-if="count===0" class="new-status-notification text-center panel-footer faint"> <div
v-if="count===0"
class="new-status-notification text-center panel-footer faint"
>
{{ $t('timeline.no_statuses') }} {{ $t('timeline.no_statuses') }}
</div> </div>
<div v-else-if="bottomedOut" class="new-status-notification text-center panel-footer faint"> <div
v-else-if="bottomedOut"
class="new-status-notification text-center panel-footer faint"
>
{{ $t('timeline.no_more_statuses') }} {{ $t('timeline.no_more_statuses') }}
</div> </div>
<a v-else-if="!timeline.loading" href="#" v-on:click.prevent='fetchOlderStatuses()'> <a
v-else-if="!timeline.loading"
href="#"
@click.prevent="fetchOlderStatuses()"
>
<div class="new-status-notification text-center panel-footer">{{ $t('timeline.load_older') }}</div> <div class="new-status-notification text-center panel-footer">{{ $t('timeline.load_older') }}</div>
</a> </a>
<div v-else class="new-status-notification text-center panel-footer"> <div
v-else
class="new-status-notification text-center panel-footer"
>
<i class="icon-spin3 animate-spin" /> <i class="icon-spin3 animate-spin" />
</div> </div>
</div> </div>

View file

@ -5,7 +5,7 @@
:title="user.screen_name" :title="user.screen_name"
:src="user.profile_image_url_original" :src="user.profile_image_url_original"
:class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }" :class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }"
:imageLoadError="imageLoadError" :image-load-error="imageLoadError"
/> />
</template> </template>

View file

@ -73,12 +73,12 @@ export default {
userHighlightType: { userHighlightType: {
get () { get () {
const data = this.$store.state.config.highlight[this.user.screen_name] const data = this.$store.state.config.highlight[this.user.screen_name]
return data && data.type || 'disabled' return (data && data.type) || 'disabled'
}, },
set (type) { set (type) {
const data = this.$store.state.config.highlight[this.user.screen_name] const data = this.$store.state.config.highlight[this.user.screen_name]
if (type !== 'disabled') { if (type !== 'disabled') {
this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: data && data.color || '#FFFFFF', type }) this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: (data && data.color) || '#FFFFFF', type })
} else { } else {
this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: undefined }) this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: undefined })
} }

View file

@ -1,41 +1,107 @@
<template> <template>
<div class="user-card" :class="classes" :style="style"> <div
class="user-card"
:class="classes"
:style="style"
>
<div class="panel-heading"> <div class="panel-heading">
<div class='user-info'> <div class="user-info">
<div class='container'> <div class="container">
<router-link :to="userProfileLink(user)"> <router-link :to="userProfileLink(user)">
<UserAvatar :betterShadow="betterShadow" :user="user"/> <UserAvatar
:better-shadow="betterShadow"
:user="user"
/>
</router-link> </router-link>
<div class="user-summary"> <div class="user-summary">
<div class="top-line"> <div class="top-line">
<div :title="user.name" class='user-name' v-if="user.name_html" v-html="user.name_html"></div> <!-- eslint-disable vue/no-v-html -->
<div :title="user.name" class='user-name' v-else>{{user.name}}</div> <div
<router-link :to="{ name: 'user-settings' }" v-if="!isOtherUser"> v-if="user.name_html"
<i class="button-icon icon-wrench usersettings" :title="$t('tool_tip.user_settings')"></i> :title="user.name"
class="user-name"
v-html="user.name_html"
/>
<!-- eslint-enable vue/no-v-html -->
<div
v-else
:title="user.name"
class="user-name"
>
{{ user.name }}
</div>
<router-link
v-if="!isOtherUser"
:to="{ name: 'user-settings' }"
>
<i
class="button-icon icon-wrench usersettings"
:title="$t('tool_tip.user_settings')"
/>
</router-link> </router-link>
<a :href="user.statusnet_profile_url" target="_blank" v-if="isOtherUser && !user.is_local"> <a
<i class="icon-link-ext usersettings"></i> v-if="isOtherUser && !user.is_local"
:href="user.statusnet_profile_url"
target="_blank"
>
<i class="icon-link-ext usersettings" />
</a> </a>
</div> </div>
<div class="bottom-line"> <div class="bottom-line">
<router-link class="user-screen-name" :to="userProfileLink(user)">@{{user.screen_name}}</router-link> <router-link
<span class="alert staff" v-if="!hideBio && !!visibleRole">{{visibleRole}}</span> class="user-screen-name"
<span v-if="user.locked"><i class="icon icon-lock"></i></span> :to="userProfileLink(user)"
<span v-if="!hideUserStatsLocal && !hideBio" class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span> >
@{{ user.screen_name }}
</router-link>
<span
v-if="!hideBio && !!visibleRole"
class="alert staff"
>{{ visibleRole }}</span>
<span v-if="user.locked"><i class="icon icon-lock" /></span>
<span
v-if="!hideUserStatsLocal && !hideBio"
class="dailyAvg"
>{{ dailyAvg }} {{ $t('user_card.per_day') }}</span>
</div> </div>
</div> </div>
</div> </div>
<div class="user-meta"> <div class="user-meta">
<div v-if="user.follows_you && loggedIn && isOtherUser" class="following"> <div
v-if="user.follows_you && loggedIn && isOtherUser"
class="following"
>
{{ $t('user_card.follows_you') }} {{ $t('user_card.follows_you') }}
</div> </div>
<div class="highlighter" v-if="isOtherUser && (loggedIn || !switcher)"> <div
v-if="isOtherUser && (loggedIn || !switcher)"
class="highlighter"
>
<!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to --> <!-- 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
<input class="userHighlightCl" type="color" :id="'userHighlightColor'+user.id" v-if="userHighlightType !== 'disabled'" v-model="userHighlightColor"/> v-if="userHighlightType !== 'disabled'"
<label for="style-switcher" class='userHighlightSel select'> :id="'userHighlightColorTx'+user.id"
<select class="userHighlightSel" :id="'userHighlightSel'+user.id" v-model="userHighlightType"> v-model="userHighlightColor"
class="userHighlightText"
type="text"
>
<input
v-if="userHighlightType !== 'disabled'"
:id="'userHighlightColor'+user.id"
v-model="userHighlightColor"
class="userHighlightCl"
type="color"
>
<label
for="style-switcher"
class="userHighlightSel select"
>
<select
:id="'userHighlightSel'+user.id"
v-model="userHighlightType"
class="userHighlightSel"
>
<option value="disabled">No highlight</option> <option value="disabled">No highlight</option>
<option value="solid">Solid bg</option> <option value="solid">Solid bg</option>
<option value="striped">Striped bg</option> <option value="striped">Striped bg</option>
@ -45,11 +111,22 @@
</label> </label>
</div> </div>
</div> </div>
<div v-if="isOtherUser" class="user-interactions"> <div
<div class="follow" v-if="loggedIn"> v-if="isOtherUser"
class="user-interactions"
>
<div
v-if="loggedIn"
class="follow"
>
<span v-if="user.following"> <span v-if="user.following">
<!--Following them!--> <!--Following them!-->
<button @click="unfollowUser" class="pressed" :disabled="followRequestInProgress" :title="$t('user_card.follow_unfollow')"> <button
class="pressed"
:disabled="followRequestInProgress"
:title="$t('user_card.follow_unfollow')"
@click="unfollowUser"
>
<template v-if="followRequestInProgress"> <template v-if="followRequestInProgress">
{{ $t('user_card.follow_progress') }} {{ $t('user_card.follow_progress') }}
</template> </template>
@ -59,7 +136,11 @@
</button> </button>
</span> </span>
<span v-if="!user.following"> <span v-if="!user.following">
<button @click="followUser" :disabled="followRequestInProgress" :title="followRequestSent ? $t('user_card.follow_again') : ''"> <button
:disabled="followRequestInProgress"
:title="followRequestSent ? $t('user_card.follow_again') : ''"
@click="followUser"
>
<template v-if="followRequestInProgress"> <template v-if="followRequestInProgress">
{{ $t('user_card.follow_progress') }} {{ $t('user_card.follow_progress') }}
</template> </template>
@ -72,61 +153,106 @@
</button> </button>
</span> </span>
</div> </div>
<div class='mute' v-if='isOtherUser && loggedIn'> <div
<span v-if='user.muted'> v-if="isOtherUser && loggedIn"
<button @click="unmuteUser" class="pressed"> class="mute"
>
<span v-if="user.muted">
<button
class="pressed"
@click="unmuteUser"
>
{{ $t('user_card.muted') }} {{ $t('user_card.muted') }}
</button> </button>
</span> </span>
<span v-if='!user.muted'> <span v-if="!user.muted">
<button @click="muteUser"> <button @click="muteUser">
{{ $t('user_card.mute') }} {{ $t('user_card.mute') }}
</button> </button>
</span> </span>
</div> </div>
<div v-if='!loggedIn && user.is_local'> <div v-if="!loggedIn && user.is_local">
<RemoteFollow :user="user" /> <RemoteFollow :user="user" />
</div> </div>
<div class='block' v-if='isOtherUser && loggedIn'> <div
<span v-if='user.statusnet_blocking'> v-if="isOtherUser && loggedIn"
<button @click="unblockUser" class="pressed"> class="block"
>
<span v-if="user.statusnet_blocking">
<button
class="pressed"
@click="unblockUser"
>
{{ $t('user_card.blocked') }} {{ $t('user_card.blocked') }}
</button> </button>
</span> </span>
<span v-if='!user.statusnet_blocking'> <span v-if="!user.statusnet_blocking">
<button @click="blockUser"> <button @click="blockUser">
{{ $t('user_card.block') }} {{ $t('user_card.block') }}
</button> </button>
</span> </span>
</div> </div>
<div class='block' v-if='isOtherUser && loggedIn'> <div
v-if="isOtherUser && loggedIn"
class="block"
>
<span> <span>
<button @click="reportUser"> <button @click="reportUser">
{{ $t('user_card.report') }} {{ $t('user_card.report') }}
</button> </button>
</span> </span>
</div> </div>
<ModerationTools :user='user' v-if='loggedIn.role === "admin"'/> <ModerationTools
v-if="loggedIn.role === &quot;admin&quot;"
:user="user"
/>
</div> </div>
</div> </div>
</div> </div>
<div class="panel-body" v-if="!hideBio"> <div
<div v-if="!hideUserStatsLocal && switcher" class="user-counts"> v-if="!hideBio"
<div class="user-count" v-on:click.prevent="setProfileView('statuses')"> class="panel-body"
>
<div
v-if="!hideUserStatsLocal && switcher"
class="user-counts"
>
<div
class="user-count"
@click.prevent="setProfileView('statuses')"
>
<h5>{{ $t('user_card.statuses') }}</h5> <h5>{{ $t('user_card.statuses') }}</h5>
<span>{{ user.statuses_count }} <br></span> <span>{{ user.statuses_count }} <br></span>
</div> </div>
<div class="user-count" v-on:click.prevent="setProfileView('friends')"> <div
class="user-count"
@click.prevent="setProfileView('friends')"
>
<h5>{{ $t('user_card.followees') }}</h5> <h5>{{ $t('user_card.followees') }}</h5>
<span>{{ user.friends_count }}</span> <span>{{ user.friends_count }}</span>
</div> </div>
<div class="user-count" v-on:click.prevent="setProfileView('followers')"> <div
class="user-count"
@click.prevent="setProfileView('followers')"
>
<h5>{{ $t('user_card.followers') }}</h5> <h5>{{ $t('user_card.followers') }}</h5>
<span>{{ user.followers_count }}</span> <span>{{ user.followers_count }}</span>
</div> </div>
</div> </div>
<p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="user-card-bio" v-html="user.description_html"></p> <!-- eslint-disable vue/no-v-html -->
<p v-else-if="!hideBio" class="user-card-bio">{{ user.description }}</p> <p
v-if="!hideBio && user.description_html"
class="user-card-bio"
@click.prevent="linkClicked"
v-html="user.description_html"
/>
<!-- eslint-enable vue/no-v-html -->
<p
v-else-if="!hideBio"
class="user-card-bio"
>
{{ user.description }}
</p>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,14 +1,38 @@
<template> <template>
<div> <div>
<div class="user-finder-container"> <div class="user-finder-container">
<i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" /> <i
<a href="#" v-if="hidden" :title="$t('finder.find_user')"><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden" /></a> v-if="loading"
class="icon-spin4 user-finder-icon animate-spin-slow"
/>
<a
v-if="hidden"
href="#"
:title="$t('finder.find_user')"
><i
class="icon-user-plus user-finder-icon"
@click.prevent.stop="toggleHidden"
/></a>
<template v-else> <template v-else>
<input class="user-finder-input" ref="userSearchInput" @keyup.enter="findUser(username)" v-model="username" :placeholder="$t('finder.find_user')" id="user-finder-input" type="text"/> <input
<button class="btn search-button" @click="findUser(username)"> id="user-finder-input"
ref="userSearchInput"
v-model="username"
class="user-finder-input"
:placeholder="$t('finder.find_user')"
type="text"
@keyup.enter="findUser(username)"
>
<button
class="btn search-button"
@click="findUser(username)"
>
<i class="icon-search" /> <i class="icon-search" />
</button> </button>
<i class="button-icon icon-cancel user-finder-icon" @click.prevent.stop="toggleHidden"/> <i
class="button-icon icon-cancel user-finder-icon"
@click.prevent.stop="toggleHidden"
/>
</template> </template>
</div> </div>
</div> </div>
@ -25,7 +49,6 @@
align-items: baseline; align-items: baseline;
vertical-align: baseline; vertical-align: baseline;
.user-finder-input, .user-finder-input,
.search-button { .search-button {
height: 29px; height: 29px;

View file

@ -1,13 +1,23 @@
<template> <template>
<div class="user-panel"> <div class="user-panel">
<div
<div v-if="signedIn" key="user-panel" class="panel panel-default signed-in"> v-if="signedIn"
<UserCard :user="user" :hideBio="true" rounded="top"/> key="user-panel"
class="panel panel-default signed-in"
>
<UserCard
:user="user"
:hide-bio="true"
rounded="top"
/>
<div class="panel-footer"> <div class="panel-footer">
<post-status-form v-if='user'></post-status-form> <post-status-form v-if="user" />
</div> </div>
</div> </div>
<auth-form v-else key="user-panel"/> <auth-form
v-else
key="user-panel"
/>
</div> </div>
</template> </template>

View file

@ -31,6 +31,8 @@ const UserProfile = {
} }
}, },
created () { created () {
// Make sure that timelines used in this page are empty
this.cleanUp()
const routeParams = this.$route.params const routeParams = this.$route.params
this.load(routeParams.name || routeParams.id) this.load(routeParams.name || routeParams.id)
}, },

View file

@ -1,18 +1,29 @@
<template> <template>
<div> <div>
<div v-if="user" class="user-profile panel panel-default"> <div
<UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/> v-if="user"
<tab-switcher :renderOnlyFocused="true" ref="tabSwitcher"> class="user-profile panel panel-default"
>
<UserCard
:user="user"
:switcher="true"
:selected="timeline.viewing"
rounded="top"
/>
<tab-switcher
ref="tabSwitcher"
:render-only-focused="true"
>
<div :label="$t('user_card.statuses')"> <div :label="$t('user_card.statuses')">
<div class="timeline"> <div class="timeline">
<template v-for="statusId in user.pinnedStatuseIds"> <template v-for="statusId in user.pinnedStatuseIds">
<Conversation <Conversation
v-if="timeline.statusesObject[statusId]" v-if="timeline.statusesObject[statusId]"
class="status-fadein"
:key="statusId" :key="statusId"
class="status-fadein"
:statusoid="timeline.statusesObject[statusId]" :statusoid="timeline.statusesObject[statusId]"
:collapsable="true" :collapsable="true"
:showPinned="true" :show-pinned="true"
/> />
</template> </template>
</div> </div>
@ -25,24 +36,42 @@
:user-id="userId" :user-id="userId"
/> />
</div> </div>
<div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count"> <div
<FriendList :userId="userId"> v-if="followsTabVisible"
<template slot="item" slot-scope="{item}"> :label="$t('user_card.followees')"
:disabled="!user.friends_count"
>
<FriendList :user-id="userId">
<template
slot="item"
slot-scope="{item}"
>
<FollowCard :user="item" /> <FollowCard :user="item" />
</template> </template>
</FriendList> </FriendList>
</div> </div>
<div :label="$t('user_card.followers')" v-if="followersTabVisible" :disabled="!user.followers_count"> <div
<FollowerList :userId="userId"> v-if="followersTabVisible"
<template slot="item" slot-scope="{item}"> :label="$t('user_card.followers')"
<FollowCard :user="item" :noFollowsYou="isUs" /> :disabled="!user.followers_count"
>
<FollowerList :user-id="userId">
<template
slot="item"
slot-scope="{item}"
>
<FollowCard
:user="item"
:no-follows-you="isUs"
/>
</template> </template>
</FollowerList> </FollowerList>
</div> </div>
<Timeline <Timeline
:label="$t('user_card.media')" :label="$t('user_card.media')"
:disabled="!media.visibleStatuses.length" :disabled="!media.visibleStatuses.length"
:embedded="true" :title="$t('user_card.media')" :embedded="true"
:title="$t('user_card.media')"
timeline-name="media" timeline-name="media"
:timeline="media" :timeline="media"
:user-id="userId" :user-id="userId"
@ -58,7 +87,10 @@
/> />
</tab-switcher> </tab-switcher>
</div> </div>
<div v-else class="panel user-profile-placeholder"> <div
v-else
class="panel user-profile-placeholder"
>
<div class="panel-heading"> <div class="panel-heading">
<div class="title"> <div class="title">
{{ $t('settings.profile_tab') }} {{ $t('settings.profile_tab') }}
@ -66,7 +98,10 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<span v-if="error">{{ error }}</span> <span v-if="error">{{ error }}</span>
<i class="icon-spin3 animate-spin" v-else></i> <i
v-else
class="icon-spin3 animate-spin"
/>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,8 +1,17 @@
<template> <template>
<div class="modal-view" @click="closeModal" v-if="isOpen"> <div
<div class="user-reporting-panel panel" @click.stop=""> v-if="isOpen"
class="modal-view"
@click="closeModal"
>
<div
class="user-reporting-panel panel"
@click.stop=""
>
<div class="panel-heading"> <div class="panel-heading">
<div class="title">{{$t('user_reporting.title', [user.screen_name])}}</div> <div class="title">
{{ $t('user_reporting.title', [user.screen_name]) }}
</div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="user-reporting-panel-left"> <div class="user-reporting-panel-left">
@ -18,21 +27,42 @@
</div> </div>
<div v-if="!user.is_local"> <div v-if="!user.is_local">
<p>{{ $t('user_reporting.forward_description') }}</p> <p>{{ $t('user_reporting.forward_description') }}</p>
<Checkbox v-model="forward">{{$t('user_reporting.forward_to', [remoteInstance])}}</Checkbox> <Checkbox v-model="forward">
{{ $t('user_reporting.forward_to', [remoteInstance]) }}
</Checkbox>
</div> </div>
<div> <div>
<button class="btn btn-default" @click="reportUser" :disabled="processing">{{$t('user_reporting.submit')}}</button> <button
<div class="alert error" v-if="error"> class="btn btn-default"
:disabled="processing"
@click="reportUser"
>
{{ $t('user_reporting.submit') }}
</button>
<div
v-if="error"
class="alert error"
>
{{ $t('user_reporting.generic_error') }} {{ $t('user_reporting.generic_error') }}
</div> </div>
</div> </div>
</div> </div>
<div class="user-reporting-panel-right"> <div class="user-reporting-panel-right">
<List :items="statuses"> <List :items="statuses">
<template slot="item" slot-scope="{item}"> <template
slot="item"
slot-scope="{item}"
>
<div class="status-fadein user-reporting-panel-sitem"> <div class="status-fadein user-reporting-panel-sitem">
<Status :inConversation="false" :focused="false" :statusoid="item" /> <Status
<Checkbox :checked="isChecked(item.id)" @change="checked => toggleStatus(checked, item.id)" /> :in-conversation="false"
:focused="false"
:statusoid="item"
/>
<Checkbox
:checked="isChecked(item.id)"
@change="checked => toggleStatus(checked, item.id)"
/>
</div> </div>
</template> </template>
</List> </List>

View file

@ -4,16 +4,36 @@
{{ $t('nav.user_search') }} {{ $t('nav.user_search') }}
</div> </div>
<div class="user-search-input-container"> <div class="user-search-input-container">
<input class="user-finder-input" ref="userSearchInput" @keyup.enter="newQuery(username)" v-model="username" :placeholder="$t('finder.find_user')"/> <input
<button class="btn search-button" @click="newQuery(username)"> ref="userSearchInput"
v-model="username"
class="user-finder-input"
:placeholder="$t('finder.find_user')"
@keyup.enter="newQuery(username)"
>
<button
class="btn search-button"
@click="newQuery(username)"
>
<i class="icon-search" /> <i class="icon-search" />
</button> </button>
</div> </div>
<div v-if="loading" class="text-center loading-icon"> <div
v-if="loading"
class="text-center loading-icon"
>
<i class="icon-spin3 animate-spin" /> <i class="icon-spin3 animate-spin" />
</div> </div>
<div v-else class="panel-body"> <div
<FollowCard v-for="user in users" :key="user.id" :user="user" class="list-item"/> v-else
class="panel-body"
>
<FollowCard
v-for="user in users"
:key="user.id"
:user="user"
class="list-item"
/>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,10 +1,18 @@
<template> <template>
<div> <div>
<slot></slot> <slot />
<button class="btn btn-default" @click="confirm" :disabled="disabled"> <button
class="btn btn-default"
:disabled="disabled"
@click="confirm"
>
{{ $t('general.confirm') }} {{ $t('general.confirm') }}
</button> </button>
<button class="btn btn-default" @click="cancel" :disabled="disabled"> <button
class="btn btn-default"
:disabled="disabled"
@click="cancel"
>
{{ $t('general.cancel') }} {{ $t('general.cancel') }}
</button> </button>
</div> </div>

View file

@ -1,44 +1,77 @@
<template> <template>
<div class="setting-item mfa-settings" v-if="readyInit && settings.available"> <div
v-if="readyInit && settings.available"
class="setting-item mfa-settings"
>
<div class="mfa-heading"> <div class="mfa-heading">
<h2>{{ $t('settings.mfa.title') }}</h2> <h2>{{ $t('settings.mfa.title') }}</h2>
</div> </div>
<div> <div>
<div class="setting-item" v-if="!setupInProgress"> <div
v-if="!setupInProgress"
class="setting-item"
>
<!-- Enabled methods --> <!-- Enabled methods -->
<h3>{{ $t('settings.mfa.authentication_methods') }}</h3> <h3>{{ $t('settings.mfa.authentication_methods') }}</h3>
<totp-item :settings="settings" @deactivate="fetchSettings" @activate="activateOTP"/> <totp-item
<br /> :settings="settings"
@deactivate="fetchSettings"
@activate="activateOTP"
/>
<br>
<div v-if="settings.enabled"> <!-- backup codes block--> <div v-if="settings.enabled">
<recovery-codes :backup-codes="backupCodes" v-if="!confirmNewBackupCodes" /> <!-- backup codes block-->
<button class="btn btn-default" @click="getBackupCodes" v-if="!confirmNewBackupCodes"> <recovery-codes
v-if="!confirmNewBackupCodes"
:backup-codes="backupCodes"
/>
<button
v-if="!confirmNewBackupCodes"
class="btn btn-default"
@click="getBackupCodes"
>
{{ $t('settings.mfa.generate_new_recovery_codes') }} {{ $t('settings.mfa.generate_new_recovery_codes') }}
</button> </button>
<div v-if="confirmNewBackupCodes"> <div v-if="confirmNewBackupCodes">
<confirm @confirm="confirmBackupCodes" @cancel="cancelBackupCodes" <confirm
:disabled="backupCodes.inProgress"> :disabled="backupCodes.inProgress"
<p class="warning">{{$t('settings.mfa.warning_of_generate_new_codes')}}</p> @confirm="confirmBackupCodes"
@cancel="cancelBackupCodes"
>
<p class="warning">
{{ $t('settings.mfa.warning_of_generate_new_codes') }}
</p>
</confirm> </confirm>
</div> </div>
</div> </div>
</div> </div>
<div v-if="setupInProgress"> <!-- setup block--> <div v-if="setupInProgress">
<!-- setup block-->
<h3>{{ $t('settings.mfa.setup_otp') }}</h3> <h3>{{ $t('settings.mfa.setup_otp') }}</h3>
<recovery-codes :backup-codes="backupCodes" v-if="!setupOTPInProgress"/> <recovery-codes
v-if="!setupOTPInProgress"
:backup-codes="backupCodes"
/>
<button
<button class="btn btn-default" @click="cancelSetup" v-if="canSetupOTP"> v-if="canSetupOTP"
class="btn btn-default"
@click="cancelSetup"
>
{{ $t('general.cancel') }} {{ $t('general.cancel') }}
</button> </button>
<button class="btn btn-default" v-if="canSetupOTP" @click="setupOTP"> <button
v-if="canSetupOTP"
class="btn btn-default"
@click="setupOTP"
>
{{ $t('settings.mfa.setup_otp') }} {{ $t('settings.mfa.setup_otp') }}
</button> </button>
@ -50,7 +83,10 @@
<div class="qr-code"> <div class="qr-code">
<h4>{{ $t('settings.mfa.scan.title') }}</h4> <h4>{{ $t('settings.mfa.scan.title') }}</h4>
<p>{{ $t('settings.mfa.scan.desc') }}</p> <p>{{ $t('settings.mfa.scan.desc') }}</p>
<qrcode :value="otpSettings.provisioning_uri" :options="{ width: 200 }"></qrcode> <qrcode
:value="otpSettings.provisioning_uri"
:options="{ width: 200 }"
/>
<p> <p>
{{ $t('settings.mfa.scan.secret_code') }}: {{ $t('settings.mfa.scan.secret_code') }}:
{{ otpSettings.key }} {{ otpSettings.key }}
@ -60,25 +96,41 @@
<div class="verify"> <div class="verify">
<h4>{{ $t('general.verify') }}</h4> <h4>{{ $t('general.verify') }}</h4>
<p>{{ $t('settings.mfa.verify.desc') }}</p> <p>{{ $t('settings.mfa.verify.desc') }}</p>
<input type="text" v-model="otpConfirmToken"> <input
v-model="otpConfirmToken"
type="text"
>
<p>{{ $t('settings.enter_current_password_to_confirm') }}:</p> <p>{{ $t('settings.enter_current_password_to_confirm') }}:</p>
<input type="password" v-model="currentPassword"> <input
v-model="currentPassword"
type="password"
>
<div class="confirm-otp-actions"> <div class="confirm-otp-actions">
<button class="btn btn-default" @click="doConfirmOTP"> <button
class="btn btn-default"
@click="doConfirmOTP"
>
{{ $t('settings.mfa.confirm_and_enable') }} {{ $t('settings.mfa.confirm_and_enable') }}
</button> </button>
<button class="btn btn-default" @click="cancelSetup"> <button
class="btn btn-default"
@click="cancelSetup"
>
{{ $t('general.cancel') }} {{ $t('general.cancel') }}
</button> </button>
</div> </div>
<div class="alert error" v-if="error">{{error}}</div> <div
v-if="error"
class="alert error"
>
{{ error }}
</div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
</div> </div>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,10 +1,21 @@
<template> <template>
<div> <div>
<h4 v-if="displayTitle">{{$t('settings.mfa.recovery_codes')}}</h4> <h4 v-if="displayTitle">
{{ $t('settings.mfa.recovery_codes') }}
</h4>
<i v-if="inProgress">{{ $t('settings.mfa.waiting_a_recovery_codes') }}</i> <i v-if="inProgress">{{ $t('settings.mfa.waiting_a_recovery_codes') }}</i>
<template v-if="ready"> <template v-if="ready">
<p class="alert warning">{{$t('settings.mfa.recovery_codes_warning')}}</p> <p class="alert warning">
<ul class="backup-codes"><li v-for="code in backupCodes.codes">{{code}}</li></ul> {{ $t('settings.mfa.recovery_codes_warning') }}
</p>
<ul class="backup-codes">
<li
v-for="code in backupCodes.codes"
:key="code"
>
{{ code }}
</li>
</ul>
</template> </template>
</div> </div>
</template> </template>

View file

@ -2,22 +2,42 @@
<div> <div>
<div class="method-item"> <div class="method-item">
<strong>{{ $t('settings.mfa.otp') }}</strong> <strong>{{ $t('settings.mfa.otp') }}</strong>
<button class="btn btn-default" v-if="!isActivated" @click="doActivate"> <button
v-if="!isActivated"
class="btn btn-default"
@click="doActivate"
>
{{ $t('general.enable') }} {{ $t('general.enable') }}
</button> </button>
<button class="btn btn-default" :disabled="deactivate" @click="doDeactivate" <button
v-if="isActivated"> v-if="isActivated"
class="btn btn-default"
:disabled="deactivate"
@click="doDeactivate"
>
{{ $t('general.disable') }} {{ $t('general.disable') }}
</button> </button>
</div> </div>
<confirm @confirm="confirmDeactivate" @cancel="cancelDeactivate" <confirm
:disabled="inProgress" v-if="deactivate"> v-if="deactivate"
:disabled="inProgress"
@confirm="confirmDeactivate"
@cancel="cancelDeactivate"
>
{{ $t('settings.enter_current_password_to_confirm') }}: {{ $t('settings.enter_current_password_to_confirm') }}:
<input type="password" v-model="currentPassword"> <input
v-model="currentPassword"
type="password"
>
</confirm> </confirm>
<div class="alert error" v-if="error">{{error}}</div> <div
v-if="error"
class="alert error"
>
{{ error }}
</div>
</div> </div>
</template> </template>
<script src="./mfa_totp.js"></script> <script src="./mfa_totp.js"></script>

View file

@ -6,11 +6,19 @@
</div> </div>
<transition name="fade"> <transition name="fade">
<template v-if="currentSaveStateNotice"> <template v-if="currentSaveStateNotice">
<div @click.prevent class="alert error" v-if="currentSaveStateNotice.error"> <div
v-if="currentSaveStateNotice.error"
class="alert error"
@click.prevent
>
{{ $t('settings.saving_err') }} {{ $t('settings.saving_err') }}
</div> </div>
<div @click.prevent class="alert transparent" v-if="!currentSaveStateNotice.error"> <div
v-if="!currentSaveStateNotice.error"
class="alert transparent"
@click.prevent
>
{{ $t('settings.saving_ok') }} {{ $t('settings.saving_ok') }}
</div> </div>
</template> </template>
@ -22,90 +30,196 @@
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.name_bio') }}</h2> <h2>{{ $t('settings.name_bio') }}</h2>
<p>{{ $t('settings.name') }}</p> <p>{{ $t('settings.name') }}</p>
<EmojiInput :suggest="emojiSuggestor" v-model="newName"> <EmojiInput
<input
v-model="newName" v-model="newName"
:suggest="emojiSuggestor"
>
<input
id="username" id="username"
v-model="newName"
classname="name-changer" classname="name-changer"
/> >
</EmojiInput> </EmojiInput>
<p>{{ $t('settings.bio') }}</p> <p>{{ $t('settings.bio') }}</p>
<EmojiInput :suggest="emojiUserSuggestor" v-model="newBio"> <EmojiInput
v-model="newBio"
:suggest="emojiUserSuggestor"
>
<textarea <textarea
v-model="newBio" v-model="newBio"
classname="bio" classname="bio"
/> />
</EmojiInput> </EmojiInput>
<p> <p>
<input type="checkbox" v-model="newLocked" id="account-locked"> <input
id="account-locked"
v-model="newLocked"
type="checkbox"
>
<label for="account-locked">{{ $t('settings.lock_account_description') }}</label> <label for="account-locked">{{ $t('settings.lock_account_description') }}</label>
</p> </p>
<div> <div>
<label for="default-vis">{{ $t('settings.default_vis') }}</label> <label for="default-vis">{{ $t('settings.default_vis') }}</label>
<div id="default-vis" class="visibility-tray"> <div
id="default-vis"
class="visibility-tray"
>
<scope-selector <scope-selector
:showAll="true" :show-all="true"
:userDefault="newDefaultScope" :user-default="newDefaultScope"
:initialScope="newDefaultScope" :initial-scope="newDefaultScope"
:onScopeChange="changeVis"/> :on-scope-change="changeVis"
/>
</div> </div>
</div> </div>
<p> <p>
<input type="checkbox" v-model="newNoRichText" id="account-no-rich-text"> <input
id="account-no-rich-text"
v-model="newNoRichText"
type="checkbox"
>
<label for="account-no-rich-text">{{ $t('settings.no_rich_text_description') }}</label> <label for="account-no-rich-text">{{ $t('settings.no_rich_text_description') }}</label>
</p> </p>
<p> <p>
<input type="checkbox" v-model="hideFollows" id="account-hide-follows"> <input
id="account-hide-follows"
v-model="hideFollows"
type="checkbox"
>
<label for="account-hide-follows">{{ $t('settings.hide_follows_description') }}</label> <label for="account-hide-follows">{{ $t('settings.hide_follows_description') }}</label>
</p> </p>
<p> <p>
<input type="checkbox" v-model="hideFollowers" id="account-hide-followers"> <input
id="account-hide-followers"
v-model="hideFollowers"
type="checkbox"
>
<label for="account-hide-followers">{{ $t('settings.hide_followers_description') }}</label> <label for="account-hide-followers">{{ $t('settings.hide_followers_description') }}</label>
</p> </p>
<p> <p>
<input type="checkbox" v-model="showRole" id="account-show-role"> <input
<label for="account-show-role" v-if="role === 'admin'">{{$t('settings.show_admin_badge')}}</label> id="account-show-role"
<label for="account-show-role" v-if="role === 'moderator'">{{$t('settings.show_moderator_badge')}}</label> v-model="showRole"
type="checkbox"
>
<label
v-if="role === 'admin'"
for="account-show-role"
>{{ $t('settings.show_admin_badge') }}</label>
<label
v-if="role === 'moderator'"
for="account-show-role"
>{{ $t('settings.show_moderator_badge') }}</label>
</p> </p>
<button :disabled='newName && newName.length === 0' class="btn btn-default" @click="updateProfile">{{$t('general.submit')}}</button> <button
:disabled="newName && newName.length === 0"
class="btn btn-default"
@click="updateProfile"
>
{{ $t('general.submit') }}
</button>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.avatar') }}</h2> <h2>{{ $t('settings.avatar') }}</h2>
<p class="visibility-notice">{{$t('settings.avatar_size_instruction')}}</p> <p class="visibility-notice">
{{ $t('settings.avatar_size_instruction') }}
</p>
<p>{{ $t('settings.current_avatar') }}</p> <p>{{ $t('settings.current_avatar') }}</p>
<img :src="user.profile_image_url_original" class="current-avatar" /> <img
:src="user.profile_image_url_original"
class="current-avatar"
>
<p>{{ $t('settings.set_new_avatar') }}</p> <p>{{ $t('settings.set_new_avatar') }}</p>
<button class="btn" type="button" id="pick-avatar" v-show="pickAvatarBtnVisible">{{$t('settings.upload_a_photo')}}</button> <button
<image-cropper trigger="#pick-avatar" :submitHandler="submitAvatar" @open="pickAvatarBtnVisible=false" @close="pickAvatarBtnVisible=true" /> v-show="pickAvatarBtnVisible"
id="pick-avatar"
class="btn"
type="button"
>
{{ $t('settings.upload_a_photo') }}
</button>
<image-cropper
trigger="#pick-avatar"
:submit-handler="submitAvatar"
@open="pickAvatarBtnVisible=false"
@close="pickAvatarBtnVisible=true"
/>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.profile_banner') }}</h2> <h2>{{ $t('settings.profile_banner') }}</h2>
<p>{{ $t('settings.current_profile_banner') }}</p> <p>{{ $t('settings.current_profile_banner') }}</p>
<img :src="user.cover_photo" class="banner" /> <img
:src="user.cover_photo"
class="banner"
>
<p>{{ $t('settings.set_new_profile_banner') }}</p> <p>{{ $t('settings.set_new_profile_banner') }}</p>
<img class="banner" v-bind:src="bannerPreview" v-if="bannerPreview" /> <img
v-if="bannerPreview"
class="banner"
:src="bannerPreview"
>
<div> <div>
<input type="file" @change="uploadFile('banner', $event)" /> <input
type="file"
@change="uploadFile('banner', $event)"
>
</div> </div>
<i class=" icon-spin4 animate-spin uploading" v-if="bannerUploading"></i> <i
<button class="btn btn-default" v-else-if="bannerPreview" @click="submitBanner">{{$t('general.submit')}}</button> v-if="bannerUploading"
<div class='alert error' v-if="bannerUploadError"> class=" icon-spin4 animate-spin uploading"
/>
<button
v-else-if="bannerPreview"
class="btn btn-default"
@click="submitBanner"
>
{{ $t('general.submit') }}
</button>
<div
v-if="bannerUploadError"
class="alert error"
>
Error: {{ bannerUploadError }} Error: {{ bannerUploadError }}
<i class="button-icon icon-cancel" @click="clearUploadError('banner')"></i> <i
class="button-icon icon-cancel"
@click="clearUploadError('banner')"
/>
</div> </div>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.profile_background') }}</h2> <h2>{{ $t('settings.profile_background') }}</h2>
<p>{{ $t('settings.set_new_profile_background') }}</p> <p>{{ $t('settings.set_new_profile_background') }}</p>
<img class="bg" v-bind:src="backgroundPreview" v-if="backgroundPreview" /> <img
v-if="backgroundPreview"
class="bg"
:src="backgroundPreview"
>
<div> <div>
<input type="file" @change="uploadFile('background', $event)" /> <input
type="file"
@change="uploadFile('background', $event)"
>
</div> </div>
<i class=" icon-spin4 animate-spin uploading" v-if="backgroundUploading"></i> <i
<button class="btn btn-default" v-else-if="backgroundPreview" @click="submitBg">{{$t('general.submit')}}</button> v-if="backgroundUploading"
<div class='alert error' v-if="backgroundUploadError"> class=" icon-spin4 animate-spin uploading"
/>
<button
v-else-if="backgroundPreview"
class="btn btn-default"
@click="submitBg"
>
{{ $t('general.submit') }}
</button>
<div
v-if="backgroundUploadError"
class="alert error"
>
Error: {{ backgroundUploadError }} Error: {{ backgroundUploadError }}
<i class="button-icon icon-cancel" @click="clearUploadError('background')"></i> <i
class="button-icon icon-cancel"
@click="clearUploadError('background')"
/>
</div> </div>
</div> </div>
</div> </div>
@ -115,20 +229,40 @@
<h2>{{ $t('settings.change_password') }}</h2> <h2>{{ $t('settings.change_password') }}</h2>
<div> <div>
<p>{{ $t('settings.current_password') }}</p> <p>{{ $t('settings.current_password') }}</p>
<input type="password" v-model="changePasswordInputs[0]"> <input
v-model="changePasswordInputs[0]"
type="password"
>
</div> </div>
<div> <div>
<p>{{ $t('settings.new_password') }}</p> <p>{{ $t('settings.new_password') }}</p>
<input type="password" v-model="changePasswordInputs[1]"> <input
v-model="changePasswordInputs[1]"
type="password"
>
</div> </div>
<div> <div>
<p>{{ $t('settings.confirm_new_password') }}</p> <p>{{ $t('settings.confirm_new_password') }}</p>
<input type="password" v-model="changePasswordInputs[2]"> <input
v-model="changePasswordInputs[2]"
type="password"
>
</div> </div>
<button class="btn btn-default" @click="changePassword">{{$t('general.submit')}}</button> <button
<p v-if="changedPassword">{{$t('settings.changed_password')}}</p> class="btn btn-default"
<p v-else-if="changePasswordError !== false">{{$t('settings.change_password_error')}}</p> @click="changePassword"
<p v-if="changePasswordError">{{changePasswordError}}</p> >
{{ $t('general.submit') }}
</button>
<p v-if="changedPassword">
{{ $t('settings.changed_password') }}
</p>
<p v-else-if="changePasswordError !== false">
{{ $t('settings.change_password_error') }}
</p>
<p v-if="changePasswordError">
{{ changePasswordError }}
</p>
</div> </div>
<div class="setting-item"> <div class="setting-item">
@ -138,15 +272,21 @@
<tr> <tr>
<th>{{ $t('settings.app_name') }}</th> <th>{{ $t('settings.app_name') }}</th>
<th>{{ $t('settings.valid_until') }}</th> <th>{{ $t('settings.valid_until') }}</th>
<th></th> <th />
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="oauthToken in oauthTokens" :key="oauthToken.id"> <tr
v-for="oauthToken in oauthTokens"
:key="oauthToken.id"
>
<td>{{ oauthToken.appName }}</td> <td>{{ oauthToken.appName }}</td>
<td>{{ oauthToken.validUntil }}</td> <td>{{ oauthToken.validUntil }}</td>
<td class="actions"> <td class="actions">
<button class="btn btn-default" @click="revokeToken(oauthToken.id)"> <button
class="btn btn-default"
@click="revokeToken(oauthToken.id)"
>
{{ $t('settings.revoke_token') }} {{ $t('settings.revoke_token') }}
</button> </button>
</td> </td>
@ -157,44 +297,83 @@
<mfa /> <mfa />
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.delete_account') }}</h2> <h2>{{ $t('settings.delete_account') }}</h2>
<p v-if="!deletingAccount">{{$t('settings.delete_account_description')}}</p> <p v-if="!deletingAccount">
{{ $t('settings.delete_account_description') }}
</p>
<div v-if="deletingAccount"> <div v-if="deletingAccount">
<p>{{ $t('settings.delete_account_instructions') }}</p> <p>{{ $t('settings.delete_account_instructions') }}</p>
<p>{{ $t('login.password') }}</p> <p>{{ $t('login.password') }}</p>
<input type="password" v-model="deleteAccountConfirmPasswordInput"> <input
<button class="btn btn-default" @click="deleteAccount">{{$t('settings.delete_account')}}</button> v-model="deleteAccountConfirmPasswordInput"
type="password"
>
<button
class="btn btn-default"
@click="deleteAccount"
>
{{ $t('settings.delete_account') }}
</button>
</div> </div>
<p v-if="deleteAccountError !== false">{{$t('settings.delete_account_error')}}</p> <p v-if="deleteAccountError !== false">
<p v-if="deleteAccountError">{{deleteAccountError}}</p> {{ $t('settings.delete_account_error') }}
<button class="btn btn-default" v-if="!deletingAccount" @click="confirmDelete">{{$t('general.submit')}}</button> </p>
<p v-if="deleteAccountError">
{{ deleteAccountError }}
</p>
<button
v-if="!deletingAccount"
class="btn btn-default"
@click="confirmDelete"
>
{{ $t('general.submit') }}
</button>
</div> </div>
</div> </div>
<div :label="$t('settings.notifications')" v-if="pleromaBackend"> <div
v-if="pleromaBackend"
:label="$t('settings.notifications')"
>
<div class="setting-item"> <div class="setting-item">
<div class="select-multiple"> <div class="select-multiple">
<span class="label">{{ $t('settings.notification_setting') }}</span> <span class="label">{{ $t('settings.notification_setting') }}</span>
<ul class="option-list"> <ul class="option-list">
<li> <li>
<input type="checkbox" id="notification-setting-follows" v-model="notificationSettings.follows"> <input
id="notification-setting-follows"
v-model="notificationSettings.follows"
type="checkbox"
>
<label for="notification-setting-follows"> <label for="notification-setting-follows">
{{ $t('settings.notification_setting_follows') }} {{ $t('settings.notification_setting_follows') }}
</label> </label>
</li> </li>
<li> <li>
<input type="checkbox" id="notification-setting-followers" v-model="notificationSettings.followers"> <input
id="notification-setting-followers"
v-model="notificationSettings.followers"
type="checkbox"
>
<label for="notification-setting-followers"> <label for="notification-setting-followers">
{{ $t('settings.notification_setting_followers') }} {{ $t('settings.notification_setting_followers') }}
</label> </label>
</li> </li>
<li> <li>
<input type="checkbox" id="notification-setting-non-follows" v-model="notificationSettings.non_follows"> <input
id="notification-setting-non-follows"
v-model="notificationSettings.non_follows"
type="checkbox"
>
<label for="notification-setting-non-follows"> <label for="notification-setting-non-follows">
{{ $t('settings.notification_setting_non_follows') }} {{ $t('settings.notification_setting_non_follows') }}
</label> </label>
</li> </li>
<li> <li>
<input type="checkbox" id="notification-setting-non-followers" v-model="notificationSettings.non_followers"> <input
id="notification-setting-non-followers"
v-model="notificationSettings.non_followers"
type="checkbox"
>
<label for="notification-setting-non-followers"> <label for="notification-setting-non-followers">
{{ $t('settings.notification_setting_non_followers') }} {{ $t('settings.notification_setting_non_followers') }}
</label> </label>
@ -203,76 +382,164 @@
</div> </div>
<p>{{ $t('settings.notification_mutes') }}</p> <p>{{ $t('settings.notification_mutes') }}</p>
<p>{{ $t('settings.notification_blocks') }}</p> <p>{{ $t('settings.notification_blocks') }}</p>
<button class="btn btn-default" @click="updateNotificationSettings">{{$t('general.submit')}}</button> <button
class="btn btn-default"
@click="updateNotificationSettings"
>
{{ $t('general.submit') }}
</button>
</div> </div>
</div> </div>
<div :label="$t('settings.data_import_export_tab')" v-if="pleromaBackend"> <div
v-if="pleromaBackend"
:label="$t('settings.data_import_export_tab')"
>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.follow_import') }}</h2> <h2>{{ $t('settings.follow_import') }}</h2>
<p>{{ $t('settings.import_followers_from_a_csv_file') }}</p> <p>{{ $t('settings.import_followers_from_a_csv_file') }}</p>
<Importer :submitHandler="importFollows" :successMessage="$t('settings.follows_imported')" :errorMessage="$t('settings.follow_import_error')" /> <Importer
:submit-handler="importFollows"
:success-message="$t('settings.follows_imported')"
:error-message="$t('settings.follow_import_error')"
/>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.follow_export') }}</h2> <h2>{{ $t('settings.follow_export') }}</h2>
<Exporter :getContent="getFollowsContent" filename="friends.csv" :exportButtonLabel="$t('settings.follow_export_button')" /> <Exporter
:get-content="getFollowsContent"
filename="friends.csv"
:export-button-label="$t('settings.follow_export_button')"
/>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.block_import') }}</h2> <h2>{{ $t('settings.block_import') }}</h2>
<p>{{ $t('settings.import_blocks_from_a_csv_file') }}</p> <p>{{ $t('settings.import_blocks_from_a_csv_file') }}</p>
<Importer :submitHandler="importBlocks" :successMessage="$t('settings.blocks_imported')" :errorMessage="$t('settings.block_import_error')" /> <Importer
:submit-handler="importBlocks"
:success-message="$t('settings.blocks_imported')"
:error-message="$t('settings.block_import_error')"
/>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.block_export') }}</h2> <h2>{{ $t('settings.block_export') }}</h2>
<Exporter :getContent="getBlocksContent" filename="blocks.csv" :exportButtonLabel="$t('settings.block_export_button')" /> <Exporter
:get-content="getBlocksContent"
filename="blocks.csv"
:export-button-label="$t('settings.block_export_button')"
/>
</div> </div>
</div> </div>
<div :label="$t('settings.blocks_tab')"> <div :label="$t('settings.blocks_tab')">
<div class="profile-edit-usersearch-wrapper"> <div class="profile-edit-usersearch-wrapper">
<Autosuggest :filter="filterUnblockedUsers" :query="queryUserIds" :placeholder="$t('settings.search_user_to_block')"> <Autosuggest
<BlockCard slot-scope="row" :userId="row.item"/> :filter="filterUnblockedUsers"
:query="queryUserIds"
:placeholder="$t('settings.search_user_to_block')"
>
<BlockCard
slot-scope="row"
:user-id="row.item"
/>
</Autosuggest> </Autosuggest>
</div> </div>
<BlockList :refresh="true" :getKey="identity"> <BlockList
<template slot="header" slot-scope="{selected}"> :refresh="true"
:get-key="identity"
>
<template
slot="header"
slot-scope="{selected}"
>
<div class="profile-edit-bulk-actions"> <div class="profile-edit-bulk-actions">
<ProgressButton class="btn btn-default" v-if="selected.length > 0" :click="() => blockUsers(selected)"> <ProgressButton
v-if="selected.length > 0"
class="btn btn-default"
:click="() => blockUsers(selected)"
>
{{ $t('user_card.block') }} {{ $t('user_card.block') }}
<template slot="progress">{{ $t('user_card.block_progress') }}</template> <template slot="progress">
{{ $t('user_card.block_progress') }}
</template>
</ProgressButton> </ProgressButton>
<ProgressButton class="btn btn-default" v-if="selected.length > 0" :click="() => unblockUsers(selected)"> <ProgressButton
v-if="selected.length > 0"
class="btn btn-default"
:click="() => unblockUsers(selected)"
>
{{ $t('user_card.unblock') }} {{ $t('user_card.unblock') }}
<template slot="progress">{{ $t('user_card.unblock_progress') }}</template> <template slot="progress">
{{ $t('user_card.unblock_progress') }}
</template>
</ProgressButton> </ProgressButton>
</div> </div>
</template> </template>
<template slot="item" slot-scope="{item}"><BlockCard :userId="item" /></template> <template
<template slot="empty">{{$t('settings.no_blocks')}}</template> slot="item"
slot-scope="{item}"
>
<BlockCard :user-id="item" />
</template>
<template slot="empty">
{{ $t('settings.no_blocks') }}
</template>
</BlockList> </BlockList>
</div> </div>
<div :label="$t('settings.mutes_tab')"> <div :label="$t('settings.mutes_tab')">
<div class="profile-edit-usersearch-wrapper"> <div class="profile-edit-usersearch-wrapper">
<Autosuggest :filter="filterUnMutedUsers" :query="queryUserIds" :placeholder="$t('settings.search_user_to_mute')"> <Autosuggest
<MuteCard slot-scope="row" :userId="row.item"/> :filter="filterUnMutedUsers"
:query="queryUserIds"
:placeholder="$t('settings.search_user_to_mute')"
>
<MuteCard
slot-scope="row"
:user-id="row.item"
/>
</Autosuggest> </Autosuggest>
</div> </div>
<MuteList :refresh="true" :getKey="identity"> <MuteList
<template slot="header" slot-scope="{selected}"> :refresh="true"
:get-key="identity"
>
<template
slot="header"
slot-scope="{selected}"
>
<div class="profile-edit-bulk-actions"> <div class="profile-edit-bulk-actions">
<ProgressButton class="btn btn-default" v-if="selected.length > 0" :click="() => muteUsers(selected)"> <ProgressButton
v-if="selected.length > 0"
class="btn btn-default"
:click="() => muteUsers(selected)"
>
{{ $t('user_card.mute') }} {{ $t('user_card.mute') }}
<template slot="progress">{{ $t('user_card.mute_progress') }}</template> <template slot="progress">
{{ $t('user_card.mute_progress') }}
</template>
</ProgressButton> </ProgressButton>
<ProgressButton class="btn btn-default" v-if="selected.length > 0" :click="() => unmuteUsers(selected)"> <ProgressButton
v-if="selected.length > 0"
class="btn btn-default"
:click="() => unmuteUsers(selected)"
>
{{ $t('user_card.unmute') }} {{ $t('user_card.unmute') }}
<template slot="progress">{{ $t('user_card.unmute_progress') }}</template> <template slot="progress">
{{ $t('user_card.unmute_progress') }}
</template>
</ProgressButton> </ProgressButton>
</div> </div>
</template> </template>
<template slot="item" slot-scope="{item}"><MuteCard :userId="item" /></template> <template
<template slot="empty">{{$t('settings.no_mutes')}}</template> slot="item"
slot-scope="{item}"
>
<MuteCard :user-id="item" />
</template>
<template slot="empty">
{{ $t('settings.no_mutes') }}
</template>
</MuteList> </MuteList>
</div> </div>
</tab-switcher> </tab-switcher>

View file

@ -1,10 +1,11 @@
<template> <template>
<video class="video" <video
@loadeddata="onVideoDataLoad" class="video"
:src="attachment.url" :src="attachment.url"
:loop="loopVideo" :loop="loopVideo"
:controls="controls" :controls="controls"
playsinline playsinline
@loadeddata="onVideoDataLoad"
/> />
</template> </template>

View file

@ -4,7 +4,12 @@
{{ $t('who_to_follow.who_to_follow') }} {{ $t('who_to_follow.who_to_follow') }}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<FollowCard v-for="user in users" :key="user.id" :user="user" class="list-item"/> <FollowCard
v-for="user in users"
:key="user.id"
:user="user"
class="list-item"
/>
</div> </div>
</div> </div>
</template> </template>

View file

@ -7,11 +7,15 @@
</div> </div>
</div> </div>
<div class="who-to-follow"> <div class="who-to-follow">
<p v-for="user in usersToFollow" class="who-to-follow-items"> <p
<img v-bind:src="user.img" /> v-for="user in usersToFollow"
<router-link v-bind:to="userProfileLink(user.id, user.name)"> :key="user.id"
class="who-to-follow-items"
>
<img :src="user.img">
<router-link :to="userProfileLink(user.id, user.name)">
{{ user.name }} {{ user.name }}
</router-link><br /> </router-link><br>
</p> </p>
<p class="who-to-follow-more"> <p class="who-to-follow-more">
<router-link :to="{ name: 'who-to-follow' }"> <router-link :to="{ name: 'who-to-follow' }">

View file

@ -14,29 +14,6 @@ const withLoadMore = ({
const props = originalProps.filter(v => v !== childPropName).concat(additionalPropNames) const props = originalProps.filter(v => v !== childPropName).concat(additionalPropNames)
return Vue.component('withLoadMore', { return Vue.component('withLoadMore', {
render (createElement) {
const props = {
props: {
...this.$props,
[childPropName]: this.entries
},
on: this.$listeners,
scopedSlots: this.$scopedSlots
}
const children = Object.entries(this.$slots).map(([key, value]) => createElement('template', { slot: key }, value))
return (
<div class="with-load-more">
<WrappedComponent {...props}>
{children}
</WrappedComponent>
<div class="with-load-more-footer">
{this.error && <a onClick={this.fetchEntries} class="alert error">{this.$t('general.generic_error')}</a>}
{!this.error && this.loading && <i class="icon-spin3 animate-spin"/>}
{!this.error && !this.loading && !this.bottomedOut && <a onClick={this.fetchEntries}>{this.$t('general.more')}</a>}
</div>
</div>
)
},
props, props,
data () { data () {
return { return {
@ -87,6 +64,29 @@ const withLoadMore = ({
this.fetchEntries() this.fetchEntries()
} }
} }
},
render (createElement) {
const props = {
props: {
...this.$props,
[childPropName]: this.entries
},
on: this.$listeners,
scopedSlots: this.$scopedSlots
}
const children = Object.entries(this.$slots).map(([key, value]) => createElement('template', { slot: key }, value))
return (
<div class="with-load-more">
<WrappedComponent {...props}>
{children}
</WrappedComponent>
<div class="with-load-more-footer">
{this.error && <a onClick={this.fetchEntries} class="alert error">{this.$t('general.generic_error')}</a>}
{!this.error && this.loading && <i class="icon-spin3 animate-spin"/>}
{!this.error && !this.loading && !this.bottomedOut && <a onClick={this.fetchEntries}>{this.$t('general.more')}</a>}
</div>
</div>
)
} }
}) })
} }

View file

@ -17,35 +17,6 @@ const withSubscription = ({
...props, ...props,
'refresh' // boolean saying to force-fetch data whenever created 'refresh' // boolean saying to force-fetch data whenever created
], ],
render (createElement) {
if (!this.error && !this.loading) {
const props = {
props: {
...this.$props,
[childPropName]: this.fetchedData
},
on: this.$listeners,
scopedSlots: this.$scopedSlots
}
const children = Object.entries(this.$slots).map(([key, value]) => createElement('template', { slot: key }, value))
return (
<div class="with-subscription">
<WrappedComponent {...props}>
{children}
</WrappedComponent>
</div>
)
} else {
return (
<div class="with-subscription-loading">
{this.error
? <a onClick={this.fetchData} class="alert error">{this.$t('general.generic_error')}</a>
: <i class="icon-spin3 animate-spin"/>
}
</div>
)
}
},
data () { data () {
return { return {
loading: false, loading: false,
@ -77,6 +48,35 @@ const withSubscription = ({
}) })
} }
} }
},
render (createElement) {
if (!this.error && !this.loading) {
const props = {
props: {
...this.$props,
[childPropName]: this.fetchedData
},
on: this.$listeners,
scopedSlots: this.$scopedSlots
}
const children = Object.entries(this.$slots).map(([key, value]) => createElement('template', { slot: key }, value))
return (
<div class="with-subscription">
<WrappedComponent {...props}>
{children}
</WrappedComponent>
</div>
)
} else {
return (
<div class="with-subscription-loading">
{this.error
? <a onClick={this.fetchData} class="alert error">{this.$t('general.generic_error')}</a>
: <i class="icon-spin3 animate-spin"/>
}
</div>
)
}
} }
}) })
} }

View file

@ -78,6 +78,20 @@
"repeated_you": "a repetit vòstre estatut", "repeated_you": "a repetit vòstre estatut",
"no_more_notifications": "Pas mai de notificacions" "no_more_notifications": "Pas mai de notificacions"
}, },
"polls": {
"add_poll": "Ajustar un sondatge",
"add_option": "Ajustar dopcions",
"option": "Opcion",
"votes": "vòtes",
"vote": "Votar",
"type": "Tipe de sondatge",
"single_choice": "Causida unica",
"multiple_choices": "Causida multipla",
"expiry": "Durada del sondatge",
"expires_in": "Lo sondatge sacabarà {0}",
"expired": "Sondatge acabat {0}",
"not_enough_options": "I a pas pro dopcions"
},
"post_status": { "post_status": {
"new_status": "Publicar destatuts novèls", "new_status": "Publicar destatuts novèls",
"account_not_locked_warning": "Vòstre compte es pas {0}. Qual que siá pòt vos seguir per veire vòstras publicacions destinadas pas qua vòstres seguidors.", "account_not_locked_warning": "Vòstre compte es pas {0}. Qual que siá pòt vos seguir per veire vòstras publicacions destinadas pas qua vòstres seguidors.",
@ -197,6 +211,7 @@
"loop_video": "Bocla vidèo", "loop_video": "Bocla vidèo",
"loop_video_silent_only": "Legir en bocla solament las vidèos sens son (coma los « Gifs » de Mastodon)", "loop_video_silent_only": "Legir en bocla solament las vidèos sens son (coma los « Gifs » de Mastodon)",
"mutes_tab": "Agamats", "mutes_tab": "Agamats",
"interactions_tab": "Interaccions",
"play_videos_in_modal": "Legir las vidèos dirèctament dins la visualizaira mèdia", "play_videos_in_modal": "Legir las vidèos dirèctament dins la visualizaira mèdia",
"use_contain_fit": "Talhar pas las pèças juntas per las vinhetas", "use_contain_fit": "Talhar pas las pèças juntas per las vinhetas",
"name": "Nom", "name": "Nom",
@ -265,6 +280,13 @@
"true": "òc" "true": "òc"
}, },
"notifications": "Notificacions", "notifications": "Notificacions",
"notification_setting": "Receber las notificacions de:",
"notification_setting_follows": "Utilizaires que seguissètz",
"notification_setting_non_follows": "Utilizaires que seguissètz pas",
"notification_setting_followers": "Utilizaires que vos seguisson",
"notification_setting_non_followers": "Utilizaires que vos seguisson pas",
"notification_mutes": "Per receber pas mai dun utilizaire en particular, botatz-lo en silenci.",
"notification_blocks": "Blocar un utilizaire arrèsta totas las notificacions tan coma quitar de los seguir.",
"enable_web_push_notifications": "Activar las notificacions web push", "enable_web_push_notifications": "Activar las notificacions web push",
"style": { "style": {
"switcher": { "switcher": {
@ -386,14 +408,14 @@
"days": "{0} jorns", "days": "{0} jorns",
"day_short": "{0} jorn", "day_short": "{0} jorn",
"days_short": "{0} jorns", "days_short": "{0} jorns",
"hour": "{0} hour", "hour": "{0} ora",
"hours": "{0} hours", "hours": "{0} oras",
"hour_short": "{0}h", "hour_short": "{0}h",
"hours_short": "{0}h", "hours_short": "{0}h",
"in_future": "in {0}", "in_future": "daquí {0}",
"in_past": "fa {0}", "in_past": "fa {0}",
"minute": "{0} minute", "minute": "{0} minuta",
"minutes": "{0} minutes", "minutes": "{0} minutas",
"minute_short": "{0}min", "minute_short": "{0}min",
"minutes_short": "{0}min", "minutes_short": "{0}min",
"month": "{0} mes", "month": "{0} mes",
@ -402,12 +424,12 @@
"months_short": "{0} meses", "months_short": "{0} meses",
"now": "ara meteis", "now": "ara meteis",
"now_short": "ara meteis", "now_short": "ara meteis",
"second": "{0} second", "second": "{0} segonda",
"seconds": "{0} seconds", "seconds": "{0} segondas",
"second_short": "{0}s", "second_short": "{0}s",
"seconds_short": "{0}s", "seconds_short": "{0}s",
"week": "{0} setm.", "week": "{0} setmana.",
"weeks": "{0} setm.", "weeks": "{0} setmanas.",
"week_short": "{0} setm.", "week_short": "{0} setm.",
"weeks_short": "{0} setm.", "weeks_short": "{0} setm.",
"year": "{0} an", "year": "{0} an",

View file

@ -73,6 +73,7 @@ const mutations = {
// actions // actions
const actions = { const actions = {
// eslint-disable-next-line camelcase
async login ({ state, dispatch, commit }, { access_token }) { async login ({ state, dispatch, commit }, { access_token }) {
commit('setToken', access_token, { root: true }) commit('setToken', access_token, { root: true })
await dispatch('loginUser', access_token, { root: true }) await dispatch('loginUser', access_token, { root: true })

Some files were not shown because too many files have changed in this diff Show more