Merge branch 'develop' of git.pleroma.social:pleroma/pleroma-fe into develop
This commit is contained in:
commit
763d2c0ce4
32 changed files with 2290 additions and 635 deletions
|
@ -1,7 +1,7 @@
|
||||||
# This file is a template, and might need editing before it works on your project.
|
# This file is a template, and might need editing before it works on your project.
|
||||||
# Official framework image. Look for the different tagged releases at:
|
# Official framework image. Look for the different tagged releases at:
|
||||||
# https://hub.docker.com/r/library/node/tags/
|
# https://hub.docker.com/r/library/node/tags/
|
||||||
image: node:8
|
image: node:10
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- lint
|
- lint
|
||||||
|
@ -14,6 +14,7 @@ lint:
|
||||||
script:
|
script:
|
||||||
- yarn
|
- yarn
|
||||||
- npm run lint
|
- npm run lint
|
||||||
|
- npm run stylelint
|
||||||
|
|
||||||
test:
|
test:
|
||||||
stage: test
|
stage: test
|
||||||
|
|
19
.stylelintrc.json
Normal file
19
.stylelintrc.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"stylelint-rscss/config",
|
||||||
|
"stylelint-config-recommended",
|
||||||
|
"stylelint-config-standard"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"declaration-no-important": true,
|
||||||
|
"rscss/no-descendant-combinator": false,
|
||||||
|
"rscss/class-format": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"component": "pascal-case",
|
||||||
|
"variant": "^-[a-z]\\w+",
|
||||||
|
"element": "^[a-z]\\w+"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
"unit:watch": "karma start test/unit/karma.conf.js --single-run=false",
|
"unit:watch": "karma start test/unit/karma.conf.js --single-run=false",
|
||||||
"e2e": "node test/e2e/runner.js",
|
"e2e": "node test/e2e/runner.js",
|
||||||
"test": "npm run unit && npm run e2e",
|
"test": "npm run unit && npm run e2e",
|
||||||
|
"stylelint": "npx stylelint src/components/status/status.scss",
|
||||||
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs",
|
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs",
|
||||||
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
|
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
|
||||||
},
|
},
|
||||||
|
@ -22,8 +23,8 @@
|
||||||
"cropperjs": "^1.4.3",
|
"cropperjs": "^1.4.3",
|
||||||
"diff": "^3.0.1",
|
"diff": "^3.0.1",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"parse-link-header": "^1.0.1",
|
|
||||||
"localforage": "^1.5.0",
|
"localforage": "^1.5.0",
|
||||||
|
"parse-link-header": "^1.0.1",
|
||||||
"phoenix": "^1.3.0",
|
"phoenix": "^1.3.0",
|
||||||
"portal-vue": "^2.1.4",
|
"portal-vue": "^2.1.4",
|
||||||
"v-click-outside": "^2.1.1",
|
"v-click-outside": "^2.1.1",
|
||||||
|
@ -36,7 +37,6 @@
|
||||||
"vuex": "^3.0.1"
|
"vuex": "^3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"karma-mocha-reporter": "^2.2.1",
|
|
||||||
"@babel/core": "^7.7.5",
|
"@babel/core": "^7.7.5",
|
||||||
"@babel/plugin-transform-runtime": "^7.7.6",
|
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||||
"@babel/preset-env": "^7.7.6",
|
"@babel/preset-env": "^7.7.6",
|
||||||
|
@ -80,6 +80,7 @@
|
||||||
"karma-coverage": "^1.1.1",
|
"karma-coverage": "^1.1.1",
|
||||||
"karma-firefox-launcher": "^1.1.0",
|
"karma-firefox-launcher": "^1.1.0",
|
||||||
"karma-mocha": "^1.2.0",
|
"karma-mocha": "^1.2.0",
|
||||||
|
"karma-mocha-reporter": "^2.2.1",
|
||||||
"karma-sinon-chai": "^2.0.2",
|
"karma-sinon-chai": "^2.0.2",
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-spec-reporter": "0.0.26",
|
"karma-spec-reporter": "0.0.26",
|
||||||
|
@ -101,6 +102,9 @@
|
||||||
"shelljs": "^0.7.4",
|
"shelljs": "^0.7.4",
|
||||||
"sinon": "^2.1.0",
|
"sinon": "^2.1.0",
|
||||||
"sinon-chai": "^2.8.0",
|
"sinon-chai": "^2.8.0",
|
||||||
|
"stylelint": "^13.6.1",
|
||||||
|
"stylelint-config-standard": "^20.0.0",
|
||||||
|
"stylelint-rscss": "^0.4.0",
|
||||||
"url-loader": "^1.1.2",
|
"url-loader": "^1.1.2",
|
||||||
"vue-loader": "^14.0.0",
|
"vue-loader": "^14.0.0",
|
||||||
"vue-style-loader": "^4.0.0",
|
"vue-style-loader": "^4.0.0",
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
|
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-body {
|
.StatusContent {
|
||||||
img.emoji {
|
img.emoji {
|
||||||
width: 1.4em;
|
width: 1.4em;
|
||||||
height: 1.4em;
|
height: 1.4em;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="timeline panel-default"
|
class="Conversation"
|
||||||
:class="[isExpanded ? 'panel' : 'panel-disabled']"
|
:class="{ '-expanded' : isExpanded, 'panel' : isExpanded }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="isExpanded"
|
v-if="isExpanded"
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
:replies="getReplies(status.id)"
|
:replies="getReplies(status.id)"
|
||||||
:in-profile="inProfile"
|
:in-profile="inProfile"
|
||||||
:profile-user-id="profileUserId"
|
:profile-user-id="profileUserId"
|
||||||
class="status-fadein panel-body"
|
class="conversation-status status-fadein panel-body"
|
||||||
@goto="setHighlight"
|
@goto="setHighlight"
|
||||||
@toggleExpanded="toggleExpanded"
|
@toggleExpanded="toggleExpanded"
|
||||||
/>
|
/>
|
||||||
|
@ -40,14 +40,27 @@
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.timeline {
|
.Conversation {
|
||||||
.panel-disabled {
|
.conversation-status {
|
||||||
.status-el {
|
border-left: none;
|
||||||
border-left: none;
|
border-bottom-width: 1px;
|
||||||
border-bottom-width: 1px;
|
border-bottom-style: solid;
|
||||||
border-bottom-style: solid;
|
border-bottom-color: var(--border, $fallback--border);
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.-expanded {
|
||||||
|
.conversation-status {
|
||||||
|
border-color: $fallback--border;
|
||||||
border-color: var(--border, $fallback--border);
|
border-color: var(--border, $fallback--border);
|
||||||
border-radius: 0;
|
border-left: 4px solid $fallback--cRed;
|
||||||
|
border-left: 4px solid var(--cRed, $fallback--cRed);
|
||||||
|
}
|
||||||
|
|
||||||
|
.conversation-status:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
|
||||||
|
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { timelineNames } from '../timeline_menu/timeline_menu.js'
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from 'vuex'
|
||||||
|
|
||||||
const NavPanel = {
|
const NavPanel = {
|
||||||
|
@ -7,9 +8,17 @@ const NavPanel = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
onTimelineRoute () {
|
||||||
|
return !!timelineNames()[this.$route.name]
|
||||||
|
},
|
||||||
|
timelinesRoute () {
|
||||||
|
if (this.$store.state.interface.lastTimeline) {
|
||||||
|
return this.$store.state.interface.lastTimeline
|
||||||
|
}
|
||||||
|
return this.currentUser ? 'friends' : 'public-timeline'
|
||||||
|
},
|
||||||
...mapState({
|
...mapState({
|
||||||
currentUser: state => state.users.currentUser,
|
currentUser: state => state.users.currentUser,
|
||||||
chat: state => state.chat.channel,
|
|
||||||
followRequestCount: state => state.api.followRequests.length,
|
followRequestCount: state => state.api.followRequests.length,
|
||||||
privateMode: state => state.instance.private,
|
privateMode: state => state.instance.private,
|
||||||
federating: state => state.instance.federating,
|
federating: state => state.instance.federating,
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
<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 || !privateMode">
|
||||||
<router-link :to="{ name: 'friends' }">
|
<router-link
|
||||||
<i class="button-icon icon-home-2" /> {{ $t("nav.timeline") }}
|
:to="{ name: timelinesRoute }"
|
||||||
|
:class="onTimelineRoute && 'router-link-active'"
|
||||||
|
>
|
||||||
|
<i class="button-icon icon-home-2" /> {{ $t("nav.timelines") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="currentUser">
|
<li v-if="currentUser">
|
||||||
|
@ -12,16 +15,6 @@
|
||||||
<i class="button-icon icon-bell-alt" /> {{ $t("nav.interactions") }}
|
<i class="button-icon icon-bell-alt" /> {{ $t("nav.interactions") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="currentUser">
|
|
||||||
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
|
||||||
<i class="button-icon icon-mail-alt" /> {{ $t("nav.dms") }}
|
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
<li v-if="currentUser">
|
|
||||||
<router-link :to="{ name: 'bookmarks'}">
|
|
||||||
<i class="button-icon icon-bookmark" /> {{ $t("nav.bookmarks") }}
|
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
<li v-if="currentUser && pleromaChatMessagesAvailable">
|
<li v-if="currentUser && pleromaChatMessagesAvailable">
|
||||||
<router-link :to="{ name: 'chats', params: { username: currentUser.screen_name } }">
|
<router-link :to="{ name: 'chats', params: { username: currentUser.screen_name } }">
|
||||||
<div
|
<div
|
||||||
|
@ -44,16 +37,6 @@
|
||||||
</span>
|
</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="currentUser || !privateMode">
|
|
||||||
<router-link :to="{ name: 'public-timeline' }">
|
|
||||||
<i class="button-icon icon-users" /> {{ $t("nav.public_tl") }}
|
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
<li v-if="federating && (currentUser || !privateMode)">
|
|
||||||
<router-link :to="{ name: 'public-external-timeline' }">
|
|
||||||
<i class="button-icon icon-globe" /> {{ $t("nav.twkn") }}
|
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<router-link :to="{ name: 'about' }">
|
<router-link :to="{ name: 'about' }">
|
||||||
<i class="button-icon icon-info-circled" /> {{ $t("nav.about") }}
|
<i class="button-icon icon-info-circled" /> {{ $t("nav.about") }}
|
||||||
|
|
|
@ -60,16 +60,8 @@
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-body {
|
--link: var(--faintLink);
|
||||||
color: $fallback--faint;
|
--text: var(--faint);
|
||||||
color: var(--faint, $fallback--faint);
|
|
||||||
a {
|
|
||||||
color: var(--faintLink);
|
|
||||||
}
|
|
||||||
.status-content a {
|
|
||||||
color: var(--postFaintLink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.follow-request-accept {
|
.follow-request-accept {
|
||||||
|
@ -106,7 +98,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-el {
|
/* TODO cleanup this */
|
||||||
|
.Status {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<span class="result-percentage">
|
<span class="result-percentage">
|
||||||
{{ percentageForOption(option.votes_count) }}%
|
{{ percentageForOption(option.votes_count) }}%
|
||||||
</span>
|
</span>
|
||||||
<span v-html="option.title_html"></span>
|
<span v-html="option.title_html" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="result-fill"
|
class="result-fill"
|
||||||
|
|
|
@ -18,7 +18,9 @@ const Popover = {
|
||||||
// Takes a x/y object and tells how many pixels to offset from
|
// Takes a x/y object and tells how many pixels to offset from
|
||||||
// anchor point on either axis
|
// anchor point on either axis
|
||||||
offset: Object,
|
offset: Object,
|
||||||
// Additional styles you may want for the popover container
|
// Replaces the classes you may want for the popover container.
|
||||||
|
// Use 'popover-default' in addition to get the default popover
|
||||||
|
// styles with your custom class.
|
||||||
popoverClass: String
|
popoverClass: String
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
|
@ -106,7 +108,7 @@ const Popover = {
|
||||||
// single translate or translate3d resulted in blurry text.
|
// single translate or translate3d resulted in blurry text.
|
||||||
this.styles = {
|
this.styles = {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
transform: `translateX(${Math.floor(translateX)}px) translateY(${Math.floor(translateY)}px)`
|
transform: `translateX(${Math.round(translateX)}px) translateY(${Math.round(translateY)}px)`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showPopover () {
|
showPopover () {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
ref="content"
|
ref="content"
|
||||||
:style="styles"
|
:style="styles"
|
||||||
class="popover"
|
class="popover"
|
||||||
:class="popoverClass"
|
:class="popoverClass || 'popover-default'"
|
||||||
>
|
>
|
||||||
<slot
|
<slot
|
||||||
name="content"
|
name="content"
|
||||||
|
@ -34,6 +34,9 @@
|
||||||
z-index: 8;
|
z-index: 8;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-default {
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
|
|
||||||
box-shadow: 1px 1px 4px rgba(0,0,0,.6);
|
box-shadow: 1px 1px 4px rgba(0,0,0,.6);
|
||||||
|
|
|
@ -13,6 +13,13 @@
|
||||||
* - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible
|
* - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible
|
||||||
*/
|
*/
|
||||||
transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px));
|
transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px));
|
||||||
|
|
||||||
|
@media all and (max-width: 800px) {
|
||||||
|
/* For mobile, the modal takes 100% of the available screen.
|
||||||
|
This ensures the minimized modal is always 50px above the browser bottom bar regardless of whether or not it is visible.
|
||||||
|
*/
|
||||||
|
transform: translateY(calc(100% - 50px));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +34,7 @@
|
||||||
|
|
||||||
@media all and (max-width: 800px) {
|
@media all and (max-width: 800px) {
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
height: 100vh;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
>.panel-body {
|
>.panel-body {
|
||||||
|
|
|
@ -49,6 +49,12 @@ const SideDrawer = {
|
||||||
federating () {
|
federating () {
|
||||||
return this.$store.state.instance.federating
|
return this.$store.state.instance.federating
|
||||||
},
|
},
|
||||||
|
timelinesRoute () {
|
||||||
|
if (this.$store.state.interface.lastTimeline) {
|
||||||
|
return this.$store.state.interface.lastTimeline
|
||||||
|
}
|
||||||
|
return this.currentUser ? 'friends' : 'public-timeline'
|
||||||
|
},
|
||||||
...mapState({
|
...mapState({
|
||||||
pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable
|
pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -39,13 +39,18 @@
|
||||||
<i class="button-icon icon-login" /> {{ $t("login.login") }}
|
<i class="button-icon icon-login" /> {{ $t("login.login") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
|
<li
|
||||||
|
v-if="currentUser || !privateMode"
|
||||||
|
@click="toggleDrawer"
|
||||||
|
>
|
||||||
|
<router-link :to="{ name: timelinesRoute }">
|
||||||
|
<i class="button-icon icon-home-2" /> {{ $t("nav.timelines") }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="currentUser && pleromaChatMessagesAvailable"
|
v-if="currentUser && pleromaChatMessagesAvailable"
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
|
||||||
<i class="button-icon icon-mail-alt" /> {{ $t("nav.dms") }}
|
|
||||||
</router-link>
|
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: 'chats', params: { username: currentUser.screen_name } }"
|
:to="{ name: 'chats', params: { username: currentUser.screen_name } }"
|
||||||
style="position: relative"
|
style="position: relative"
|
||||||
|
@ -59,34 +64,15 @@
|
||||||
</span>
|
</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
</ul>
|
||||||
v-if="currentUser"
|
<ul v-if="currentUser">
|
||||||
@click="toggleDrawer"
|
<li @click="toggleDrawer">
|
||||||
>
|
|
||||||
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
|
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
|
||||||
<i class="button-icon icon-bell-alt" /> {{ $t("nav.interactions") }}
|
<i class="button-icon icon-bell-alt" /> {{ $t("nav.interactions") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
|
||||||
<ul>
|
|
||||||
<li
|
<li
|
||||||
v-if="currentUser"
|
v-if="currentUser.locked"
|
||||||
@click="toggleDrawer"
|
|
||||||
>
|
|
||||||
<router-link :to="{ name: 'friends' }">
|
|
||||||
<i class="button-icon icon-home-2" /> {{ $t("nav.timeline") }}
|
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
v-if="currentUser"
|
|
||||||
@click="toggleDrawer"
|
|
||||||
>
|
|
||||||
<router-link :to="{ name: 'bookmarks'}">
|
|
||||||
<i class="button-icon icon-bookmark" /> {{ $t("nav.bookmarks") }}
|
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
v-if="currentUser && currentUser.locked"
|
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link to="/friend-requests">
|
<router-link to="/friend-requests">
|
||||||
|
@ -100,19 +86,11 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="currentUser || !privateMode"
|
v-if="chat"
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link to="/main/public">
|
<router-link :to="{ name: 'chat' }">
|
||||||
<i class="button-icon icon-users" /> {{ $t("nav.public_tl") }}
|
<i class="button-icon icon-chat" /> {{ $t("nav.chat") }}
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
v-if="federating && (currentUser || !privateMode)"
|
|
||||||
@click="toggleDrawer"
|
|
||||||
>
|
|
||||||
<router-link to="/main/all">
|
|
||||||
<i class="button-icon icon-globe" /> {{ $t("nav.twkn") }}
|
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
400
src/components/status/status.scss
Normal file
400
src/components/status/status.scss
Normal file
|
@ -0,0 +1,400 @@
|
||||||
|
|
||||||
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
|
$status-margin: 0.75em;
|
||||||
|
|
||||||
|
.Status {
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
&:hover .avatar {
|
||||||
|
--still-image-img: visible;
|
||||||
|
--still-image-canvas: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.-focused {
|
||||||
|
background-color: $fallback--lightBg;
|
||||||
|
background-color: var(--selectedPost, $fallback--lightBg);
|
||||||
|
color: $fallback--text;
|
||||||
|
color: var(--selectedPostText, $fallback--text);
|
||||||
|
|
||||||
|
--lightText: var(--selectedPostLightText, $fallback--light);
|
||||||
|
--faint: var(--selectedPostFaintText, $fallback--faint);
|
||||||
|
--faintLink: var(--selectedPostFaintLink, $fallback--faint);
|
||||||
|
--postLink: var(--selectedPostPostLink, $fallback--faint);
|
||||||
|
--postFaintLink: var(--selectedPostFaintPostLink, $fallback--faint);
|
||||||
|
--icon: var(--selectedPostIcon, $fallback--icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-container {
|
||||||
|
display: flex;
|
||||||
|
padding: $status-margin;
|
||||||
|
|
||||||
|
&.-repeat {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pin {
|
||||||
|
padding: $status-margin $status-margin 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-side {
|
||||||
|
margin-right: $status-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-side {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usercard {
|
||||||
|
margin-bottom: $status-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-username {
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 14px;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 85%;
|
||||||
|
font-weight: bold;
|
||||||
|
flex-shrink: 1;
|
||||||
|
margin-right: 0.4em;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
vertical-align: middle;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-favicon {
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
margin-right: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-heading {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-name-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
line-height: 18px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-name {
|
||||||
|
min-width: 1.6em;
|
||||||
|
margin-right: 0.4em;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-left {
|
||||||
|
display: flex;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-right {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeago {
|
||||||
|
margin-right: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-reply-row {
|
||||||
|
position: relative;
|
||||||
|
align-content: baseline;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
max-width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-to-and-accountname {
|
||||||
|
display: flex;
|
||||||
|
height: 18px;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
.icon-reply {
|
||||||
|
// mirror the icon
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .reply-to-popover,
|
||||||
|
& .reply-to-no-popover {
|
||||||
|
min-width: 0;
|
||||||
|
margin-right: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-to-popover {
|
||||||
|
&:hover {
|
||||||
|
border-bottom: 1px solid var(--faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faint-link:hover {
|
||||||
|
// override default
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.-strikethrough {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid var(--faint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-to {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-to-text {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.replies-separator {
|
||||||
|
margin-left: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.replies {
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
margin-right: 0.4em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-link {
|
||||||
|
height: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repeat-info {
|
||||||
|
padding: 0.4em $status-margin;
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
|
.right-side {
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
padding: 0 0.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.repeater-avatar {
|
||||||
|
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
|
||||||
|
margin-left: 28px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repeater-name {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-right: 0;
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
vertical-align: middle;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-fadein {
|
||||||
|
animation-duration: 0.4s;
|
||||||
|
animation-name: fadein;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadein {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-actions {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
margin-top: $status-margin;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
max-width: 4em;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-reply {
|
||||||
|
&:not(.-disabled) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.-disabled):hover,
|
||||||
|
&.-active {
|
||||||
|
color: $fallback--cBlue;
|
||||||
|
color: var(--cBlue, $fallback--cBlue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted {
|
||||||
|
padding: 0.25em 0.6em;
|
||||||
|
height: 1.2em;
|
||||||
|
line-height: 1.2em;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
|
||||||
|
& .status-username,
|
||||||
|
& .mute-thread,
|
||||||
|
& .mute-words {
|
||||||
|
word-wrap: normal;
|
||||||
|
word-break: normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .status-username,
|
||||||
|
& .mute-words {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-username {
|
||||||
|
font-weight: normal;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
margin-right: 0.2em;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mute-thread {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mute-words {
|
||||||
|
flex: 1 0 5em;
|
||||||
|
margin-left: 0.2em;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unmute {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-left: auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-form {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-body {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.favs-repeated-users {
|
||||||
|
margin-top: $status-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-row {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 1px;
|
||||||
|
left: 0;
|
||||||
|
background-color: var(--faint, $fallback--faint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-count {
|
||||||
|
margin-right: $status-margin;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.stat-title {
|
||||||
|
color: var(--faint, $fallback--faint);
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-number {
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .stat-title {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (max-width: 800px) {
|
||||||
|
.repeater-avatar {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar:not(.repeater-avatar) {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
// TODO define those other way somehow?
|
||||||
|
// stylelint-disable rscss/class-format
|
||||||
|
&.avatar-compact {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,8 @@
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div
|
<div
|
||||||
v-if="!hideStatus"
|
v-if="!hideStatus"
|
||||||
class="status-el"
|
class="Status"
|
||||||
:class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"
|
:class="[{ '-focused': isFocused }, { '-conversation': inlineExpanded }]"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="error"
|
v-if="error"
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="muted && !isPreview">
|
<template v-if="muted && !isPreview">
|
||||||
<div class="media status container muted">
|
<div class="status-csontainer muted">
|
||||||
<small class="username">
|
<small class="status-username">
|
||||||
<i
|
<i
|
||||||
v-if="muted && retweet"
|
v-if="muted && retweet"
|
||||||
class="button-icon icon-retweet"
|
class="button-icon icon-retweet"
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div
|
<div
|
||||||
v-if="showPinned"
|
v-if="showPinned"
|
||||||
class="status-pin"
|
class="pin"
|
||||||
>
|
>
|
||||||
<i class="fa icon-pin faint" />
|
<i class="fa icon-pin faint" />
|
||||||
<span class="faint">{{ $t('status.pinned') }}</span>
|
<span class="faint">{{ $t('status.pinned') }}</span>
|
||||||
|
@ -63,17 +63,17 @@
|
||||||
v-if="retweet && !noHeading && !inConversation"
|
v-if="retweet && !noHeading && !inConversation"
|
||||||
:class="[repeaterClass, { highlighted: repeaterStyle }]"
|
:class="[repeaterClass, { highlighted: repeaterStyle }]"
|
||||||
:style="[repeaterStyle]"
|
:style="[repeaterStyle]"
|
||||||
class="media container retweet-info"
|
class="status-container repeat-info"
|
||||||
>
|
>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
v-if="retweet"
|
v-if="retweet"
|
||||||
class="media-left"
|
class="left-side repeater-avatar"
|
||||||
:better-shadow="betterShadow"
|
:better-shadow="betterShadow"
|
||||||
:user="statusoid.user"
|
:user="statusoid.user"
|
||||||
/>
|
/>
|
||||||
<div class="media-body faint">
|
<div class="right-side faint">
|
||||||
<span
|
<span
|
||||||
class="user-name"
|
class="status-username repeater-name"
|
||||||
:title="retweeter"
|
:title="retweeter"
|
||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
|
@ -95,14 +95,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
:class="[userClass, { highlighted: userStyle, 'is-retweet': retweet && !inConversation }]"
|
:class="[userClass, { highlighted: userStyle, '-repeat': retweet && !inConversation }]"
|
||||||
:style="[ userStyle ]"
|
:style="[ userStyle ]"
|
||||||
class="media status"
|
class="status-container"
|
||||||
:data-tags="tags"
|
:data-tags="tags"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="!noHeading"
|
v-if="!noHeading"
|
||||||
class="media-left"
|
class="left-side"
|
||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
:to="userProfileLink"
|
:to="userProfileLink"
|
||||||
|
@ -115,29 +115,29 @@
|
||||||
/>
|
/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-body">
|
<div class="right-side">
|
||||||
<UserCard
|
<UserCard
|
||||||
v-if="userExpanded"
|
v-if="userExpanded"
|
||||||
:user-id="status.user.id"
|
:user-id="status.user.id"
|
||||||
:rounded="true"
|
:rounded="true"
|
||||||
:bordered="true"
|
:bordered="true"
|
||||||
class="status-usercard"
|
class="usercard"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="!noHeading"
|
v-if="!noHeading"
|
||||||
class="media-heading"
|
class="status-heading"
|
||||||
>
|
>
|
||||||
<div class="heading-name-row">
|
<div class="heading-name-row">
|
||||||
<div class="name-and-account-name">
|
<div class="heading-left">
|
||||||
<h4
|
<h4
|
||||||
v-if="status.user.name_html"
|
v-if="status.user.name_html"
|
||||||
class="user-name"
|
class="status-username"
|
||||||
:title="status.user.name"
|
:title="status.user.name"
|
||||||
v-html="status.user.name_html"
|
v-html="status.user.name_html"
|
||||||
/>
|
/>
|
||||||
<h4
|
<h4
|
||||||
v-else
|
v-else
|
||||||
class="user-name"
|
class="status-username"
|
||||||
:title="status.user.name"
|
:title="status.user.name"
|
||||||
>
|
>
|
||||||
{{ status.user.name }}
|
{{ status.user.name }}
|
||||||
|
@ -150,8 +150,8 @@
|
||||||
{{ status.user.screen_name }}
|
{{ status.user.screen_name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<img
|
<img
|
||||||
class="status-favicon"
|
|
||||||
v-if="!!(status.user && status.user.favicon)"
|
v-if="!!(status.user && status.user.favicon)"
|
||||||
|
class="status-favicon"
|
||||||
:src="status.user.favicon"
|
:src="status.user.favicon"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -211,6 +211,7 @@
|
||||||
:status-id="status.parent_visible && status.in_reply_to_status_id"
|
:status-id="status.parent_visible && status.in_reply_to_status_id"
|
||||||
class="reply-to-popover"
|
class="reply-to-popover"
|
||||||
style="min-width: 0"
|
style="min-width: 0"
|
||||||
|
:class="{ '-strikethrough': !status.parent_visible }"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="reply-to"
|
class="reply-to"
|
||||||
|
@ -218,10 +219,9 @@
|
||||||
:aria-label="$t('tool_tip.reply')"
|
:aria-label="$t('tool_tip.reply')"
|
||||||
@click.prevent="gotoOriginal(status.in_reply_to_status_id)"
|
@click.prevent="gotoOriginal(status.in_reply_to_status_id)"
|
||||||
>
|
>
|
||||||
<i class="button-icon icon-reply" />
|
<i class="button-icon reply-button icon-reply" />
|
||||||
<span
|
<span
|
||||||
class="faint-link reply-to-text"
|
class="faint-link reply-to-text"
|
||||||
:class="{ 'strikethrough': !status.parent_visible }"
|
|
||||||
>
|
>
|
||||||
{{ $t('status.reply_to') }}
|
{{ $t('status.reply_to') }}
|
||||||
</span>
|
</span>
|
||||||
|
@ -229,7 +229,7 @@
|
||||||
</StatusPopover>
|
</StatusPopover>
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
class="reply-to"
|
class="reply-to-no-popover"
|
||||||
>
|
>
|
||||||
<span class="reply-to-text">{{ $t('status.reply_to') }}</span>
|
<span class="reply-to-text">{{ $t('status.reply_to') }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -317,19 +317,19 @@
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="!noHeading && !isPreview"
|
v-if="!noHeading && !isPreview"
|
||||||
class="status-actions media-body"
|
class="status-actions"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<i
|
<i
|
||||||
v-if="loggedIn"
|
v-if="loggedIn"
|
||||||
class="button-icon icon-reply"
|
class="button-icon button-reply icon-reply"
|
||||||
:title="$t('tool_tip.reply')"
|
:title="$t('tool_tip.reply')"
|
||||||
:class="{'button-icon-active': replying}"
|
:class="{'-active': replying}"
|
||||||
@click.prevent="toggleReplying"
|
@click.prevent="toggleReplying"
|
||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
v-else
|
v-else
|
||||||
class="button-icon button-icon-disabled icon-reply"
|
class="button-icon button-reply -disabled icon-reply"
|
||||||
:title="$t('tool_tip.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>
|
||||||
|
@ -357,7 +357,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="replying"
|
v-if="replying"
|
||||||
class="container"
|
class="status-container reply-form"
|
||||||
>
|
>
|
||||||
<PostStatusForm
|
<PostStatusForm
|
||||||
class="reply-body"
|
class="reply-body"
|
||||||
|
@ -375,439 +375,4 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./status.js" ></script>
|
<script src="./status.js" ></script>
|
||||||
<style lang="scss">
|
<style src="./status.scss" lang="scss"></style>
|
||||||
@import '../../_variables.scss';
|
|
||||||
|
|
||||||
$status-margin: 0.75em;
|
|
||||||
|
|
||||||
.status-body {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-pin {
|
|
||||||
padding: $status-margin $status-margin 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-left {
|
|
||||||
margin-right: $status-margin;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-el {
|
|
||||||
border-left-width: 0px;
|
|
||||||
min-width: 0;
|
|
||||||
border-color: $fallback--border;
|
|
||||||
border-color: var(--border, $fallback--border);
|
|
||||||
|
|
||||||
border-left: 4px $fallback--cRed;
|
|
||||||
border-left: 4px var(--cRed, $fallback--cRed);
|
|
||||||
|
|
||||||
&_focused {
|
|
||||||
background-color: $fallback--lightBg;
|
|
||||||
background-color: var(--selectedPost, $fallback--lightBg);
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--selectedPostText, $fallback--text);
|
|
||||||
--lightText: var(--selectedPostLightText, $fallback--light);
|
|
||||||
--faint: var(--selectedPostFaintText, $fallback--faint);
|
|
||||||
--faintLink: var(--selectedPostFaintLink, $fallback--faint);
|
|
||||||
--postLink: var(--selectedPostPostLink, $fallback--faint);
|
|
||||||
--postFaintLink: var(--selectedPostFaintPostLink, $fallback--faint);
|
|
||||||
--icon: var(--selectedPostIcon, $fallback--icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
.timeline & {
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
border-bottom-style: solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-body {
|
|
||||||
flex: 1;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-usercard {
|
|
||||||
margin-bottom: $status-margin;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-name {
|
|
||||||
white-space: nowrap;
|
|
||||||
font-size: 14px;
|
|
||||||
overflow: hidden;
|
|
||||||
flex-shrink: 0;
|
|
||||||
max-width: 85%;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
img.emoji {
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
vertical-align: middle;
|
|
||||||
object-fit: contain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-favicon {
|
|
||||||
height: 18px;
|
|
||||||
width: 18px;
|
|
||||||
margin-right: 0.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-heading {
|
|
||||||
padding: 0;
|
|
||||||
vertical-align: bottom;
|
|
||||||
flex-basis: 100%;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-weight: lighter;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heading-name-row {
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
line-height: 18px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
display: inline-block;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name-and-account-name {
|
|
||||||
display: flex;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-name {
|
|
||||||
flex-shrink: 1;
|
|
||||||
margin-right: 0.4em;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-name {
|
|
||||||
min-width: 1.6em;
|
|
||||||
margin-right: 0.4em;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
flex: 1 1 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.heading-right {
|
|
||||||
display: flex;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timeago {
|
|
||||||
margin-right: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heading-reply-row {
|
|
||||||
position: relative;
|
|
||||||
align-content: baseline;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 18px;
|
|
||||||
max-width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: stretch;
|
|
||||||
|
|
||||||
> .reply-to-and-accountname > a {
|
|
||||||
overflow: hidden;
|
|
||||||
max-width: 100%;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.reply-to-and-accountname {
|
|
||||||
display: flex;
|
|
||||||
height: 18px;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
max-width: 100%;
|
|
||||||
.icon-reply {
|
|
||||||
transform: scaleX(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.reply-info {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reply-to-popover {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reply-to {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reply-to-text {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin: 0 0.4em 0 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.strikethrough {
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
.replies-separator {
|
|
||||||
margin-left: 0.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.replies {
|
|
||||||
line-height: 18px;
|
|
||||||
font-size: 12px;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
& > * {
|
|
||||||
margin-right: 0.4em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.reply-link {
|
|
||||||
height: 17px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.retweet-info {
|
|
||||||
padding: 0.4em $status-margin;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
.avatar.still-image {
|
|
||||||
border-radius: $fallback--avatarAltRadius;
|
|
||||||
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
|
|
||||||
margin-left: 28px;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-body {
|
|
||||||
font-size: 1em;
|
|
||||||
line-height: 22px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-content: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
.user-name {
|
|
||||||
font-weight: bold;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
vertical-align: middle;
|
|
||||||
object-fit: contain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
padding: 0 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-fadein {
|
|
||||||
animation-duration: 0.4s;
|
|
||||||
animation-name: fadein;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadein {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-conversation {
|
|
||||||
border-left-style: solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-actions {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
margin-top: $status-margin;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
max-width: 4em;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-icon.icon-reply {
|
|
||||||
&:not(.button-icon-disabled):hover,
|
|
||||||
&.button-icon-active {
|
|
||||||
color: $fallback--cBlue;
|
|
||||||
color: var(--cBlue, $fallback--cBlue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-icon.icon-reply {
|
|
||||||
&:not(.button-icon-disabled) {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status:hover .animated.avatar {
|
|
||||||
canvas {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
display: flex;
|
|
||||||
padding: $status-margin;
|
|
||||||
&.is-retweet {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-conversation:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.muted {
|
|
||||||
padding: .25em .6em;
|
|
||||||
height: 1.2em;
|
|
||||||
line-height: 1.2em;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
|
|
||||||
.username, .mute-thread, .mute-words {
|
|
||||||
word-wrap: normal;
|
|
||||||
word-break: normal;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.username, .mute-words {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.username {
|
|
||||||
flex: 0 1 auto;
|
|
||||||
margin-right: .2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mute-thread {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mute-words {
|
|
||||||
flex: 1 0 5em;
|
|
||||||
margin-left: .2em;
|
|
||||||
&::before {
|
|
||||||
content: ' '
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.unmute {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-left: auto;
|
|
||||||
display: block;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.reply-body {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favs-repeated-users {
|
|
||||||
margin-top: $status-margin;
|
|
||||||
|
|
||||||
.stats {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
line-height: 1em;
|
|
||||||
|
|
||||||
.stat-count {
|
|
||||||
margin-right: $status-margin;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
&:hover .stat-title {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stat-title {
|
|
||||||
color: var(--faint, $fallback--faint);
|
|
||||||
font-size: 12px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stat-number {
|
|
||||||
font-weight: bolder;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-row {
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
width: 1px;
|
|
||||||
left: 0;
|
|
||||||
background-color: var(--faint, $fallback--faint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media all and (max-width: 800px) {
|
|
||||||
.status-el {
|
|
||||||
.retweet-info {
|
|
||||||
.avatar.still-image {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.status {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status .avatar.still-image {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
|
|
||||||
&.avatar-compact {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div class="status-body">
|
<div class="StatusContent">
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
<div
|
<div
|
||||||
v-if="status.summary_html"
|
v-if="status.summary_html"
|
||||||
|
@ -133,7 +133,7 @@
|
||||||
|
|
||||||
$status-margin: 0.75em;
|
$status-margin: 0.75em;
|
||||||
|
|
||||||
.status-body {
|
.StatusContent {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
|
@ -275,6 +275,7 @@ $status-margin: 0.75em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
height: 1.4em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,13 +284,4 @@ $status-margin: 0.75em;
|
||||||
color: $fallback--cGreen;
|
color: $fallback--cGreen;
|
||||||
color: var(--postGreentext, $fallback--cGreen);
|
color: var(--postGreentext, $fallback--cGreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline :not(.panel-disabled) > {
|
|
||||||
.status-el:last-child {
|
|
||||||
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
|
|
||||||
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Popover
|
<Popover
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
popover-class="status-popover"
|
popover-class="popover-default status-popover"
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
@show="enter"
|
@show="enter"
|
||||||
>
|
>
|
||||||
|
@ -52,7 +52,8 @@
|
||||||
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
|
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
|
||||||
box-shadow: var(--popupShadow);
|
box-shadow: var(--popupShadow);
|
||||||
|
|
||||||
.status-el.status-el {
|
/* TODO cleanup this */
|
||||||
|
.Status.Status {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,43 +35,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&:hover canvas {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.animated {
|
|
||||||
&:hover::before,
|
|
||||||
img {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover img {
|
|
||||||
visibility: visible
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: 'gif';
|
|
||||||
position: absolute;
|
|
||||||
line-height: 10px;
|
|
||||||
font-size: 10px;
|
|
||||||
top: 5px;
|
|
||||||
left: 5px;
|
|
||||||
background: rgba(127,127,127,.5);
|
|
||||||
color: #FFF;
|
|
||||||
display: block;
|
|
||||||
padding: 2px 4px;
|
|
||||||
border-radius: $fallback--tooltipRadius;
|
|
||||||
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -81,6 +44,44 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
|
visibility: var(--still-image-canvas, visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.animated {
|
||||||
|
&::before {
|
||||||
|
content: 'gif';
|
||||||
|
position: absolute;
|
||||||
|
line-height: 10px;
|
||||||
|
font-size: 10px;
|
||||||
|
top: 5px;
|
||||||
|
left: 5px;
|
||||||
|
background: rgba(127, 127, 127, 0.5);
|
||||||
|
color: #fff;
|
||||||
|
display: block;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: $fallback--tooltipRadius;
|
||||||
|
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover canvas {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover::before,
|
||||||
|
img {
|
||||||
|
visibility: var(--still-image-img, hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover img {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
import './tab_switcher.scss'
|
import './tab_switcher.scss'
|
||||||
|
|
||||||
|
@ -44,7 +45,13 @@ export default Vue.component('tab-switcher', {
|
||||||
} else {
|
} else {
|
||||||
return this.active
|
return this.active
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
settingsModalVisible () {
|
||||||
|
return this.settingsModalState === 'visible'
|
||||||
|
},
|
||||||
|
...mapState({
|
||||||
|
settingsModalState: state => state.interface.settingsModalState
|
||||||
|
})
|
||||||
},
|
},
|
||||||
beforeUpdate () {
|
beforeUpdate () {
|
||||||
const currentSlot = this.$slots.default[this.active]
|
const currentSlot = this.$slots.default[this.active]
|
||||||
|
@ -134,7 +141,7 @@ export default Vue.component('tab-switcher', {
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
{tabs}
|
{tabs}
|
||||||
</div>
|
</div>
|
||||||
<div ref="contents" class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}>
|
<div ref="contents" class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')} v-body-scroll-lock={this.settingsModalVisible}>
|
||||||
{contents}
|
{contents}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Status from '../status/status.vue'
|
import Status from '../status/status.vue'
|
||||||
import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
|
import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
|
||||||
import Conversation from '../conversation/conversation.vue'
|
import Conversation from '../conversation/conversation.vue'
|
||||||
|
import TimelineMenu from '../timeline_menu/timeline_menu.vue'
|
||||||
import { throttle, keyBy } from 'lodash'
|
import { throttle, keyBy } from 'lodash'
|
||||||
|
|
||||||
export const getExcludedStatusIdsByPinning = (statuses, pinnedStatusIds) => {
|
export const getExcludedStatusIdsByPinning = (statuses, pinnedStatusIds) => {
|
||||||
|
@ -35,6 +36,11 @@ const Timeline = {
|
||||||
bottomedOut: false
|
bottomedOut: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
Status,
|
||||||
|
Conversation,
|
||||||
|
TimelineMenu
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
timelineError () {
|
timelineError () {
|
||||||
return this.$store.state.statuses.error
|
return this.$store.state.statuses.error
|
||||||
|
@ -74,10 +80,6 @@ const Timeline = {
|
||||||
return keyBy(this.pinnedStatusIds)
|
return keyBy(this.pinnedStatusIds)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
|
||||||
Status,
|
|
||||||
Conversation
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
const store = this.$store
|
const store = this.$store
|
||||||
const credentials = store.state.users.currentUser.credentials
|
const credentials = store.state.users.currentUser.credentials
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="classes.root">
|
<div :class="[classes.root, 'timeline']">
|
||||||
<div :class="classes.header">
|
<div :class="classes.header">
|
||||||
<div class="title">
|
<TimelineMenu v-if="!embedded" />
|
||||||
{{ title }}
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
v-if="timelineError"
|
v-if="timelineError"
|
||||||
class="loadmore-error alert error"
|
class="loadmore-error alert error"
|
||||||
|
@ -106,4 +104,16 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timeline-heading {
|
||||||
|
max-width: 100%;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
.loadmore-button {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.loadmore-text {
|
||||||
|
flex-shrink: 0;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
57
src/components/timeline_menu/timeline_menu.js
Normal file
57
src/components/timeline_menu/timeline_menu.js
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import Popover from '../popover/popover.vue'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
// Route -> i18n key mapping, exported andnot in the computed
|
||||||
|
// because nav panel benefits from the same information.
|
||||||
|
export const timelineNames = () => {
|
||||||
|
return {
|
||||||
|
'friends': 'nav.timeline',
|
||||||
|
'bookmarks': 'nav.bookmarks',
|
||||||
|
'dms': 'nav.dms',
|
||||||
|
'public-timeline': 'nav.public_tl',
|
||||||
|
'public-external-timeline': 'nav.twkn'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const TimelineMenu = {
|
||||||
|
components: {
|
||||||
|
Popover
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isOpen: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
if (this.currentUser && this.currentUser.locked) {
|
||||||
|
this.$store.dispatch('startFetchingFollowRequests')
|
||||||
|
}
|
||||||
|
if (timelineNames()[this.$route.name]) {
|
||||||
|
this.$store.dispatch('setLastTimeline', this.$route.name)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openMenu () {
|
||||||
|
// $nextTick is too fast, animation won't play back but
|
||||||
|
// instead starts in fully open position. Low values
|
||||||
|
// like 1-5 work on fast machines but not on mobile, 25
|
||||||
|
// seems like a good compromise that plays without significant
|
||||||
|
// added lag.
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isOpen = true
|
||||||
|
}, 25)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
currentUser: state => state.users.currentUser,
|
||||||
|
privateMode: state => state.instance.private,
|
||||||
|
federating: state => state.instance.federating
|
||||||
|
}),
|
||||||
|
timelineNames () {
|
||||||
|
return timelineNames()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TimelineMenu
|
180
src/components/timeline_menu/timeline_menu.vue
Normal file
180
src/components/timeline_menu/timeline_menu.vue
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
<template>
|
||||||
|
<Popover
|
||||||
|
trigger="click"
|
||||||
|
class="timeline-menu"
|
||||||
|
:class="{ 'open': isOpen }"
|
||||||
|
:margin="{ left: -15, right: -200 }"
|
||||||
|
:bound-to="{ x: 'container' }"
|
||||||
|
popover-class="timeline-menu-popover-wrap"
|
||||||
|
@show="openMenu"
|
||||||
|
@close="() => isOpen = false"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
slot="content"
|
||||||
|
class="timeline-menu-popover panel panel-default"
|
||||||
|
>
|
||||||
|
<ul>
|
||||||
|
<li v-if="currentUser">
|
||||||
|
<router-link :to="{ name: 'friends' }">
|
||||||
|
<i class="button-icon icon-home-2" />{{ $t("nav.timeline") }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li v-if="currentUser">
|
||||||
|
<router-link :to="{ name: 'bookmarks'}">
|
||||||
|
<i class="button-icon icon-bookmark" />{{ $t("nav.bookmarks") }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li v-if="currentUser">
|
||||||
|
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
||||||
|
<i class="button-icon icon-mail-alt" />{{ $t("nav.dms") }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li v-if="currentUser || !privateMode">
|
||||||
|
<router-link :to="{ name: 'public-timeline' }">
|
||||||
|
<i class="button-icon icon-users" />{{ $t("nav.public_tl") }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li v-if="federating && (currentUser || !privateMode)">
|
||||||
|
<router-link :to="{ name: 'public-external-timeline' }">
|
||||||
|
<i class="button-icon icon-globe" />{{ $t("nav.twkn") }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
slot="trigger"
|
||||||
|
class="title timeline-menu-title"
|
||||||
|
>
|
||||||
|
<span>{{ $t(timelineNames[$route.name]) }}</span>
|
||||||
|
<i class="icon-down-open" />
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./timeline_menu.js" ></script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
|
.timeline-menu {
|
||||||
|
flex-shrink: 1;
|
||||||
|
margin-right: auto;
|
||||||
|
min-width: 0;
|
||||||
|
width: 24rem;
|
||||||
|
.timeline-menu-popover-wrap {
|
||||||
|
overflow: hidden;
|
||||||
|
// Match panel heading padding to line up menu with bottom of heading
|
||||||
|
margin-top: 0.6rem;
|
||||||
|
padding: 0 15px 15px 15px;
|
||||||
|
}
|
||||||
|
.timeline-menu-popover {
|
||||||
|
width: 24rem;
|
||||||
|
max-width: 100vw;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
transition: transform 100ms;
|
||||||
|
}
|
||||||
|
.panel::after {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
}
|
||||||
|
&.open .timeline-menu-popover {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-menu-title {
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
user-select: none;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
span {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-left: 0.6em;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: transform 100ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.open .timeline-menu-title i {
|
||||||
|
color: $fallback--text;
|
||||||
|
color: var(--panelText, $fallback--text);
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
box-shadow: var(--popoverShadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
border-color: $fallback--border;
|
||||||
|
border-color: var(--border, $fallback--border);
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:last-child a {
|
||||||
|
border-bottom-right-radius: $fallback--panelRadius;
|
||||||
|
border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius);
|
||||||
|
border-bottom-left-radius: $fallback--panelRadius;
|
||||||
|
border-bottom-left-radius: var(--panelRadius, $fallback--panelRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin: 0 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
padding: 0.6em 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $fallback--lightBg;
|
||||||
|
background-color: var(--selectedMenu, $fallback--lightBg);
|
||||||
|
color: $fallback--link;
|
||||||
|
color: var(--selectedMenuText, $fallback--link);
|
||||||
|
--faint: var(--selectedMenuFaintText, $fallback--faint);
|
||||||
|
--faintLink: var(--selectedMenuFaintLink, $fallback--faint);
|
||||||
|
--lightText: var(--selectedMenuLightText, $fallback--lightText);
|
||||||
|
--icon: var(--selectedMenuIcon, $fallback--icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.router-link-active {
|
||||||
|
font-weight: bolder;
|
||||||
|
background-color: $fallback--lightBg;
|
||||||
|
background-color: var(--selectedMenu, $fallback--lightBg);
|
||||||
|
color: $fallback--text;
|
||||||
|
color: var(--selectedMenuText, $fallback--text);
|
||||||
|
--faint: var(--selectedMenuFaintText, $fallback--faint);
|
||||||
|
--faintLink: var(--selectedMenuFaintLink, $fallback--faint);
|
||||||
|
--lightText: var(--selectedMenuLightText, $fallback--lightText);
|
||||||
|
--icon: var(--selectedMenuIcon, $fallback--icon);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -20,13 +20,14 @@
|
||||||
:key="index"
|
:key="index"
|
||||||
class="user-profile-field"
|
class="user-profile-field"
|
||||||
>
|
>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
|
||||||
<dt
|
<dt
|
||||||
:title="user.fields_text[index].name"
|
:title="user.fields_text[index].name"
|
||||||
class="user-profile-field-name"
|
class="user-profile-field-name"
|
||||||
@click.prevent="linkClicked"
|
@click.prevent="linkClicked"
|
||||||
v-html="field.name"
|
>
|
||||||
/>
|
{{ field.name }}
|
||||||
|
</dt>
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<dd
|
<dd
|
||||||
:title="user.fields_text[index].value"
|
:title="user.fields_text[index].value"
|
||||||
class="user-profile-field-value"
|
class="user-profile-field-value"
|
||||||
|
|
|
@ -146,7 +146,8 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
> .status-el {
|
/* TODO cleanup this */
|
||||||
|
> .Status {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
"dms": "Direktnachrichten",
|
"dms": "Direktnachrichten",
|
||||||
"public_tl": "Öffentliche Zeitleiste",
|
"public_tl": "Öffentliche Zeitleiste",
|
||||||
"timeline": "Zeitleiste",
|
"timeline": "Zeitleiste",
|
||||||
"twkn": "Das gesamte bekannte Netzwerk",
|
"twkn": "Bekannte Netzwerk",
|
||||||
"user_search": "Benutzersuche",
|
"user_search": "Benutzersuche",
|
||||||
"search": "Suche",
|
"search": "Suche",
|
||||||
"preferences": "Voreinstellungen",
|
"preferences": "Voreinstellungen",
|
||||||
|
|
|
@ -120,12 +120,13 @@
|
||||||
"dms": "Direct Messages",
|
"dms": "Direct Messages",
|
||||||
"public_tl": "Public Timeline",
|
"public_tl": "Public Timeline",
|
||||||
"timeline": "Timeline",
|
"timeline": "Timeline",
|
||||||
"twkn": "The Whole Known Network",
|
"twkn": "Known Network",
|
||||||
"bookmarks": "Bookmarks",
|
"bookmarks": "Bookmarks",
|
||||||
"user_search": "User Search",
|
"user_search": "User Search",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"who_to_follow": "Who to follow",
|
"who_to_follow": "Who to follow",
|
||||||
"preferences": "Preferences",
|
"preferences": "Preferences",
|
||||||
|
"timelines": "Timelines",
|
||||||
"chats": "Chats"
|
"chats": "Chats"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
"dms": "Yksityisviestit",
|
"dms": "Yksityisviestit",
|
||||||
"public_tl": "Julkinen Aikajana",
|
"public_tl": "Julkinen Aikajana",
|
||||||
"timeline": "Aikajana",
|
"timeline": "Aikajana",
|
||||||
"twkn": "Koko Tunnettu Verkosto",
|
"twkn": "Tunnettu Verkosto",
|
||||||
"user_search": "Käyttäjähaku",
|
"user_search": "Käyttäjähaku",
|
||||||
"who_to_follow": "Seurausehdotukset",
|
"who_to_follow": "Seurausehdotukset",
|
||||||
"preferences": "Asetukset",
|
"preferences": "Asetukset",
|
||||||
|
|
|
@ -16,7 +16,8 @@ const defaultState = {
|
||||||
},
|
},
|
||||||
mobileLayout: false,
|
mobileLayout: false,
|
||||||
globalNotices: [],
|
globalNotices: [],
|
||||||
layoutHeight: 0
|
layoutHeight: 0,
|
||||||
|
lastTimeline: null
|
||||||
}
|
}
|
||||||
|
|
||||||
const interfaceMod = {
|
const interfaceMod = {
|
||||||
|
@ -69,6 +70,9 @@ const interfaceMod = {
|
||||||
},
|
},
|
||||||
setLayoutHeight (state, value) {
|
setLayoutHeight (state, value) {
|
||||||
state.layoutHeight = value
|
state.layoutHeight = value
|
||||||
|
},
|
||||||
|
setLastTimeline (state, value) {
|
||||||
|
state.lastTimeline = value
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -117,6 +121,9 @@ const interfaceMod = {
|
||||||
},
|
},
|
||||||
setLayoutHeight ({ commit }, value) {
|
setLayoutHeight ({ commit }, value) {
|
||||||
commit('setLayoutHeight', value)
|
commit('setLayoutHeight', value)
|
||||||
|
},
|
||||||
|
setLastTimeline ({ commit }, value) {
|
||||||
|
commit('setLastTimeline', value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,6 +509,7 @@ const users = {
|
||||||
store.commit('clearNotifications')
|
store.commit('clearNotifications')
|
||||||
store.commit('resetStatuses')
|
store.commit('resetStatuses')
|
||||||
store.dispatch('resetChats')
|
store.dispatch('resetChats')
|
||||||
|
store.dispatch('setLastTimeline', 'public-timeline')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
loginUser (store, accessToken) {
|
loginUser (store, accessToken) {
|
||||||
|
|
Loading…
Reference in a new issue