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

* origin/develop: (40 commits)
  Poll, StatusContent: Move emoji css to status body.
  remove recentqueries thing
  fix width of long field value
  change key-value to look like one
  revert import style
  return the correct promise type from action
  update changelog
  remove search blocker, fix debounce params
  resume the previous emoji size for now
  restyle the fields
  Update popover.js
  update changelog
  disable subject field when posting
  remove log whoops
  fix popovers cutting off in notifications, port popover changes from chats mr
  Changelog: Add info about poll option emoji.
  changelog
  Apply suggestion to src/services/entity_normalizer/entity_normalizer.service.js
  Polls: Construct an html field during normalization.
  fix #866
  ...
This commit is contained in:
Henry Jameson 2020-06-19 15:50:43 +03:00
commit eb10e7edf6
30 changed files with 226 additions and 181 deletions

View file

@ -3,6 +3,7 @@
<Popover
trigger="click"
placement="bottom"
:bound-to="{ x: 'container' }"
>
<div
slot="content"

View file

@ -13,7 +13,7 @@ import { debounce } from 'lodash'
const debounceUserSearch = debounce((data, input) => {
data.updateUsersList(input)
}, 500, { leading: true, trailing: false })
}, 500)
export default data => input => {
const firstChar = input[0]
@ -97,8 +97,8 @@ export const suggestUsers = data => input => {
replacement: '@' + screen_name + ' '
}))
// BE search users if there are no matches
if (newUsers.length === 0 && data.updateUsersList) {
// BE search users to get more comprehensive results
if (data.updateUsersList) {
debounceUserSearch(data, noPrefix)
}
return newUsers

View file

@ -3,6 +3,7 @@
trigger="click"
placement="top"
class="extra-button-popover"
:bound-to="{ x: 'container' }"
>
<div
slot="content"

View file

@ -78,6 +78,7 @@
video,
canvas {
object-fit: contain;
height: 100%;
}
}

View file

@ -54,25 +54,20 @@
flex-wrap: nowrap;
padding: 0.6em;
min-width: 0;
.avatar-container {
width: 32px;
height: 32px;
}
.status-el {
.status {
padding: 0.25em 0;
color: $fallback--faint;
color: var(--faint, $fallback--faint);
a {
color: var(--faintLink);
}
.status-content a {
color: var(--postFaintLink);
}
.status-body {
color: $fallback--faint;
color: var(--faint, $fallback--faint);
a {
color: var(--faintLink);
}
padding: 0;
.media-body {
margin: 0;
.status-content a {
color: var(--postFaintLink);
}
}
}

View file

@ -17,7 +17,7 @@
<span class="result-percentage">
{{ percentageForOption(option.votes_count) }}%
</span>
<span>{{ option.title }}</span>
<span v-html="option.title_html"></span>
</div>
<div
class="result-fill"

View file

@ -1,4 +1,3 @@
const Popover = {
name: 'Popover',
props: {
@ -10,6 +9,9 @@ const Popover = {
// 'container' for using offsetParent as boundaries for either axis
// or 'viewport'
boundTo: Object,
// Takes a selector to use as a replacement for the parent container
// for getting boundaries for x an y axis
boundToSelector: String,
// Takes a top/bottom/left/right object, how much space to leave
// between boundary and popover element
margin: Object,
@ -27,6 +29,10 @@ const Popover = {
}
},
methods: {
containerBoundingClientRect () {
const container = this.boundToSelector ? this.$el.closest(this.boundToSelector) : this.$el.offsetParent
return container.getBoundingClientRect()
},
updateStyles () {
if (this.hidden) {
this.styles = {
@ -45,7 +51,8 @@ const Popover = {
// Minor optimization, don't call a slow reflow call if we don't have to
const parentBounds = this.boundTo &&
(this.boundTo.x === 'container' || this.boundTo.y === 'container') &&
this.$el.offsetParent.getBoundingClientRect()
this.containerBoundingClientRect()
const margin = this.margin || {}
// What are the screen bounds for the popover? Viewport vs container

View file

@ -81,6 +81,7 @@
v-model="newStatus.spoilerText"
type="text"
:placeholder="$t('post_status.content_warning')"
:disabled="posting"
class="form-post-subject"
>
</EmojiInput>

View file

@ -13,6 +13,9 @@ const PostStatusModal = {
}
},
computed: {
isLoggedIn () {
return !!this.$store.state.users.currentUser
},
modalActivated () {
return this.$store.state.postStatus.modalActivated
},

View file

@ -1,5 +1,6 @@
<template>
<Modal
v-if="isLoggedIn && !resettingForm"
:is-open="modalActivated"
class="post-form-modal-view"
@backdropClicked="closeModal"

View file

@ -256,6 +256,13 @@
:label="$t('settings.links')"
/>
<ContrastRatio :contrast="previewContrast.postLink" />
<ColorInput
v-model="postGreentextColorLocal"
name="postGreentextColor"
:fallback="previewTheme.colors.cGreen"
:label="$t('settings.greentext')"
/>
<ContrastRatio :contrast="previewContrast.postGreentext" />
<h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
<ColorInput
v-model="alertErrorColorLocal"

View file

@ -164,23 +164,23 @@ $status-margin: 0.75em;
word-break: break-all;
}
img, video {
max-width: 100%;
max-height: 400px;
vertical-align: middle;
object-fit: contain;
&.emoji {
width: 32px;
height: 32px;
}
}
.status-content {
font-family: var(--postFont, sans-serif);
line-height: 1.4em;
white-space: pre-wrap;
img, video {
max-width: 100%;
max-height: 400px;
vertical-align: middle;
object-fit: contain;
&.emoji {
width: 32px;
height: 32px;
}
}
blockquote {
margin: 0.2em 0 0.2em 2em;
font-style: italic;
@ -226,7 +226,7 @@ $status-margin: 0.75em;
.greentext {
color: $fallback--cGreen;
color: var(--cGreen, $fallback--cGreen);
color: var(--postGreentext, $fallback--cGreen);
}
.timeline :not(.panel-disabled) > {

View file

@ -23,13 +23,6 @@
<style lang="scss">
@import '../../_variables.scss';
.contain-fit {
.still-image {
img {
height: 100%;
}
}
}
.still-image {
position: relative;
@ -38,6 +31,7 @@
width: 100%;
height: 100%;
display: flex;
align-items: center;
&:hover canvas {
display: none;
@ -45,8 +39,8 @@
img {
width: 100%;
min-height: 100%;
object-fit: contain;
align-self: center;
}
&.animated {

View file

@ -124,6 +124,14 @@ const UserProfile = {
onTabSwitch (tab) {
this.tab = tab
this.$router.replace({ query: { tab } })
},
linkClicked ({ target }) {
if (target.tagName === 'SPAN') {
target = target.parentNode
}
if (target.tagName === 'A') {
window.open(target.href, '_blank')
}
}
},
watch: {

View file

@ -11,6 +11,31 @@
:allow-zooming-avatar="true"
rounded="top"
/>
<div
v-if="user.fields_html && user.fields_html.length > 0"
class="user-profile-fields"
>
<dl
v-for="(field, index) in user.fields_html"
:key="index"
class="user-profile-field"
>
<!-- eslint-disable vue/no-v-html -->
<dt
:title="user.fields_text[index].name"
class="user-profile-field-name"
@click.prevent="linkClicked"
v-html="field.name"
/>
<dd
:title="user.fields_text[index].value"
class="user-profile-field-value"
@click.prevent="linkClicked"
v-html="field.value"
/>
<!-- eslint-enable vue/no-v-html -->
</dl>
</div>
<tab-switcher
:active-tab="tab"
:render-only-focused="true"
@ -108,11 +133,60 @@
<script src="./user_profile.js"></script>
<style lang="scss">
@import '../../_variables.scss';
.user-profile {
flex: 2;
flex-basis: 500px;
.user-profile-fields {
margin: 0 0.5em;
img {
object-fit: contain;
vertical-align: middle;
max-width: 100%;
max-height: 400px;
&.emoji {
width: 18px;
height: 18px;
}
}
.user-profile-field {
display: flex;
margin: 0.25em auto;
max-width: 32em;
border: 1px solid var(--border, $fallback--border);
border-radius: $fallback--inputRadius;
border-radius: var(--inputRadius, $fallback--inputRadius);
.user-profile-field-name {
flex: 0 1 30%;
font-weight: 500;
text-align: right;
color: var(--lightText);
min-width: 120px;
border-right: 1px solid var(--border, $fallback--border);
}
.user-profile-field-value {
flex: 1 1 70%;
color: var(--text);
margin: 0 0 0 0.25em;
}
.user-profile-field-name, .user-profile-field-value {
line-height: 18px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
padding: 0.5em 1.5em;
box-sizing: border-box;
}
}
}
.userlist-placeholder {
display: flex;
justify-content: center;

View file

@ -238,13 +238,42 @@
"alert_warning": "Attenzione",
"alert_error": "Errore",
"alert": "Sfondo degli avvertimenti",
"_tab_label": "Avanzate"
"_tab_label": "Avanzate",
"tabs": "Etichette",
"disabled": "Disabilitato",
"selectedMenu": "Voce menù selezionata",
"selectedPost": "Messaggio selezionato",
"pressed": "Premuto",
"highlight": "Elementi evidenziati",
"icons": "Icone",
"poll": "Grafico sondaggi",
"underlay": "Sottostante",
"faint_text": "Testo sbiadito",
"inputs": "Campi d'immissione",
"buttons": "Pulsanti",
"borders": "Bordi",
"top_bar": "Barra superiore",
"panel_header": "Titolo pannello",
"badge_notification": "Notifica",
"popover": "Suggerimenti, menù, sbalzi"
},
"common_colors": {
"rgbo": "Icone, accenti, medaglie",
"foreground_hint": "Seleziona l'etichetta \"Avanzate\" per controlli più fini",
"main": "Colori comuni",
"_tab_label": "Comuni"
},
"shadows": {
"inset": "Includi",
"spread": "Spandi",
"blur": "Sfoca",
"shadow_id": "Ombra numero {value}",
"override": "Sostituisci",
"component": "Componente",
"_tab_label": "Luci ed ombre"
},
"radii": {
"_tab_label": "Raggio"
}
},
"enable_web_push_notifications": "Abilita notifiche web push",
@ -261,7 +290,7 @@
"notifications": "Notifiche",
"greentext": "Frecce da meme",
"upload_a_photo": "Carica un'immagine",
"type_domains_to_mute": "Inserisci domini da zittire",
"type_domains_to_mute": "Cerca domini da zittire",
"theme_help_v2_2": "Le icone dietro alcuni elementi sono indicatori del contrasto fra testo e sfondo, passaci sopra col puntatore per ulteriori informazioni. Se si usano delle trasparenze, questi indicatori mostrano il peggior caso possibile.",
"theme_help_v2_1": "Puoi anche forzare colore ed opacità di alcuni elementi selezionando la casella. Usa il pulsante \"Azzera\" per azzerare tutte le forzature.",
"useStreamingApiWarning": "(Sconsigliato, sperimentale, può saltare messaggi)",

View file

@ -1,13 +1,12 @@
import merge from 'lodash.merge'
import objectPath from 'object-path'
import localforage from 'localforage'
import { each } from 'lodash'
import { each, get, set } from 'lodash'
let loaded = false
const defaultReducer = (state, paths) => (
paths.length === 0 ? state : paths.reduce((substate, path) => {
objectPath.set(substate, path, objectPath.get(state, path))
set(substate, path, get(state, path))
return substate
}, {})
)

View file

@ -428,10 +428,10 @@ const users = {
store.commit('setUserForNotification', notification)
})
},
searchUsers (store, { query }) {
return store.rootState.api.backendInteractor.searchUsers({ query })
searchUsers ({ rootState, commit }, { query }) {
return rootState.api.backendInteractor.searchUsers({ query })
.then((users) => {
store.commit('addNewUsers', users)
commit('addNewUsers', users)
return users
})
},

View file

@ -1,6 +1,5 @@
import { each, map, concat, last, get } from 'lodash'
import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
import 'whatwg-fetch'
import { RegistrationError, StatusCodeError } from '../errors/errors'
/* eslint-env browser */

View file

@ -56,6 +56,12 @@ export const parseUser = (data) => {
value: addEmojis(field.value, data.emojis)
}
})
output.fields_text = data.fields.map(field => {
return {
name: unescape(field.name.replace(/<[^>]*>/g, '')),
value: unescape(field.value.replace(/<[^>]*>/g, ''))
}
})
// Utilize avatar_static for gif avatars?
output.profile_image_url = data.avatar
@ -258,6 +264,12 @@ export const parseStatus = (data) => {
output.summary_html = addEmojis(escape(data.spoiler_text), data.emojis)
output.external_url = data.url
output.poll = data.poll
if (output.poll) {
output.poll.options = (output.poll.options || []).map(field => ({
...field,
title_html: addEmojis(field.title, data.emojis)
}))
}
output.pinned = data.pinned
output.muted = data.muted
} else {

View file

@ -1,17 +1,4 @@
import { filter } from 'lodash'
import sanitize from 'sanitize-html'
export const removeAttachmentLinks = (html) => {
return sanitize(html, {
allowedTags: false,
allowedAttributes: false,
exclusiveFilter: ({ tag, attribs }) => tag === 'a' && typeof attribs.class === 'string' && attribs.class.match(/attachment/)
})
}
export const parse = (html) => {
return removeAttachmentLinks(html)
}
export const muteWordHits = (status, muteWords) => {
const statusText = status.text.toLowerCase()
@ -22,5 +9,3 @@ export const muteWordHits = (status, muteWords) => {
return hits
}
export default parse

View file

@ -356,6 +356,12 @@ export const SLOT_INHERITANCE = {
textColor: 'preserve'
},
postGreentext: {
depends: ['cGreen'],
layer: 'bg',
textColor: 'preserve'
},
border: {
depends: ['fg'],
opacity: 'border',