Compare commits

..

5 commits

Author SHA1 Message Date
4a50b1273d Merge pull request 'fix panel z-index conflicting with heading popover' (#422) from tea/akkoma-fe:fix/panel-z-index into develop
Reviewed-on: AkkomaGang/akkoma-fe#422
2024-10-26 03:42:48 +00:00
c76dc6d79e Merge pull request 'Fix redirect on logout' (#420) from Oneric/akkoma-fe:logout-redirect into develop
Reviewed-on: AkkomaGang/akkoma-fe#420
2024-10-26 03:42:23 +00:00
cb4c581cde Merge pull request 'Add proper autocomplete prop for TOTP login field' (#424) from tudbut/akkoma-fe:develop into develop
Reviewed-on: AkkomaGang/akkoma-fe#424
2024-10-26 03:41:15 +00:00
TudbuT
8231c8f0b6
add proper autocomplete prop for TOTP login field 2024-10-19 19:19:15 +02:00
1ae09458c6 Fix redirect on logout
An instance may restrict access to the public timeline (among others)
to authenticated users and there already is a setting to decide which page
to show authenticated and unauthenticated viewers by default each.
However, the logout redirect didn't honour this setting
leading to potentially broken pages and errors on logout
2024-09-28 17:47:28 +02:00
11 changed files with 70 additions and 170 deletions

View file

@ -20,7 +20,7 @@ body {
color: var(--text, $fallback--text);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overscroll-behavior-y: auto;
overscroll-behavior-y: none;
overflow-x: clip;
overflow-y: scroll;

View file

@ -18,6 +18,7 @@
<input
id="code"
v-model="code"
autocomplete="one-time-code"
class="form-control"
>
</div>

View file

@ -1,14 +1,12 @@
import Popover from '../popover/popover.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faRetweet, faTrash } from '@fortawesome/free-solid-svg-icons'
import { faRetweet } from '@fortawesome/free-solid-svg-icons'
library.add(faRetweet, faTrash)
library.add(faRetweet)
const RetweetButton = {
props: ['status', 'loggedIn', 'visibility'],
components: {
Popover,
ConfirmModal
},
data () {
@ -18,16 +16,16 @@ const RetweetButton = {
}
},
methods: {
retweet (visibility) {
retweet () {
if (!this.status.repeated && this.shouldConfirmRepeat) {
this.showConfirmDialog()
} else {
this.doRetweet(visibility)
this.doRetweet()
}
},
doRetweet (visibility) {
doRetweet () {
if (!this.status.repeated) {
this.$store.dispatch('retweet', { id: this.status.id, visibility: visibility })
this.$store.dispatch('retweet', { id: this.status.id })
} else {
this.$store.dispatch('unretweet', { id: this.status.id })
}

View file

@ -1,124 +1,57 @@
<template>
<!-- TODO settings the offset like this feels like a hack -->
<Popover
class="RetweetButton"
trigger="click"
placement="bottom"
:offset="{ y: 22 }"
:bound-to="{ x: 'container' }"
remove-padding
>
<template v-slot:content="{close}">
<div class="dropdown-menu">
<template v-if="status.repeated">
<button
v-if="status.repeated"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="retweet()"
>
<!-- TODO: i18n -->
<FAIcon
fixed-width
icon="trash"
/><span>Undo repeat</span>
</button>
</template>
<template v-else>
<!-- TODO: don't show button that would increase post visibility -->
<button
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="retweet('public')"
>
<FAIcon
fixed-width
icon="globe"
/><span>{{ $t("general.scope_in_timeline.public") }}</span>
</button>
<button
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="retweet('unlisted')"
>
<FAIcon
fixed-width
icon="lock-open"
/><span>{{ $t("general.scope_in_timeline.unlisted") }}</span>
</button>
<button
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="retweet('private')"
>
<FAIcon
fixed-width
icon="lock"
/><span>{{ $t("general.scope_in_timeline.private") }}</span>
</button>
<button
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="retweet('local')"
>
<!-- TODO: "general.scope_in_timeline.local" feels too long for the popover -->
<FAIcon
fixed-width
icon="users"
/><span>Local</span>
</button>
</template>
</div>
</template>
<template v-slot:trigger>
<button
v-if="(visibility !== 'private' || isOwn) && visibility !== 'direct' && loggedIn"
class="button-unstyled popover-trigger"
:class="status.repeated && '-repeated'"
<div class="RetweetButton">
<button
v-if="(visibility !== 'private' || isOwn) && visibility !== 'direct' && loggedIn"
class="button-unstyled interactive"
:class="status.repeated && '-repeated'"
:title="$t('tool_tip.repeat')"
@click.prevent="retweet()"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="retweet"
:spin="animated"
/>
</button>
<span v-else-if="loggedIn">
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="lock"
:title="$t('timeline.no_retweet_hint')"
/>
</span>
<a
v-else
class="button-unstyled interactive"
target="_blank"
role="button"
:href="remoteInteractionLink"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="retweet"
:title="$t('tool_tip.repeat')"
/>
</a>
<span
v-if="!mergedConfig.hidePostStats && status.repeat_num > 0"
class="no-event"
>
{{ status.repeat_num }}
</span>
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmDialog"
:title="$t('status.repeat_confirm_title')"
:confirm-text="$t('status.repeat_confirm_accept_button')"
:cancel-text="$t('status.repeat_confirm_cancel_button')"
@accepted="doRetweet"
@cancelled="hideConfirmDialog"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="retweet"
:spin="animated"
/>
</button>
<span v-else-if="loggedIn">
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="lock"
:title="$t('timeline.no_retweet_hint')"
/>
</span>
<a
v-else
class="button-unstyled interactive"
target="_blank"
role="button"
:href="remoteInteractionLink"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="retweet"
:title="$t('tool_tip.repeat')"
/>
</a>
<span
v-if="!mergedConfig.hidePostStats && status.repeat_num > 0"
class="no-event"
>
{{ status.repeat_num }}
</span>
<teleport to="#modal">
<!-- TODO does this work for all? -->
<confirm-modal
v-if="showingConfirmDialog"
:title="$t('status.repeat_confirm_title')"
:confirm-text="$t('status.repeat_confirm_accept_button')"
:cancel-text="$t('status.repeat_confirm_cancel_button')"
@accepted="doRetweet"
@cancelled="hideConfirmDialog"
>
{{ $t('status.repeat_confirm') }}
</confirm-modal>
</teleport>
</template>
</Popover>
{{ $t('status.repeat_confirm') }}
</confirm-modal>
</teleport>
</div>
</template>
<script src="./retweet_button.js"></script>
@ -139,7 +72,7 @@
user-select: none;
}
.popover-trigger {
.interactive {
.svg-inline--fa {
@media (prefers-reduced-motion: reduce) {
animation: unset;
@ -147,7 +80,6 @@
animation-duration: 0.6s;
}
/* TODO: don't turn green on hover because it keeps being focused on mobile when the popover is open. Instead make it while(?) like in extra_buttons and only green once it's been repeated. */
&:hover .svg-inline--fa,
&.-repeated .svg-inline--fa {
color: $fallback--cGreen;

View file

@ -69,7 +69,7 @@ const SettingsModal = {
this.$store.dispatch('closeSettingsModal')
},
logout () {
this.$router.replace('/main/public')
this.$router.replace(this.$store.state.instance.redirectRootNoLogin || '/main/all')
this.$store.dispatch('closeSettingsModal')
this.$store.dispatch('logout')
},

View file

@ -215,7 +215,6 @@ const Status = {
retweeter () { return this.statusoid.user.name || this.statusoid.user.screen_name_ui },
retweeterHtml () { return this.statusoid.user.name },
retweeterProfileLink () { return this.generateUserProfileLink(this.statusoid.user.id, this.statusoid.user.screen_name) },
retweeterVisibility () { return this.statusoid.visibility },
status () {
if (this.retweet) {
return this.statusoid.retweeted_status
@ -441,9 +440,6 @@ const Status = {
visibilityLocalized () {
return this.$i18n.t('general.scope_in_timeline.' + this.status.visibility)
},
retweeterVisibilityLocalized () {
return this.$i18n.t('general.scope_in_timeline.' + this.statusoid.visibility)
},
isEdited () {
return this.status.edited_at !== null
},

View file

@ -42,6 +42,10 @@
display: flex;
padding: var(--status-margin, $status-margin);
.content {
overflow: hidden;
}
> * {
min-width: 0;
}

View file

@ -113,18 +113,6 @@
/>
{{ $t('timeline.repeated') }}
</div>
<span
v-if="retweeterVisibility"
class="visibility-icon"
:title="retweeterVisibilityLocalized"
>
<FAIcon
fixed-width
class="fa-scale-110"
:icon="visibilityIcon(retweeterVisibility)"
/>
</span>
</div>
</div>

View file

@ -41,7 +41,6 @@
-webkit-mask-composite: xor;
mask-composite: exclude;
background-size: cover;
background-position: top;
mask-size: 100% 60%;
border-top-left-radius: calc(var(--panelRadius) - 1px);
border-top-right-radius: calc(var(--panelRadius) - 1px);

View file

@ -666,7 +666,7 @@ const statuses = {
retweet ({ rootState, commit }, status) {
// Optimistic retweeting...
commit('setRetweeted', { status, value: true })
rootState.api.backendInteractor.retweet({ id: status.id, visibility: status.visibility })
rootState.api.backendInteractor.retweet({ id: status.id })
.then(status => commit('setRetweetedConfirm', { status: status.retweeted_status, user: rootState.users.currentUser }))
},
unretweet ({ rootState, commit }, status) {

View file

@ -125,31 +125,21 @@ let fetch = (url, options) => {
}
const promisedRequest = ({ method, url, params, payload, credentials, headers = {} }) => {
const payloadIsFormData = payload instanceof FormData
const options = {
method,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
...headers
}
}
if (!payloadIsFormData) {
// only set content type if payload is not form data
// if it is unset the content type will be automatically set to multipart/form-data
options.headers['Content-Type'] = 'application/json'
}
if (params) {
url += '?' + Object.entries(params)
.map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value))
.join('&')
}
if (payload) {
if (payloadIsFormData) {
options.body = payload
} else {
options.body = JSON.stringify(payload)
}
options.body = JSON.stringify(payload)
}
if (credentials) {
options.headers = {
@ -832,16 +822,8 @@ const unfavorite = ({ id, credentials }) => {
.then((data) => parseStatus(data))
}
const retweet = ({ id, credentials, visibility }) => {
const form = new FormData()
if (visibility) form.append('visibility', visibility)
return promisedRequest({
url: MASTODON_RETWEET_URL(id),
payload: form,
method: 'POST',
credentials
})
const retweet = ({ id, credentials }) => {
return promisedRequest({ url: MASTODON_RETWEET_URL(id), method: 'POST', credentials })
.then((data) => parseStatus(data))
}