Compare commits

..

14 Commits

Author SHA1 Message Date
FloatingGhost 5106fcedd6 Merge branch 'develop' into stable 2023-08-05 13:29:55 +01:00
FloatingGhost 1db322bae6 Merge branch 'develop' into stable 2023-08-05 13:29:26 +01:00
FloatingGhost e530c2b462 Merge branch 'develop' into stable 2023-05-23 14:10:31 +01:00
FloatingGhost 9aa64d82c9 Merge branch 'develop' into stable 2023-04-14 18:10:41 +01:00
FloatingGhost 85abc62213 Merge branch 'develop' into stable 2023-03-11 17:27:22 +00:00
FloatingGhost 8569b5946e Merge branch 'develop' into stable 2023-02-11 10:50:04 +00:00
FloatingGhost 9c9b4cc07c Merge branch 'develop' into stable 2022-12-10 14:52:00 +00:00
floatingghost 2c9b73646c Merge pull request 'hotfix: mfm mysteries' (#215) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/215
2022-11-15 16:01:07 +00:00
floatingghost 80a519d7e4 Merge pull request 'hotfix: translation' (#207) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/207
2022-11-12 19:08:20 +00:00
floatingghost 975f04bf5a Merge pull request '2022.11 stable release' (#202) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/202
2022-11-12 15:33:57 +00:00
floatingghost c8c8d40827 Merge pull request '2022.10 stable' (#177) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/177
2022-10-08 11:13:01 +00:00
floatingghost d7499a1f91 Merge pull request '2022.09 stable' (#160) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/160
2022-09-10 14:39:13 +00:00
floatingghost 5972d89117 Merge pull request 'stable release' (#130) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/130
2022-08-12 15:26:51 +00:00
floatingghost d03872d598 Merge pull request 'port MFM link into stable docs' (#38) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/38
2022-07-15 13:02:06 +00:00
44 changed files with 117 additions and 365 deletions
-1
View File
@@ -1,4 +1,3 @@
platform: linux/amd64
pipeline:
lint:
when:
+2 -2
View File
@@ -22,7 +22,7 @@ To use Akkoma-FE in Akkoma, use the [frontend](https://docs.akkoma.dev/stable/ad
``` bash
# install dependencies
corepack enable
npm install -g yarn
yarn
# serve with hot reload at localhost:8080
@@ -37,7 +37,7 @@ npm run unit
# For Contributors:
You can create file `/config/local.json` (see [example](https://akkoma.dev/AkkomaGang/akkoma-fe/src/branch/develop/config/local.example.json)) to enable some convenience dev options:
You can create file `/config/local.json` (see [example](https://git.pleroma.social/pleroma/pleroma-fe/blob/develop/config/local.example.json)) to enable some convenience dev options:
* `target`: makes local dev server redirect to some existing instance's BE instead of local BE, useful for testing things in near-production environment and searching for real-life use-cases.
* `staticConfigPreference`: makes FE's `/static/config.json` take preference of BE-served `/api/statusnet/config.json`. Only works in dev mode.
+1 -1
View File
@@ -1,4 +1,4 @@
{
"target": "https://otp.akkoma.dev/",
"target": "https://pleroma.soykaf.com/",
"staticConfigPreference": false
}
-3
View File
@@ -70,9 +70,6 @@ Default post formatting option (markdown/bbcode/plaintext/etc...)
### `redirectRootNoLogin`, `redirectRootLogin`
These two settings should point to where FE should redirect visitor when they login/open up website root
### `scopeCopy`
Copy post scope (visibility) when replying to a post. Instance-default.
### `sidebarRight`
Change alignment of sidebar and panels to the right. Defaults to `false`.
+1 -6
View File
@@ -64,11 +64,6 @@ export default {
'-' + this.layoutType
]
},
pageBackground () {
return this.mergedConfig.displayPageBackgrounds
? this.$store.state.users.displayBackground
: null
},
currentUser () { return this.$store.state.users.currentUser },
userBackground () { return this.currentUser.background_image },
instanceBackground () {
@@ -76,7 +71,7 @@ export default {
? null
: this.$store.state.instance.background
},
background () { return this.pageBackground || this.userBackground || this.instanceBackground },
background () { return this.userBackground || this.instanceBackground },
bgStyle () {
if (this.background) {
return {
+1 -1
View File
@@ -8,7 +8,7 @@
}
html {
font-size: 0.875rem;
font-size: 14px;
// overflow-x: clip causes my browser's tab to crash with SIGILL lul
}
-2
View File
@@ -173,10 +173,8 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
copyInstanceOption('redirectRootNoLogin')
copyInstanceOption('redirectRootLogin')
copyInstanceOption('showInstanceSpecificPanel')
copyInstanceOption('minimalScopesMode')
copyInstanceOption('hideMutedPosts')
copyInstanceOption('collapseMessageWithSubject')
copyInstanceOption('scopeCopy')
copyInstanceOption('subjectLineBehavior')
copyInstanceOption('postContentType')
copyInstanceOption('alwaysShowSubjectInput')
+1 -1
View File
@@ -37,7 +37,7 @@
white-space: pre-line;
word-break: break-word;
text-overflow: ellipsis;
overflow: auto;
overflow: scroll;
}
&.-static {
@@ -4,7 +4,6 @@ const FeaturesPanel = {
computed: {
whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled },
mediaProxy: function () { return this.$store.state.instance.mediaProxyAvailable },
minimalScopesMode: function () { return this.$store.state.instance.minimalScopesMode },
textlimit: function () { return this.$store.state.instance.textlimit },
uploadlimit: function () { return fileSizeFormatService.fileSizeFormat(this.$store.state.instance.uploadlimit) }
}
@@ -93,6 +93,9 @@ const MentionLink = {
this.highlightType
]
},
useAtIcon () {
return this.mergedConfig.useAtIcon
},
isRemote () {
return this.userName !== this.userNameFull
},
@@ -151,6 +151,7 @@
>
<Timeago
:time="notification.created_at"
:with-direction="true"
:auto-update="240"
/>
</router-link>
@@ -105,12 +105,9 @@
flex: 1;
padding-left: 0.8em;
min-width: 0;
}
.heading-right, .notification-right {
.timeago {
display: inline-block;
min-width: 6em;
min-width: 3em;
text-align: right;
}
}
@@ -138,7 +138,7 @@ const PostStatusForm = {
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
}
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, interfaceLanguage, alwaysShowSubjectInput } = this.$store.getters.mergedConfig
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, interfaceLanguage } = this.$store.getters.mergedConfig
let statusParams = {
spoilerText: this.subject || '',
@@ -199,10 +199,6 @@ const PostStatusForm = {
}
}
// When first loading the form, hide the subject (CW) field if it's disabled or doesn't have a starting value.
// "disableSubject" seems to take priority over "alwaysShowSubjectInput".
const showSubject = !this.disableSubject && (statusParams.spoilerText || alwaysShowSubjectInput)
return {
dropFiles: [],
uploadingFiles: false,
@@ -217,10 +213,7 @@ const PostStatusForm = {
preview: null,
previewLoading: false,
emojiInputShown: false,
idempotencyKey: '',
activeEmojiInput: undefined,
activeTextInput: undefined,
subjectVisible: showSubject
idempotencyKey: ''
}
},
computed: {
@@ -230,9 +223,6 @@ const PostStatusForm = {
userDefaultScope () {
return this.$store.state.users.currentUser.default_scope
},
showAllScopes () {
return !this.mergedConfig.minimalScopesMode
},
emojiUserSuggestor () {
return suggestor({
emoji: [
@@ -274,9 +264,6 @@ const PostStatusForm = {
isOverLengthLimit () {
return this.hasStatusLengthLimit && (this.charactersLeft < 0)
},
minimalScopesMode () {
return this.$store.state.instance.minimalScopesMode
},
alwaysShowSubject () {
return this.mergedConfig.alwaysShowSubjectInput
},
@@ -687,33 +674,8 @@ const PostStatusForm = {
this.$refs['emoji-input'].resize()
},
showEmojiPicker () {
if (!this.activeEmojiInput || !this.activeTextInput)
this.focusStatusInput()
this.$refs[this.activeTextInput].focus()
this.$refs[this.activeEmojiInput].triggerShowPicker()
},
focusStatusInput() {
this.activeEmojiInput = 'emoji-input'
this.activeTextInput = 'textarea'
},
focusSubjectInput() {
this.activeEmojiInput = 'subject-emoji-input'
this.activeTextInput = 'subject-input'
},
toggleSubjectVisible() {
// If hiding CW, then we need to clear the subject and reset focus
if (this.subjectVisible)
{
this.focusStatusInput()
// "nsfw" property is normally set by the @change listener, but this bypasses it.
// We need to clear it manually instead.
this.newStatus.spoilerText = ''
this.newStatus.nsfw = false
}
this.subjectVisible = !this.subjectVisible
this.$refs['textarea'].focus()
this.$refs['emoji-input'].triggerShowPicker()
},
clearError () {
this.error = null
@@ -758,12 +720,10 @@ const PostStatusForm = {
if (this.copyMessageScope === 'direct') {
return this.copyMessageScope
}
if (this.$store.getters.mergedConfig.scopeCopy) {
if (this.copyMessageScope !== 'public' && this.$store.state.users.currentUser.default_scope !== 'private') {
return this.copyMessageScope
}
}
}
return this.$store.state.users.currentUser.default_scope
}
}
@@ -118,16 +118,13 @@
/>
</div>
<EmojiInput
ref="subject-emoji-input"
v-if="subjectVisible"
v-if="!disableSubject && (newStatus.spoilerText || alwaysShowSubject)"
v-model="newStatus.spoilerText"
enable-emoji-picker
hide-emoji-button
:suggest="emojiSuggestor"
class="form-control"
>
<input
ref="subject-input"
v-model="newStatus.spoilerText"
type="text"
:placeholder="$t('post_status.content_warning')"
@@ -135,7 +132,6 @@
size="1"
class="form-post-subject"
@input="onSubjectInput"
@focus="focusSubjectInput()"
>
</EmojiInput>
<i18n-t
@@ -177,7 +173,6 @@
@input="resize"
@compositionupdate="resize"
@paste="paste"
@focus="focusStatusInput()"
/>
<p
v-if="hasStatusLengthLimit"
@@ -193,7 +188,6 @@
>
<scope-selector
v-if="!disableVisibilitySelector"
:show-all="showAllScopes"
:user-default="userDefaultScope"
:original-scope="copyMessageScope"
:initial-scope="newStatus.visibility"
@@ -282,15 +276,6 @@
>
<FAIcon icon="poll-h" />
</button>
<button
v-if="!disableSubject"
class="spoiler-icon button-unstyled"
:class="{ selected: subjectVisible }"
:title="$t('post_status.toggle_content_warning')"
@click="toggleSubjectVisible"
>
<FAIcon icon="eye-slash" />
</button>
</div>
<button
v-if="posting"
@@ -471,7 +456,7 @@
}
}
.media-upload-icon, .poll-icon, .emoji-icon, .spoiler-icon {
.media-upload-icon, .poll-icon, .emoji-icon {
font-size: 1.85em;
line-height: 1.1;
flex: 1;
@@ -514,11 +499,6 @@
.poll-icon {
order: 3;
justify-content: center;
}
.spoiler-icon {
order: 4;
justify-content: right;
}
@@ -13,6 +13,14 @@ library.add(
faLockOpen
)
const SCOPE_LEVELS = {
'direct': 0,
'private': 1,
'local': 2,
'unlisted': 2,
'public': 3
}
const ScopeSelector = {
props: [
'showAll',
@@ -57,11 +65,15 @@ const ScopeSelector = {
},
methods: {
shouldShow (scope) {
return this.showAll ||
this.currentScope === scope ||
this.originalScope === scope ||
this.userDefault === scope ||
scope === 'direct'
if (!this.originalScope) {
return true
}
if (this.originalScope === 'local') {
return scope === 'direct' || scope === 'local'
}
return SCOPE_LEVELS[scope] <= SCOPE_LEVELS[this.originalScope]
},
changeVis (scope) {
this.currentScope = scope
@@ -146,11 +146,6 @@
{{ $t('settings.show_wider_shortcuts') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="displayPageBackgrounds">
{{ $t('settings.show_page_backgrounds') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }}
@@ -488,6 +483,14 @@
</BooleanSetting>
</li>
</ul>
<li>
<BooleanSetting
path="useAtIcon"
expert="1"
>
{{ $t('settings.use_at_icon') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="mentionLinkShowAvatar">
{{ $t('settings.mention_link_show_avatar') }}
@@ -542,18 +545,12 @@
{{ $t('settings.default_vis') }} <ServerSideIndicator :server-side="true" />
<ScopeSelector
class="scope-selector"
:show-all="true"
:user-default="serverSide_defaultScope"
:initial-scope="serverSide_defaultScope"
:on-scope-change="changeDefaultScope"
/>
</label>
</li>
<li>
<BooleanSetting path="minimalScopesMode">
{{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="sensitiveByDefault">
{{ $t('settings.sensitive_by_default') }}
@@ -564,14 +561,6 @@
{{ $t('settings.sensitive_if_subject') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="scopeCopy"
expert="1"
>
{{ $t('settings.scope_copy') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="alwaysShowSubjectInput"
@@ -599,14 +588,6 @@
{{ $t('settings.post_status_content_type') }}
</ChoiceSetting>
</li>
<li>
<BooleanSetting
path="minimalScopesMode"
expert="1"
>
{{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="alwaysShowNewPostButton"
@@ -33,7 +33,6 @@ const ProfileTab = {
newName: this.$store.state.users.currentUser.name_unescaped,
newBio: unescape(this.$store.state.users.currentUser.description),
newLocked: this.$store.state.users.currentUser.locked,
newPermitFollowback: this.$store.state.users.currentUser.permit_followback,
newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })),
showRole: this.$store.state.users.currentUser.show_role,
role: this.$store.state.users.currentUser.role,
@@ -136,7 +135,6 @@ const ProfileTab = {
bot: this.bot,
show_role: this.showRole,
status_ttl_days: this.expirePosts ? this.newPostTTLDays : -1,
permit_followback: this.permit_followback,
accepts_direct_messages_from: this.userAcceptsDirectMessagesFrom
/* eslint-enable camelcase */
}
@@ -259,19 +259,6 @@
<BooleanSetting path="serverSide_locked">
{{ $t('settings.lock_account_description') }}
</BooleanSetting>
<ul
class="setting-list suboptions"
:class="[{disabled: !serverSide_locked}]"
>
<li>
<BooleanSetting
path="serverSide_permitFollowback"
:disabled="!serverSide_locked"
>
{{ $t('settings.permit_followback_description') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="serverSide_discoverable">
@@ -1,6 +1,6 @@
import { extractCommit } from 'src/services/version/version.service'
const pleromaFeCommitUrl = 'https://akkoma.dev/lamp/akkoma-fe/commit/'
const pleromaFeCommitUrl = 'https://akkoma.dev/AkkomaGang/pleroma-fe/commit/'
const pleromaBeCommitUrl = 'https://akkoma.dev/AkkomaGang/akkoma/commit/'
const VersionTab = {
+1 -1
View File
@@ -190,7 +190,7 @@
>
<Timeago
:time="status.created_at"
:with-direction="!compact"
:with-direction="true"
:auto-update="60"
/>
</router-link>
+24 -116
View File
@@ -13,7 +13,6 @@ const StillImage = {
return {
stopGifs: this.$store.getters.mergedConfig.stopGifs || window.matchMedia('(prefers-reduced-motion: reduce)').matches,
isAnimated: false,
imageTypeLabel: ''
}
},
computed: {
@@ -40,24 +39,27 @@ const StillImage = {
this.imageLoadError && this.imageLoadError()
},
detectAnimation (image) {
// If there are no file extensions, the mimetype isn't set, and no mediaproxy is available, we can't figure out
// the mimetype of the image.
const hasFileExtension = this.src.split('/').pop().includes('.') // TODO: Better check?
const mediaProxyAvailable = this.$store.state.instance.mediaProxyAvailable
if (!mediaProxyAvailable) {
if (!hasFileExtension && this.mimetype === undefined && !mediaProxyAvailable) {
// It's a bit aggressive to assume all images we can't find the mimetype of is animated, but necessary for
// people in need of reduced motion accessibility. As such, we'll consider those images animated if the user
// agent is set to prefer reduced motion. Otherwise, it'll just be used as an early exit.
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
// Since the canvas and images are not pixel-perfect matching (due to scaling),
// It makes the images jiggle on hover, which is not ideal for accessibility, methinks
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches)
this.isAnimated = true
return
}
this.detectWithoutMediaProxy(image)
} else {
this.detectWithMediaProxy(image)
if (this.mimetype === 'image/gif' || this.src.endsWith('.gif')) {
this.isAnimated = true
return
}
},
detectAnimationWithFetch (image) {
// harmless CORS errors without-- clean console with
if (!mediaProxyAvailable) return
// Animated JPEGs?
if (!(this.src.endsWith('.webp') || this.src.endsWith('.png'))) return
// Browser Cache should ensure image doesn't get loaded twice if cache exists
fetch(image.src, {
referrerPolicy: 'same-origin'
@@ -66,20 +68,12 @@ const StillImage = {
// We don't need to read the whole file so only call it once
data.body.getReader().read()
.then(reader => {
// Ordered from least to most intensive
if (this.isGIF(reader.value)) {
if (this.src.endsWith('.webp') && this.isAnimatedWEBP(reader.value)) {
this.isAnimated = true
this.setLabel('GIF')
return
}
if (this.isAnimatedWEBP(reader.value)) {
if (this.src.endsWith('.png') && this.isAnimatedPNG(reader.value)) {
this.isAnimated = true
this.setLabel('WEBP')
return
}
if (this.isAnimatedPNG(reader.value)) {
this.isAnimated = true
this.setLabel('APNG')
}
})
})
@@ -87,53 +81,6 @@ const StillImage = {
// this.imageLoadError && this.imageLoadError()
})
},
detectWithMediaProxy (image) {
this.detectAnimationWithFetch(image)
},
detectWithoutMediaProxy (image) {
// We'll just assume that gifs and webp are animated
const extension = image.src.split('.').pop().toLowerCase()
if (extension === 'gif') {
this.isAnimated = true
this.setLabel('GIF')
return
}
if (extension === 'webp') {
this.isAnimated = true
this.setLabel('WEBP')
return
}
// Beware the apng! use this if ye dare
// if (extension === 'png') {
// this.isAnimated = true
// this.setLabel('PNG')
// return
// }
// Hail mary for extensionless
if (extension.includes('/')) {
// Don't mind the CORS error barrage
this.detectAnimationWithFetch(image)
}
},
setLabel (name) {
this.imageTypeLabel = name;
},
isGIF (data) {
// I am a perfectly sane individual
//
// GIF HEADER CHUNK
// === START HEADER ===
// 47 49 46 38 ("GIF8")
const gifHeader = [0x47, 0x49, 0x46];
for (let i = 0; i < 3; i++) {
if (data[i] !== gifHeader[i]) {
return false;
}
}
return true
},
isAnimatedWEBP (data) {
/**
* WEBP HEADER CHUNK
@@ -167,54 +114,15 @@ const StillImage = {
const idatPos = str.indexOf('IDAT')
return (str.substring(0, idatPos > 0 ? idatPos : 0).indexOf('acTL') > 0)
},
drawThumbnail() {
const canvas = this.$refs.canvas;
if (!canvas) return;
const context = canvas.getContext('2d');
const image = this.$refs.src;
const parentElement = canvas.parentElement;
// Draw the quick, unscaled version first
context.drawImage(image, 0, 0, parentElement.clientWidth, parentElement.clientHeight);
// Use requestAnimationFrame to schedule the scaling to the next frame
requestAnimationFrame(() => {
// Compute scaling ratio between the natural dimensions of the image and its display dimensions
const scalingRatioWidth = parentElement.clientWidth / image.naturalWidth;
const scalingRatioHeight = parentElement.clientHeight / image.naturalHeight;
// Adjust for high-DPI displays
const ratio = window.devicePixelRatio || 1;
canvas.width = image.naturalWidth * scalingRatioWidth * ratio;
canvas.height = image.naturalHeight * scalingRatioHeight * ratio;
canvas.style.width = `${parentElement.clientWidth}px`;
canvas.style.height = `${parentElement.clientHeight}px`;
context.scale(ratio, ratio);
// Maintain the aspect ratio of the image
const imgAspectRatio = image.naturalWidth / image.naturalHeight;
const canvasAspectRatio = parentElement.clientWidth / parentElement.clientHeight;
let drawWidth, drawHeight;
if (imgAspectRatio > canvasAspectRatio) {
drawWidth = parentElement.clientWidth;
drawHeight = parentElement.clientWidth / imgAspectRatio;
} else {
drawHeight = parentElement.clientHeight;
drawWidth = parentElement.clientHeight * imgAspectRatio;
}
context.clearRect(0, 0, canvas.width, canvas.height); // Clear the previous unscaled image
context.imageSmoothingEnabled = true;
context.imageSmoothingQuality = 'high';
// Draw the good one for realsies
const dx = (parentElement.clientWidth - drawWidth) / 2;
const dy = (parentElement.clientHeight - drawHeight) / 2;
context.drawImage(image, dx, dy, drawWidth, drawHeight);
});
drawThumbnail () {
const canvas = this.$refs.canvas
if (!this.$refs.canvas) return
const image = this.$refs.src
const width = image.naturalWidth
const height = image.naturalHeight
canvas.width = width
canvas.height = height
canvas.getContext('2d').drawImage(image, 0, 0, width, height)
}
},
updated () {
+10 -12
View File
@@ -1,15 +1,9 @@
<template>
<div
ref="still-image"
class="still-image"
:class="{ animated: animated }"
:style="style"
>
<div
v-if="animated && imageTypeLabel"
class="image-type-label">
{{ imageTypeLabel }}
</div>
<canvas
v-if="animated"
ref="canvas"
@@ -63,26 +57,30 @@
}
}
.image-type-label {
&.animated {
&::before {
zoom: var(--_still_image-label-scale, 1);
content: 'gif';
position: absolute;
top: 0.25em;
left: 0.25em;
line-height: 1;
font-size: 0.6em;
font-size: 0.7em;
top: 0.5em;
left: 0.5em;
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;
visibility: var(--_still-image-label-visibility, visible);
}
&.animated {
&:hover canvas {
display: none;
}
&:hover .image-type-label {
&:hover::before {
visibility: var(--_still-image-label-visibility, hidden);
}
+1 -1
View File
@@ -33,7 +33,7 @@
--_avatarShadowBox: var(--avatarStatusShadow);
--_avatarShadowFilter: var(--avatarStatusShadowFilter);
--_avatarShadowInset: var(--avatarStatusShadowInset);
// --_still-image-label-visibility: hidden;
--_still-image-label-visibility: hidden;
display: inline-block;
position: relative;
+4 -12
View File
@@ -97,9 +97,6 @@ const UserProfile = {
followersTabVisible () {
return this.isUs || !this.user.hide_followers
},
favoritesTabVisible () {
return this.isUs || !this.user.hide_favorites
},
currentUser () {
return this.$store.state.users.currentUser
},
@@ -117,14 +114,14 @@ const UserProfile = {
replies: 'replies',
media: 'media'
}
if (this.favoritesTabVisible) timelineTabMap['favorites'] = 'favorites'
// only we can see our own favourites
if (this.isUs) timelineTabMap['favorites'] = 'favorites'
const timeline = timelineTabMap[nextTab]
if (timeline) {
this.stopFetching()
this.$store.dispatch('startFetchingTimeline', { timeline: timeline, userId: nextTab == 'favorites' && this.isUs ? null : this.userId })
this.$store.dispatch('startFetchingTimeline', { timeline: timeline, userId: this.userId })
}
},
load (userNameOrId) {
@@ -148,12 +145,10 @@ const UserProfile = {
if (user) {
loadById(user.id)
this.note = user.relationship.note
this.$store.dispatch('setDisplayBackground', user.background_image)
} else {
this.$store.dispatch('fetchUser', userNameOrId)
.then(({ id, relationship, background_image }) => {
.then(({ id, relationship }) => {
this.note = relationship.note
this.$store.dispatch('setDisplayBackground', background_image)
return loadById(id)
})
.catch((reason) => {
@@ -230,9 +225,6 @@ const UserProfile = {
Conversation,
RichContent,
FollowedTagList
},
beforeRouteLeave(to, from) {
this.$store.dispatch('setDisplayBackground', null)
}
}
+2 -2
View File
@@ -165,14 +165,14 @@
:footer-slipgate="footerRef"
/>
<Timeline
v-if="favoritesTabVisible"
v-if="isUs"
key="favorites"
:label="$t('user_card.favorites')"
:disabled="!isUs"
:embedded="true"
:title="$t('user_card.favorites')"
timeline-name="favorites"
:timeline="favorites"
:user-id="isUs ? undefined : userId"
:in-profile="true"
:footer-slipgate="footerRef"
/>
+1
View File
@@ -884,6 +884,7 @@
"upload_a_photo": "Pujar una foto",
"useStreamingApi": "Rebre apunts i notificacions en temps real",
"useStreamingApiWarning": "És genial emprar-lo. Si es trenca, refresca, suposo?",
"use_at_icon": "Mostra el símbol {'@'} com a icona enlloc de text",
"use_contain_fit": "No retallar els adjunts en miniatures",
"use_one_click_nsfw": "Obre els adjunts NSFW amb només un clic",
"user_mutes": "Usuaris",
+1
View File
@@ -916,6 +916,7 @@
"upload_a_photo": "Lade ein Foto hoch",
"useStreamingApi": "Empfange Posts und Benachrichtigungen in Echtzeit",
"useStreamingApiWarning": "(Nicht empfohlen, experimentell, bekannt dafür, Posts zu überspringen)",
"use_at_icon": "{'@'}-Symbol als Icon und nicht als Text anzeigen",
"use_blurhash": "Blurhash für NSFW-Vorschauen verwenden",
"use_contain_fit": "Vorschaubilder nicht zuschneiden",
"use_one_click_nsfw": "Heikle Anhänge mit nur einem Klick öffnen",
+1 -3
View File
@@ -380,7 +380,6 @@
"text/x.misskeymarkdown": "MFM"
},
"content_warning": "Content Warning (optional)",
"toggle_content_warning": "Toggle content warning",
"default": "Just arrived at Luna Nova Academy",
"direct_warning_to_all": "This post will be visible to all the mentioned users.",
"direct_warning_to_first_only": "This post will only be visible to the mentioned users at the beginning of the message.",
@@ -601,7 +600,6 @@
"list_aliases_error": "Error fetching aliases: {error}",
"list_backups_error": "Error fetching backup list: {error}",
"lock_account_description": "Restrict your account to approved followers only",
"permit_followback_description": "Automatically approve requests from already followed users",
"loop_video": "Loop videos",
"loop_video_silent_only": "Loop only videos without sound (i.e. Mastodon's \"gifs\")",
"mascot": "Mastodon FE Mascot",
@@ -751,7 +749,6 @@
"show_nav_shortcuts": "Show extra navigation shortcuts in top panel",
"show_panel_nav_shortcuts": "Show timeline navigation shortcuts at the top of the panel",
"show_scrollbars": "Show side column's scrollbars",
"show_page_backgrounds": "Show page-specific backgrounds, e.g. for user profiles",
"show_wider_shortcuts": "Show wider gap between top panel shortcuts",
"show_yous": "Show (You)s",
"stop_gifs": "Pause animated images until you hover on them",
@@ -925,6 +922,7 @@
"upload_a_photo": "Upload a photo",
"useStreamingApi": "Receive posts and notifications real-time",
"useStreamingApiWarning": "It's cool use it. If it breaks refresh I guess?",
"use_at_icon": "Display {'@'} symbol as an icon instead of text",
"use_contain_fit": "Don't crop the attachment in thumbnails",
"use_one_click_nsfw": "Open NSFW attachments with just one click",
"user_mutes": "Users",
+1
View File
@@ -920,6 +920,7 @@
"upload_a_photo": "Envoyer une photo",
"useStreamingApi": "Recevoir les messages et notifications en temps réel",
"useStreamingApiWarning": "(Non recommandé, expérimental, connu pour rater des messages)",
"use_at_icon": "Afficher le symbol {'@'} comme une image",
"use_contain_fit": "Ne pas rogner les miniatures des pièces-jointes",
"use_one_click_nsfw": "Ouvrir les pièces-jointes sensibles avec un seul clic",
"user_mutes": "Comptes",
+1
View File
@@ -921,6 +921,7 @@
"upload_a_photo": "画像をアップロード",
"useStreamingApi": "投稿と通知を、すぐに受け取る",
"useStreamingApiWarning": "(実験中で、投稿を取りこぼすかもしれないので、おすすめしません)",
"use_at_icon": "{'@'}マークをアイコンにする",
"use_contain_fit": "画像のサムネイルを、切り抜かない",
"use_one_click_nsfw": "NSFWなファイルを1クリックで開く",
"user_mutes": "ユーザー",
-2
View File
@@ -21,7 +21,6 @@ const loaders = {
ga: () => import('./ga.json'),
he: () => import('./he.json'),
hu: () => import('./hu.json'),
id: () => import('./id.json'),
it: () => import('./it.json'),
ja: () => import('./ja_pedantic.json'),
ja_easy: () => import('./ja_easy.json'),
@@ -36,7 +35,6 @@ const loaders = {
sk: () => import('./sk.json'),
te: () => import('./te.json'),
uk: () => import('./uk.json'),
vi: () => import('./vi.json'),
zh: () => import('./zh.json'),
zh_Hant: () => import('./zh_Hant.json')
}
+1
View File
@@ -918,6 +918,7 @@
"upload_a_photo": "Foto uploaden",
"useStreamingApi": "Berichten en meldingen in real-time ontvangen",
"useStreamingApiWarning": "Iets experimenteels met berichten streamen uwu miss kun je beter uit laten ofzo?",
"use_at_icon": "{'@'} symbool als icoon tonen in plaats van tekst",
"use_blurhash": "Waas tonen over NSFW-miniaturen",
"use_contain_fit": "Bijlage in miniaturen niet bijsnijden",
"use_one_click_nsfw": "Gevoelige bijlagen met slechts één klik openen",
+1
View File
@@ -922,6 +922,7 @@
"upload_a_photo": "Вивантажити фото",
"useStreamingApi": "Отримувати дописи та сповіщення наживо",
"useStreamingApiWarning": "Загалом працює. Якщо не зовсім, спробуєте оновити сторінку?",
"use_at_icon": "Значок {'@'} замість символу",
"use_blurhash": "Показувати дражливі мініатюри (як розмиті кольори)",
"use_contain_fit": "Не обрізати краї мініатюр",
"use_one_click_nsfw": "Відкривати NSFW вкладення одним кліком миші",
+1
View File
@@ -922,6 +922,7 @@
"upload_a_photo": "上传照片",
"useStreamingApi": "实时接收帖文和通知",
"useStreamingApiWarning": "十分炫酷推荐使用。要是崩了试试刷新?",
"use_at_icon": "将 {'@'} 符号显示为图标而不是文本",
"use_blurhash": "对NSFW的缩略图使用模糊处理",
"use_contain_fit": "生成缩略图时不要裁剪附件",
"use_one_click_nsfw": "点击一次以打开工作场所不适宜(NSFW)的附件",
+2 -4
View File
@@ -55,7 +55,6 @@ export const defaultState = {
alwaysShowNewPostButton: false,
autohideFloatingPostButton: false,
pauseOnUnfocused: true,
displayPageBackgrounds: true,
stopGifs: undefined,
replyVisibility: 'all',
thirdColumnMode: 'notifications',
@@ -77,11 +76,9 @@ export const defaultState = {
hideScopeNotice: false,
useStreamingApi: false,
sidebarRight: undefined, // instance default
scopeCopy: undefined, // instance default
subjectLineBehavior: undefined, // instance default
alwaysShowSubjectInput: undefined, // instance default
postContentType: undefined, // instance default
minimalScopesMode: undefined, // instance default
// This hides statuses filtered via a word filter
hideFilteredStatuses: undefined, // instance default
modalOnRepeat: undefined, // instance default
@@ -98,6 +95,7 @@ export const defaultState = {
disableStickyHeaders: false,
showScrollbars: false,
greentext: undefined, // instance default
useAtIcon: undefined, // instance default
mentionLinkDisplay: undefined, // instance default
mentionLinkShowTooltip: undefined, // instance default
mentionLinkShowAvatar: undefined, // instance default
@@ -231,7 +229,7 @@ const config = {
break
case 'interfaceLanguage':
messages.setLanguage(this.getters.i18n, value)
Cookies.set(BACKEND_LANGUAGE_COOKIE_NAME, localeService.internalToBackendLocale(value), {sameSite: 'Lax'})
Cookies.set(BACKEND_LANGUAGE_COOKIE_NAME, localeService.internalToBackendLocale(value))
dispatch('setInstanceOption', { name: 'interfaceLanguage', value })
break
case 'thirdColumnMode':
+1 -2
View File
@@ -21,6 +21,7 @@ const defaultState = {
background: '/static/aurora_borealis.jpg',
collapseMessageWithSubject: true,
greentext: false,
useAtIcon: false,
mentionLinkDisplay: 'short',
mentionLinkShowTooltip: true,
mentionLinkShowAvatar: false,
@@ -52,12 +53,10 @@ const defaultState = {
logoMargin: '.2em',
logoMask: true,
logoLeft: false,
minimalScopesMode: false,
nsfwCensorImage: undefined,
postContentType: 'text/plain',
redirectRootLogin: '/main/friends',
redirectRootNoLogin: '/main/all',
scopeCopy: true,
showFeaturesPanel: true,
showInstanceSpecificPanel: false,
showNavShortcuts: true,
+2 -9
View File
@@ -37,18 +37,11 @@ const recentEmojis = {
getters: {
recentEmojis: (state, getters, rootState) => state.emojis.reduce((objects, displayText) => {
let comparator = emoji => emoji.displayText === displayText
let emojiObject = rootState.instance.emoji.find(comparator)
if (emojiObject !== undefined) {
objects.push(emojiObject)
} else {
emojiObject = rootState.instance.customEmoji.find(comparator)
const allEmojis = rootState.instance.emoji.concat(rootState.instance.customEmoji)
let emojiObject = allEmojis.find(emoji => emoji.displayText === displayText)
if (emojiObject !== undefined) {
objects.push(emojiObject)
}
}
return objects
}, []),
},
-4
View File
@@ -47,10 +47,6 @@ export const settingsMap = {
},
// Privacy
'locked': 'locked',
'permitFollowback': {
get: 'akkoma.permit_followback',
set: 'permit_followback'
},
'allowFollowingMove': {
get: 'pleroma.allow_following_move',
set: 'allow_following_move'
+1 -1
View File
@@ -314,7 +314,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
})
// Keep the visible statuses sorted
if (timeline && !(['favorites', 'publicFavorites', 'bookmarks'].includes(timeline))) {
if (timeline && !(timeline === 'bookmarks')) {
sortTimeline(timelineObject)
}
}
-9
View File
@@ -135,10 +135,6 @@ export const mutations = {
const user = state.usersObject[id]
user['deactivated'] = deactivated
},
setDisplayBackground(state, url) {
console.log("Commiting user profile bg mutation")
state.displayBackground = url
},
setCurrentUser (state, user) {
state.lastLoginName = user.screen_name
state.currentUser = mergeWith(state.currentUser || {}, user, mergeArrayLength)
@@ -311,7 +307,6 @@ export const defaultState = {
currentUser: false,
users: [],
usersObject: {},
displayBackground: null,
signUpPending: false,
signUpErrors: [],
relationships: {},
@@ -324,10 +319,6 @@ const users = {
mutations,
getters,
actions: {
setDisplayBackground (store, url) {
console.log("Performing user profile bg action...")
store.commit('setDisplayBackground', url)
},
fetchUserIfMissing (store, id) {
if (!store.getters.findUser(id)) {
store.dispatch('fetchUser', id)
-6
View File
@@ -107,7 +107,6 @@ const PLEROMA_ANNOUNCEMENTS_URL = '/api/v1/pleroma/admin/announcements'
const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements'
const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_USER_FAVORITES_TIMELINE_URL = id => `/api/v1/pleroma/accounts/${id}/favourites`
const AKKOMA_SETTING_PROFILE_URL = (name) => `/api/v1/akkoma/frontend_settings/pleroma-fe/${name}`
const AKKOMA_SETTING_PROFILE_LIST = `/api/v1/akkoma/frontend_settings/pleroma-fe`
const MASTODON_TAG_URL = (name) => `/api/v1/tags/${name}`
@@ -710,7 +709,6 @@ const fetchTimeline = ({
media: MASTODON_USER_TIMELINE_URL,
list: MASTODON_LIST_TIMELINE_URL,
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
publicFavorites: PLEROMA_USER_FAVORITES_TIMELINE_URL,
tag: MASTODON_TAG_TIMELINE_URL,
bookmarks: MASTODON_BOOKMARK_TIMELINE_URL
}
@@ -719,10 +717,6 @@ const fetchTimeline = ({
let url = timelineUrls[timeline]
if (timeline === 'favorites' && userId) {
url = timelineUrls.publicFavorites(userId)
}
if (timeline === 'user' || timeline === 'media' || timeline === 'replies') {
url = url(userId)
}
@@ -95,7 +95,6 @@ export const parseUser = (data) => {
if (data.akkoma) {
output.instance = data.akkoma.instance
output.status_ttl_days = data.akkoma.status_ttl_days
output.permit_followback = data.akkoma.permit_followback
}
if (data.pleroma) {
@@ -110,7 +109,6 @@ export const parseUser = (data) => {
output.allow_following_move = data.pleroma.allow_following_move
output.hide_favorites = data.pleroma.hide_favorites
output.hide_follows = data.pleroma.hide_follows
output.hide_followers = data.pleroma.hide_followers
output.hide_follows_count = data.pleroma.hide_follows_count
+1 -24
View File
@@ -8,30 +8,7 @@ const specialLanguageCodes = {
'zh': 'zh-Hans'
}
// Find a browser language that matches the configured UI language.
// Browser language should match the configured generic short code prefix:
// eg 'en-GB' browser language matches 'en' UI language.
const findBrowserRegionMatch = genericLang => {
for (const blang of window.navigator.languages) {
if (genericLang === blang.split('-')[0])
return blang;
}
return null;
}
const internalToBrowserLocale = (() => {
const resolvedBrowserLocales = {}
return i18nLocale => {
if (resolvedBrowserLocales[i18nLocale]) {
return resolvedBrowserLocales[i18nLocale]
}
const lang = specialLanguageCodes[i18nLocale] || i18nLocale;
const resolved = findBrowserRegionMatch(lang) || lang;
resolvedBrowserLocales[i18nLocale] = resolved
return resolved
}
})()
const internalToBrowserLocale = code => specialLanguageCodes[code] || code
const internalToBackendLocale = code => internalToBrowserLocale(code).replace('_', '-')
-2
View File
@@ -13,12 +13,10 @@
"logoMargin": ".1em",
"logoMask": true,
"logoLeft": false,
"minimalScopesMode": false,
"nsfwCensorImage": "",
"postContentType": "text/plain",
"redirectRootLogin": "/main/friends",
"redirectRootNoLogin": "/main/all",
"scopeCopy": true,
"showFeaturesPanel": true,
"showInstanceSpecificPanel": false,
"sidebarRight": false,