refactor status

This commit is contained in:
Henry Jameson 2020-07-28 01:27:11 +03:00
parent 61d78ff11b
commit 65b6e23c00
11 changed files with 1786 additions and 416 deletions

View file

@ -22,8 +22,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 +36,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 +79,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 +101,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",

View file

@ -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;

View file

@ -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,15 +40,26 @@
<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-color: var(--border, $fallback--border); border-color: var(--border, $fallback--border);
border-radius: 0; border-radius: 0;
} }
&.-expanded {
.conversation-status:last-child {
border-bottom: none;
}
}
&:not(.-expanded) > {
.conversation-status:last-child {
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
}
} }
} }
</style> </style>

View file

@ -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;
} }

View file

@ -3,36 +3,31 @@
$status-margin: 0.75em; $status-margin: 0.75em;
.status-body { .Status {
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; min-width: 0;
border-color: $fallback--border; border-color: $fallback--border;
border-color: var(--border, $fallback--border); border-color: var(--border, $fallback--border);
border-left: 4px $fallback--cRed; border-left: 4px $fallback--cRed;
border-left: 4px var(--cRed, $fallback--cRed); border-left: 4px var(--cRed, $fallback--cRed);
&_focused { // TODO find a way to do this in a cleaner way without JS
// stylelint-disable rscss/class-format
&:hover .avatar.animated {
canvas {
display: none;
}
img {
visibility: visible;
}
}
&.-focused {
background-color: $fallback--lightBg; background-color: $fallback--lightBg;
background-color: var(--selectedPost, $fallback--lightBg); background-color: var(--selectedPost, $fallback--lightBg);
color: $fallback--text; color: $fallback--text;
color: var(--selectedPostText, $fallback--text); color: var(--selectedPostText, $fallback--text);
--lightText: var(--selectedPostLightText, $fallback--light); --lightText: var(--selectedPostLightText, $fallback--light);
--faint: var(--selectedPostFaintText, $fallback--faint); --faint: var(--selectedPostFaintText, $fallback--faint);
--faintLink: var(--selectedPostFaintLink, $fallback--faint); --faintLink: var(--selectedPostFaintLink, $fallback--faint);
@ -41,17 +36,32 @@ $status-margin: 0.75em;
--icon: var(--selectedPostIcon, $fallback--icon); --icon: var(--selectedPostIcon, $fallback--icon);
} }
.timeline & { .status-container {
border-bottom-width: 1px; display: flex;
border-bottom-style: solid; padding: $status-margin;
&.-repeat {
padding-top: 0;
}
} }
.media-body { .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; flex: 1;
padding: 0; min-width: 0;
} }
.status-usercard { .usercard {
margin-bottom: $status-margin; margin-bottom: $status-margin;
} }
@ -59,15 +69,17 @@ $status-margin: 0.75em;
white-space: nowrap; white-space: nowrap;
font-size: 14px; font-size: 14px;
overflow: hidden; overflow: hidden;
flex-shrink: 0;
max-width: 85%; max-width: 85%;
font-weight: bold; font-weight: bold;
flex-shrink: 1;
margin-right: 0.4em;
text-overflow: ellipsis;
img.emoji { .emoji {
width: 14px; width: 14px;
height: 14px; height: 14px;
vertical-align: middle; vertical-align: middle;
object-fit: contain object-fit: contain;
} }
} }
@ -77,18 +89,11 @@ $status-margin: 0.75em;
margin-right: 0.4em; margin-right: 0.4em;
} }
.media-heading { .status-heading {
padding: 0;
vertical-align: bottom;
flex-basis: 100%;
margin-bottom: 0.5em; margin-bottom: 0.5em;
small {
font-weight: lighter;
} }
.heading-name-row { .heading-name-row {
padding: 0;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
line-height: 18px; line-height: 18px;
@ -97,17 +102,6 @@ $status-margin: 0.75em;
display: inline-block; display: inline-block;
word-break: break-all; 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 { .account-name {
@ -118,6 +112,10 @@ $status-margin: 0.75em;
text-overflow: ellipsis; text-overflow: ellipsis;
flex: 1 1 0; flex: 1 1 0;
} }
.heading-left {
display: flex;
min-width: 0;
} }
.heading-right { .heading-right {
@ -138,14 +136,6 @@ $status-margin: 0.75em;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: stretch; 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 { .reply-to-and-accountname {
@ -153,17 +143,25 @@ $status-margin: 0.75em;
height: 18px; height: 18px;
margin-right: 0.5em; margin-right: 0.5em;
max-width: 100%; max-width: 100%;
.icon-reply { .icon-reply {
// mirror the icon
transform: scaleX(-1); transform: scaleX(-1);
} }
} }
.reply-info {
display: flex;
}
.reply-to-popover { .reply-to-popover {
min-width: 0; min-width: 0;
margin-right: 0.4em;
&:hover {
border-bottom: 1px solid var(--faint);
}
.faint-link:hover {
// override default
text-decoration: none;
}
} }
.reply-to { .reply-to {
@ -174,12 +172,12 @@ $status-margin: 0.75em;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
margin: 0 0.4em 0 0.2em; margin-left: 0.2em;
}
.strikethrough { &.-strikethrough {
text-decoration: line-through; text-decoration: line-through;
} }
}
.replies-separator { .replies-separator {
margin-left: 0.4em; margin-left: 0.4em;
@ -190,6 +188,7 @@ $status-margin: 0.75em;
font-size: 12px; font-size: 12px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
& > * { & > * {
margin-right: 0.4em; margin-right: 0.4em;
} }
@ -198,52 +197,38 @@ $status-margin: 0.75em;
.reply-link { .reply-link {
height: 17px; height: 17px;
} }
.repeat-info {
padding: 0.4em $status-margin;
line-height: 22px;
.right-side {
display: flex;
align-content: center;
flex-wrap: wrap;
} }
.retweet-info { i {
padding: 0.4em $status-margin; padding: 0 0.2em;
margin: 0; }
}
.avatar.still-image { .repeater-avatar {
border-radius: $fallback--avatarAltRadius;
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
margin-left: 28px; margin-left: 28px;
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
.media-body { .repeater-name {
font-size: 1em;
line-height: 22px;
display: flex;
align-content: center;
flex-wrap: wrap;
.user-name {
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
margin-right: 0;
img { .emoji {
width: 14px; width: 14px;
height: 14px; height: 14px;
vertical-align: middle; vertical-align: middle;
object-fit: contain object-fit: contain;
}
}
i {
padding: 0 0.2em;
}
a {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
} }
} }
@ -256,15 +241,12 @@ $status-margin: 0.75em;
from { from {
opacity: 0; opacity: 0;
} }
to { to {
opacity: 1; opacity: 1;
} }
} }
.status-conversation {
border-left-style: solid;
}
.status-actions { .status-actions {
position: relative; position: relative;
width: 100%; width: 100%;
@ -277,43 +259,20 @@ $status-margin: 0.75em;
} }
} }
.button-icon.icon-reply { .button-reply {
&:not(.button-icon-disabled):hover, &:not(.-disabled) {
&.button-icon-active { cursor: pointer;
}
&:not(.-disabled):hover,
&.-active {
color: $fallback--cBlue; color: $fallback--cBlue;
color: var(--cBlue, $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 { .muted {
padding: .25em .6em; padding: 0.25em 0.6em;
height: 1.2em; height: 1.2em;
line-height: 1.2em; line-height: 1.2em;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -321,20 +280,24 @@ $status-margin: 0.75em;
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
.username, .mute-thread, .mute-words { & .user-name,
& .mute-thread,
& .mute-words {
word-wrap: normal; word-wrap: normal;
word-break: normal; word-break: normal;
white-space: nowrap; white-space: nowrap;
} }
.username, .mute-words { & .user-name,
& .mute-words {
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
} }
.username { .user-name {
font-weight: normal;
flex: 0 1 auto; flex: 0 1 auto;
margin-right: .2em; margin-right: 0.2em;
} }
.mute-thread { .mute-thread {
@ -343,9 +306,10 @@ $status-margin: 0.75em;
.mute-words { .mute-words {
flex: 1 0 5em; flex: 1 0 5em;
margin-left: .2em; margin-left: 0.2em;
&::before { &::before {
content: ' ' content: ' ';
} }
} }
@ -353,7 +317,6 @@ $status-margin: 0.75em;
flex: 0 0 auto; flex: 0 0 auto;
margin-left: auto; margin-left: auto;
display: block; display: block;
margin-left: auto;
} }
} }
@ -363,32 +326,12 @@ $status-margin: 0.75em;
.favs-repeated-users { .favs-repeated-users {
margin-top: $status-margin; margin-top: $status-margin;
}
.stats { .stats {
width: 100%; width: 100%;
display: flex; display: flex;
line-height: 1em; 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 { .avatar-row {
@ -407,28 +350,44 @@ $status-margin: 0.75em;
background-color: var(--faint, $fallback--faint); 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) { @media all and (max-width: 800px) {
.status-el { .repeater-avatar {
.retweet-info {
.avatar.still-image {
margin-left: 20px; margin-left: 20px;
} }
}
}
.status {
max-width: 100%;
}
.status .avatar.still-image { .avatar:not(.repeater-avatar) {
width: 40px; width: 40px;
height: 40px; height: 40px;
// TODO define those other way somehow?
// stylelint-disable rscss/class-format
&.avatar-compact { &.avatar-compact {
width: 32px; width: 32px;
height: 32px; height: 32px;
} }
} }
} }
}

View file

@ -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="user-name">
<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="user-name 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,20 +115,20 @@
/> />
</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="user-name"
@ -218,10 +218,10 @@
: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 }" :class="{ '-strikethrough': !status.parent_visible }"
> >
{{ $t('status.reply_to') }} {{ $t('status.reply_to') }}
</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"
> >
<PostStatusForm <PostStatusForm
class="reply-body" class="reply-body"
@ -375,4 +375,4 @@
</template> </template>
<script src="./status.js" ></script> <script src="./status.js" ></script>
<style src="./status.css" lang="scss"></style> <style src="./status.scss" lang="scss"></style>

View file

@ -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;
@ -283,13 +283,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>

View file

@ -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;
} }

View file

@ -1,5 +1,5 @@
<template> <template>
<div :class="classes.root"> <div :class="[classes.root, 'timeline']">
<div :class="classes.header"> <div :class="classes.header">
<div class="title"> <div class="title">
{{ title }} {{ title }}

View file

@ -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;
} }

1437
yarn.lock

File diff suppressed because it is too large Load diff