Compare commits

..

No commits in common. "develop" and "develop" have entirely different histories.

18 changed files with 75 additions and 141 deletions

View file

@ -3,28 +3,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased (3.18)
### REMOVED
- dropped obsolete and buggy dm timeline
## Unreleased
### Added
- UI for conversations API, replacing the DM timeline.
Here each thread (conversation) has its own timeline and read markers instead of mixing everything together.
- Boosts now show when and with which visibility they were boosted
- bookmarks are now accessible via the narrow/mobile UI
### Fixed
- fixed saving fallback cop yof settings to local browser storage
- improve image animation detection further
- fix status content parsing for mention and hashtag detection; this could lock the UI until reload
- fix display of nsfw attachment overlays on webkit
## Between 2022.09 (3.2.0) and 2025.12 (3.17.0)
A whole lot of stuff, but we forgot to update the changelog besides the one entry below, oopsi
- Implemented remote interaction with statuses
## 2022.09 (3.2.0) - 2022-09-10
## 2022.09 - 2022-09-10
### Added
- Automatic post translations. Must be configured on the backend in order to work.
- Post editing, including a log of previous edits.

View file

@ -26,12 +26,6 @@
}
}
&.-nsfw-placeholder {
.attachment-wrapper {
align-content: unset;
}
}
.description-container {
flex: 0 1 0;
display: flex;

View file

@ -6,9 +6,8 @@
<div class="heading">
<div class="title-bar">
<div class="title-bar-left">
<div
<div class="unread"
v-if="conversation.unread"
class="unread"
>
<span
class="badge badge-notification"
@ -30,7 +29,7 @@
</button>
&nbsp;
</div>
<h4>{{ $t('dm_conv.default_name', {id: conversation.id}) }}</h4>
<h4>{{ $t('dm_conv.default_name', {id: this.conversation.id}) }}</h4>
</div>
<div class="title-bar-right">
<button
@ -49,21 +48,17 @@
<div class="members">
<UserAvatar
v-for="user in membersTruncated.users"
:key="user.id"
:user="user"
:compact="compact"
/>
<div
v-if="membersTruncated.truncated"
class="ellipsis"
>
<div v-if="membersTruncated.truncated" class="ellipsis">
...
</div>
</div>
</router-link>
<div
v-if="showLastStatus"
class="last-message"
v-if="showLastStatus"
>
<div class="last-message-title">
{{ $t('dm_conv.last_message_title') }}:
@ -81,7 +76,7 @@
<button
class="btn button-default"
:title="$t('dm_conv.recipients_edit_mode_button_tooltip')"
@click.once="$router.push({ name: 'dm-conversation-recipients', params: { id: conversation.id }})"
@click.once="$router.push({ name: 'dm-conversation-recipients', params: { id: this.conversation.id }})"
>
{{ $t('dm_conv.recipients_edit_mode_button') }}
</button>
@ -95,7 +90,7 @@
@accepted="doDeleteConversation"
@cancelled="hideDeleteConfirmModal"
>
{{ $t('dm_conv.delete_confirm', { identifier: conversation.id }) }}
{{ $t('dm_conv.delete_confirm', { identifier: this.conversation.id }) }}
</confirm-modal>
</teleport>
</div>

View file

@ -6,15 +6,15 @@
timeline-name="dmConv"
>
<template
#extraHeading
v-slot:extraHeading
>
<DMConvCard
v-if="conversation"
:conversation="conversation"
:compact="false"
:show-full-controls="true"
:show-last-status="false"
:link-to-timeline="false"
:showFullControls="true"
:showLastStatus="false"
:linkToTimeline="false"
@deleted="forceLeave"
/>
</template>

View file

@ -37,7 +37,7 @@
<StillImage
v-else
:src="item.emoji.imageUrl"
no-stop-gifs="true"
noStopGifs="true"
/>
</span>
</template>

View file

@ -51,7 +51,7 @@
<StillImage
v-if="suggestion.img"
:src="suggestion.img"
no-stop-gifs="true"
noStopGifs="true"
/>
<span v-else>{{ suggestion.replacement }}</span>
</span>

View file

@ -21,7 +21,7 @@
<StillImage
v-else
:src="group.first.imageUrl"
no-stop-gifs="true"
noStopGifs="true"
/>
</span>
<span

View file

@ -31,7 +31,7 @@
:alt="currentMedia.description"
:title="currentMedia.description"
:image-load-handler="onImageLoaded"
no-stop-gifs="true"
noStopGifs="true"
/>
</PinchZoom>
</SwipeClick>

View file

@ -195,8 +195,8 @@
:class="{ 'visibility-tray-edit': isEdit }"
>
<scope-selector
v-if="!disableVisibilitySelector"
ref="scopeselector"
v-if="!disableVisibilitySelector"
:user-default="userDefaultScope"
:original-scope="copyMessageScope"
:initial-scope="newStatus.visibility"
@ -204,11 +204,10 @@
/>
<div
class="format-selector-container"
>
class="format-selector-container">
<div
class="format-selector"
>
>
<Select
id="post-language"
v-model="newStatus.language"

View file

@ -7,16 +7,8 @@ const QuoteButton = {
name: 'QuoteButton',
props: ['status', 'quoting', 'visibility'],
computed: {
showButton () {
const currentUserId = this.$store.state.users.currentUser?.id
if (!currentUserId)
return false
if (['public', 'unlisted', 'local'].includes(this.visibility))
return true
return (this.visibility === 'private' && currentUserId == this.status.user.id)
loggedIn () {
return !!this.$store.state.users.currentUser
}
}
}

View file

@ -1,6 +1,6 @@
<template>
<div
v-if="showButton"
v-if="(visibility === 'public' || visibility === 'unlisted') && loggedIn"
class="QuoteButton"
>
<button

View file

@ -9,7 +9,6 @@ import {
faHome,
faComments,
faBolt,
faBookmark,
faUserPlus,
faBullhorn,
faSearch,
@ -26,7 +25,6 @@ library.add(
faHome,
faComments,
faBolt,
faBookmark,
faUserPlus,
faBullhorn,
faSearch,

View file

@ -85,18 +85,6 @@
/> {{ $t("nav.lists") }}
</router-link>
</li>
<li
v-if="currentUser"
@click="toggleDrawer"
>
<router-link :to="{ name: 'bookmarks' }">
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="bookmark"
/> {{ $t("nav.bookmarks") }}
</router-link>
</li>
</ul>
<ul v-if="currentUser">
<li @click="toggleDrawer">

View file

@ -99,21 +99,19 @@
<router-link
v-else
:to="retweeterProfileLink"
>
{{ retweeter }}
</router-link>
>{{ retweeter }}</router-link>
</div>
{{ ' ' }}
<div
class="repeat-tooltip"
>
<FAIcon
icon="retweet"
class="repeat-icon"
:title="$t('tool_tip.repeat')"
/>
{{ $t('timeline.repeated') }}
<FAIcon
icon="retweet"
class="repeat-icon"
:title="$t('tool_tip.repeat')"
/>
{{ $t('timeline.repeated') }}
</div>
<span

View file

@ -56,7 +56,7 @@
v-if="$slots.extraHeading"
class="timeline-extra-heading"
>
<slot name="extraHeading" />
<slot name="extraHeading"></slot>
</div>
<div :class="classes.body">
<div

View file

@ -11,7 +11,7 @@
<div class="panel-heading -flexible-height">
<div
class="user-info"
:class="{ '-compact': compactUserInfo }"
:class="{ '-compact': this.compactUserInfo }"
>
<div class="container">
<a
@ -54,10 +54,7 @@
>
@{{ user.screen_name_ui }}
</router-link>
<span
v-if="!hideBio && (user.deactivated || !!visibleRole || user.bot)"
class="user-roles"
>
<span class="user-roles" v-if="!hideBio && (user.deactivated || !!visibleRole || user.bot)">
<span
v-if="user.deactivated"
class="alert user-role"
@ -77,10 +74,7 @@
{{ $t('user_card.bot') }}
</span>
</span>
<span
v-if="user.locked"
class="user-locked"
>
<span class="user-locked" v-if="user.locked">
<FAIcon
class="lock-icon"
icon="lock"
@ -120,44 +114,44 @@
</div>
<div class="user-buttons">
<button
v-if="!isOtherUser && user.is_local"
class="button-unstyled edit-profile-button"
@click.stop="openProfileTab"
>
<FAIcon
fixed-width
class="icon"
icon="edit"
:title="$t('user_card.edit_profile')"
v-if="!isOtherUser && user.is_local"
class="button-unstyled edit-profile-button"
@click.stop="openProfileTab"
>
<FAIcon
fixed-width
class="icon"
icon="edit"
:title="$t('user_card.edit_profile')"
/>
</button>
<a
v-if="isOtherUser && !user.is_local"
:href="user.statusnet_profile_url"
target="_blank"
class="button-unstyled external-link-button"
>
<FAIcon
class="icon"
icon="external-link-alt"
/>
</a>
<a
v-if="isOtherUser"
:href="user.statusnet_profile_url + '.rss'"
target="_blank"
class="button-unstyled external-link-button"
>
<FAIcon
class="icon"
icon="rss"
/>
</a>
<AccountActions
v-if="isOtherUser && loggedIn"
:user="user"
:relationship="relationship"
/>
</button>
<a
v-if="isOtherUser && !user.is_local"
:href="user.statusnet_profile_url"
target="_blank"
class="button-unstyled external-link-button"
>
<FAIcon
class="icon"
icon="external-link-alt"
/>
</a>
<a
v-if="isOtherUser"
:href="user.statusnet_profile_url + '.rss'"
target="_blank"
class="button-unstyled external-link-button"
>
<FAIcon
class="icon"
icon="rss"
/>
</a>
<AccountActions
v-if="isOtherUser && loggedIn"
:user="user"
:relationship="relationship"
/>
</div>
</div>
<div class="user-meta">
@ -309,7 +303,7 @@
:html="user.description_html"
:emoji="user.emoji"
:handle-links="true"
:style='{"text-align": $store.getters.mergedConfig.centerAlignBio ? "center" : "start"}'
:style='{"text-align": this.$store.getters.mergedConfig.centerAlignBio ? "center" : "start"}'
/>
</div>
<teleport to="#modal">

View file

@ -1,7 +1,5 @@
import { merge } from 'lodash'
const POLL_UPDATE_FREQUENCY = 150_000;
const polls = {
state: {
// Contains key = id, value = number of trackers for this poll
@ -14,9 +12,6 @@ const polls = {
// Make expired-state change trigger re-renders properly
poll.expired = Date.now() > Date.parse(poll.expires_at)
if (existingPoll) {
if (poll.expired) {
state.trackedPolls[poll.id] = 0
}
state.pollsObject[poll.id] = merge(existingPoll, poll)
} else {
state.pollsObject[poll.id] = poll
@ -49,16 +44,13 @@ const polls = {
if (rootState.polls.trackedPolls[pollId]) {
dispatch('updateTrackedPoll', pollId)
}
}, POLL_UPDATE_FREQUENCY)
}, 30 * 1000)
commit('mergeOrAddPoll', poll)
})
},
trackPoll ({ rootState, commit, dispatch }, pollId) {
if (rootState.polls.pollsObject[pollId]?.expired)
return;
if (!rootState.polls.trackedPolls[pollId]) {
setTimeout(() => dispatch('updateTrackedPoll', pollId), POLL_UPDATE_FREQUENCY)
setTimeout(() => dispatch('updateTrackedPoll', pollId), 30 * 1000)
}
commit('trackPoll', pollId)
},

View file

@ -22,7 +22,7 @@ export const getAttrs = tag => {
.replace(new RegExp('^' + getTagName(tag)), '')
.replace(/\/?$/, '')
.trim()
const attrs = Array.from(innertag.matchAll(/([a-z]+[a-z0-9-]*)(?:=((?:"(?:\\.|[^"\\])*")|(?:'(?:\\.|[^'\\])*')))?/gi))
const attrs = Array.from(innertag.matchAll(/([a-z0-9-]+)(?:=("[^"]+?"|'[^']+?'))?/gi))
.map(([trash, key, value]) => [key, value])
.map(([k, v]) => {
if (!v) return [k, true]