Compare commits

...

61 commits

Author SHA1 Message Date
9bdec82db7 merge in the changes made to upstream (Hopefully didn't break anything)' (#1) 2025-03-12 05:50:36 +01:00
4a4644d42f
fix styling to be more in line with how akkoma-fe used to look before #403 in upstream 2025-03-12 00:44:58 -04:00
79ef3f87e5
fixes to make settings page load after merge 2025-03-12 00:01:02 -04:00
7c0df5cf0e
Merge remote-tracking branch 'upstream/develop' into iceshrimp-merged 2025-03-11 23:42:45 -04:00
Floatingghost
2914eaf1ca Revert "reduce gallery size"
This reverts commit 06ba190e2e.
2025-03-01 16:14:55 +00:00
floatingghost
0bf9cb0660 Merge pull request 'Optional widened main column' (#402) from Riedler/akkoma-fe:wide-columns-for-upstream into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/402
2025-03-01 12:00:33 +00:00
floatingghost
65cb3b95e0 Merge pull request 'Use FEP-c16b: Formatting MFM functions' (#410) from ilja/akkoma-fe:use_fep-c16b_formatting_mfm_functions into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/410
2025-02-27 12:04:41 +00:00
Riedler
f15b94d566 made widenTimeline false by default 2025-02-07 03:50:44 +01:00
Riedler
06ba190e2e reduce gallery size 2025-02-07 03:49:57 +01:00
floatingghost
2086522d64 Merge pull request '(arguably) improved layouting of user profile page' (#403) from Riedler/akkoma-fe:user-profile-changes into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/403
2025-01-15 21:47:55 +00:00
Weblate
fa294e0003 Merge branch 'origin/develop' into Weblate. 2025-01-05 15:52:29 +00:00
floatingghost
d3fa5cfad0 Merge pull request 'post_status_form: enable sync flush for watcher' (#414) from novenary/akkoma-fe:sticky-drafts into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/414
2025-01-05 15:52:26 +00:00
Weblate
9552287442 Merge branch 'origin/develop' into Weblate. 2025-01-05 15:52:19 +00:00
floatingghost
6b7c8f0def Merge pull request 'Allow using custom source URLs' (#421) from Oneric/akkoma-fe:custom-source into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/421
2025-01-05 15:52:15 +00:00
Weblate
3386692e26 Merge branch 'origin/develop' into Weblate. 2025-01-05 15:51:50 +00:00
floatingghost
ad6bb47003 Merge pull request 'Add visual feedback when clicking translate' (#423) from ilja/akkoma-fe:provide_visual_feedback_when_clicking_translate_button into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/423
2025-01-05 15:51:47 +00:00
ilja
9838545904 Add visual feedback when clicking translate
In a status, we can choose to translate the status (assuming there's a translator enabled on the backend)

It will translate, in practice generally according to detected language, and also provide an option to override the source language.

Translating can take a while, and there wasn't really a visual feedback when it was translating.
Now the translate button will be dissabled while translating.
2024-12-01 14:04:49 +01:00
ilja space
868c6e41ac Improve readability for MFM styles code
The code to turn mdm-data-* attributes into a value for the style attribute is complex.
I wrapped it in it's own function now for better code readability.
A comment was already provided with what the code intents to do and why, this information has also been moved
to this function.
2024-12-01 12:24:23 +01:00
Weblate
b3f25e5d84 Translated using Weblate (Polish)
Currently translated at 99.7% (1046 of 1049 strings)

Translated using Weblate (Polish)

Currently translated at 99.7% (1046 of 1049 strings)

Co-authored-by: ? <akkoma@mkljczk.pl>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: subtype <subtype@hollow.capital>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/pl/
Translation: Pleroma fe/pleroma-fe
2024-11-22 04:56:24 +00:00
Weblate
248509073e Translated using Weblate (Italian)
Currently translated at 93.8% (985 of 1049 strings)

Co-authored-by: Steffo <akkoma@steffo.eu>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/it/
Translation: Pleroma fe/pleroma-fe
2024-11-22 04:56:24 +00:00
Weblate
a7d6235131 Translated using Weblate (Lithuanian)
Currently translated at 8.1% (86 of 1049 strings)

Translated using Weblate (Lithuanian)

Currently translated at 5.5% (58 of 1049 strings)

Translated using Weblate (Lithuanian)

Currently translated at 1.9% (20 of 1049 strings)

Added translation using Weblate (Lithuanian)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/lt/
Translation: Pleroma fe/pleroma-fe
2024-11-22 04:56:24 +00:00
ilja space
177d96f977 Improve how scaling is done
During code review a much better way was pointed out to do the emoji scaling, by using `em`.

*key uses 2em for emoji, which is smaller than Akkoma has. I now kept the 38px for Akkoma,
but when "zoom" (ie x2, x3, x4, tada) happens, we set to 2em and zoom from there.
2024-11-01 14:25:22 +01:00
Oneric
42ba77ebf4 Allow using custom source URLs 2024-10-26 16:32:14 +02:00
floatingghost
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: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/422
2024-10-26 03:42:48 +00:00
floatingghost
c76dc6d79e Merge pull request 'Fix redirect on logout' (#420) from Oneric/akkoma-fe:logout-redirect into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/420
2024-10-26 03:42:23 +00:00
floatingghost
cb4c581cde Merge pull request 'Add proper autocomplete prop for TOTP login field' (#424) from tudbut/akkoma-fe:develop into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/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
novenary
ef242a1ddd post_status_form: enable sync flush for watcher
This fixes drafts not clearing after posting a reply.

Vue 3.3.11 changed watchers to stop firing after component unmount.
After posting a reply, the post form is removed, now causing the queued
event to be discarded.
Synchronous flush causes the handler to be called immediately when
changes happen, solving the problem.

The performance impact of this change seems non-existent. Even before,
typing would generate an event for each keystroke. Pasting is atomic.

See: https://github.com/vuejs/core/pull/7181
See: 80e2128d52
Fixes: a7dea2f70f
Fixes: #413
2024-10-15 00:16:45 +03:00
tea
35cf3327c8 fix panel z-index conflicting with heading popover
resolves #342
2024-10-05 10:59:46 +02:00
Oneric
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
ilja
25681cf5f6 Don't require # in the data-mfm-color attribute
For colour in MFM attributes, we expected a `#`, but that's apparently wrong. The BE
translates the `color` attribute in `$[fg.color=000 text]` into `data-mfm-color=000`.
But for the SCSS to work, we need to put it in the style attribute as `--mfm-color: #000`.

Generally we just add the attribute value as-is in the `style` attribute, but now we
have a special exception for color so we add a `#` before the value.
2024-08-18 15:48:22 +02:00
ilja
6666a273a4 MFM only use sanitised data-* attribute values
We take the value from a data-* attribute and then add this to the style attribute.
This will probably be OK in most cases, but just to be sure, we check for "weird" characters first.
For now we only allow letters, numbers, dot, hash, and plus and minus sign, because those are the ones I currently know of who are used in MFM.
The data-* attribute remains because it was already considered proper HTML as-is.
2024-08-11 18:11:03 +02:00
ilja
3210873d7f MFM make all supported tags suggested
When typing MFM, a sugestor drop-down appears so you can see and/or choose what MFM function to use
The new MFM functions we support have now also been added
2024-08-10 13:55:52 +02:00
ilja
f5f9949253 Fix mfm-position and mfm-scale
The `span`'s needed an inline-block for the transform to wrok
I also added an `overflow: hidden;` because these functions can make the text go beyond the borders of the StatusBody
With `overflow: hidden;`, it won't show outside of the borders
2024-08-10 13:13:47 +02:00
ilja
ba4ae5badb Fix MFM functions x2, x3, and x4
These now work for the new, FEP-c16b compliant, representation
Nesting also works

It already worked for text and "normal" emoji, but now it also works for custom emoji
2024-08-10 12:45:37 +02:00
ilja
56a59e1b55 fill in data-mfm- variables
Things like `speed=0.1s` now work

I also noticed a class was set on StatusBody, but we don't use it, we use StatusContent.
Therefor I removed it now.

We do still pass the setting through StatusBody to RichContent bc it's used there to decide to not show greentext for arrows when MFM was used.
Note that while this setting still works
* You have to refresh the page to see it working (was already like this, so I didn't touch it here)
* It explicitly checks for content type. If womeone provides MFM-like HTML, then it will still show as greentext if that option is enabled
  I think it's a bit inconsistent, but otoh, the inconsistency to me seems more that we ignore the greentext option for one input type specifically

I do still notice generall bugs with MFM.
* Position doesn't seem to work, neither does scale.
* There also seems to be a regression where custom emojis don't become larger any more with e.g. `$[x2 :hehe: ]`

I don't assume the regression is made in this commit, so I add this already. The rest needs to be fixed before merging.
2024-08-05 17:23:15 +02:00
ilja
3065416c93 Make new SCSS work for non-variables
The SCSS that we took from Foundkey in a previous commit, is now working
The settings for disabling MFM or only show animation on hover are working
The previous representation also works and it's clearly marked in the code what is legacy
All the MFM SCSS is now located in one file specifically for MFM, ./src/components/status_content/mfm.scss

This is only SCSS:
* The variables who are provided as data-attributes are not working yet
* `sparkle` also doesn't work
2024-08-04 19:10:25 +02:00
Johann150
94141dcb3c Message from commiter: Add Foundkey MFM stylesheet
This is part of a bigger work to fix MFM in Akkoma
See <https://akkoma.dev/AkkomaGang/akkoma/issues/381>

Here we add the MFM stylesheet as it is used by Foundkey
See <b22e627089>

Foundkey uses MFM and both the Founkey and Akkoma projects and communities, have historically been closely related
As such it makes sense to start with feature-parity with Foundkey

This commit only adds the stylesheet so that correct attribution is given
Properly integrating and making it work will happen in later commits
2024-08-04 17:55:32 +02:00
ilja
92e278d406 Move MFM SCSS to separate SCSS
MFM was defined in three places.
There was ./src/components/status_body/status_body.scss => I moved this to ./src/components/status_content/mfm.scss
There was ./src/components/status_content/status_content.vue => I moved this to ./src/components/status_content/mfm.scss
There's ./static/mfm.css => I kept this as-is

./src/components/status_content/mfm.scss is now being loaded in ./src/components/status_content/status_content.vue

I added a comment in both ./src/components/status_content/mfm.scss and ./static/mfm.css referencing each other

Note that this is just a first step in an overhoal of how MFM is handled. It seemed easier to do this as a first step and then build further on that.
2024-08-04 17:44:21 +02:00
RiedleroD
94ed0991bc reverted 2e83ccefdc and clarified that compact user info is only used with enough room 2024-07-06 14:54:24 +02:00
RiedleroD
e955eb4503 oops, unfucked username placement 2024-07-03 18:58:50 +02:00
RiedleroD
c39d9fa64b fixed stuff overflowing in user popup e.g. in notifs 2024-07-03 18:30:51 +02:00
RiedleroD
a74a631793 stopped user handle from overflowing from its boundaries in user card 2024-07-03 17:45:40 +02:00
RiedleroD
2e83ccefdc disabled "compact user info" setting in mobile layout 2024-07-03 17:35:13 +02:00
RiedleroD
cf11b2523e disabled compact user card in mobile layout 2024-07-03 17:26:09 +02:00
RiedleroD
85001814a2 added setting for user info compactness 2024-06-26 18:09:13 +02:00
RiedleroD
c902219997 added setting to switch between center and left-aligned user bio 2024-06-26 17:20:50 +02:00
RiedleroD
2e2e87db75 expand underlay to screen edges when TL is widened 2024-06-26 16:43:32 +02:00
RiedleroD
b2af067fd3 reverted visual changes to underlay 2024-06-26 16:39:04 +02:00
RiedleroD
754cd2fa57 slightly adjusted edit button spacing 2024-06-16 17:15:04 +02:00
RiedleroD
31055fb4f2 removed min-width statements that were messing up my layouts 2024-06-16 17:14:59 +02:00
RiedleroD
918b0e3770 stopped username from wrapping… 2024-06-16 17:14:14 +02:00
RiedleroD
88aae1706a oops, removed unneeded spacing 2024-06-16 17:14:08 +02:00
RiedleroD
3d2a8a3ca2 left-aligned bio text
why the fuck was it centered in the first place?!?
2024-06-16 17:14:03 +02:00
RiedleroD
a24fff5d5b moved user stats to between user info and user actions 2024-06-16 17:14:00 +02:00
RiedleroD
4abddf5e6a made wide column layout optional 2024-06-16 16:37:33 +02:00
RiedleroD
1b4df9e79d reverted audio attachments to 4:1 aspect ratio 2024-06-16 16:37:30 +02:00
RiedleroD
45fe334cd7 fixed sizing issues with attachments in some non-status containers 2024-06-16 16:37:26 +02:00
RiedleroD
dd32a33d59 fixed media attachment heights 2024-06-16 16:37:22 +02:00
RiedleroD
74b651a3a2 made attached images max size scale with font size
meta-comment: eliminated corner-case weirdness by replaced cursed CSS with slightly less cursed CSS
2024-06-16 16:37:07 +02:00
RiedleroD
21fe7d76d3 made columns use more space, fixed minor bug 2024-06-16 16:35:46 +02:00
30 changed files with 1135 additions and 532 deletions

View file

@ -6,7 +6,6 @@
<title>Akkoma</title>
<link rel="stylesheet" href="/static/font/tiresias.css">
<link rel="stylesheet" href="/static/font/css/lato.css">
<link rel="stylesheet" href="/static/mfm.css">
<link rel="stylesheet" href="/static/custom.css">
<link rel="stylesheet" href="/static/theme-holder.css" id="theme-holder">
<!--server-generated-meta-->

View file

@ -59,7 +59,8 @@ export default {
{
'-reverse': this.reverseLayout,
'-no-sticky-headers': this.noSticky,
'-has-new-post-button': this.newPostButtonShown
'-has-new-post-button': this.newPostButtonShown,
'-wide-timeline': this.widenTimeline
},
'-' + this.layoutType
]
@ -93,6 +94,9 @@ export default {
newPostButtonShown () {
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile'
},
widenTimeline () {
return this.$store.getters.mergedConfig.widenTimeline
},
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
editingAvailable () { return this.$store.state.instance.editingAvailable },
layoutType () { return this.$store.state.interface.layoutType },

View file

@ -172,6 +172,10 @@ nav {
background-color: rgba(0, 0, 0, 0.15);
background-color: var(--underlay, rgba(0, 0, 0, 0.15));
z-index: -1000;
.-wide-timeline & {
margin:0 calc(var(--columnGap) / -2);
}
}
.app-layout {
@ -187,12 +191,17 @@ nav {
grid-template-rows: 1fr;
box-sizing: border-box;
margin: 0 auto;
padding: 0 calc(var(--columnGap) / 2);
align-content: flex-start;
flex-wrap: wrap;
justify-content: center;
min-height: 100vh;
overflow-x: clip;
&.-wide-timeline {
--maxiColumn: minmax(var(--miniColumn), 1fr);
}
.column {
--___columnMargin: var(--columnGap);
@ -246,6 +255,10 @@ nav {
}
}
&.-scrollable:has(.user-panel) {
padding-left: calc(var(--___paddingIncrease) + var(--___columnMargin) / 999);
}
.panel-heading.-sticky {
top: calc(var(--columnGap) / -1);
}

View file

@ -183,6 +183,12 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
copyInstanceOption('renderMisskeyMarkdown')
copyInstanceOption('sidebarRight')
if (config.backendCommitUrl)
copyInstanceOption('backendCommitUrl')
if (config.frontendCommitUrl)
copyInstanceOption('frontendCommitUrl')
return store.dispatch('setTheme', config['theme'])
}

View file

@ -1,4 +1,4 @@
const MFM_TAGS = ['blur', 'bounce', 'flip', 'font', 'jelly', 'jump', 'rainbow', 'rotate', 'shake', 'sparkle', 'spin', 'tada', 'twitch', 'x2', 'x3', 'x4']
const MFM_TAGS = ['bg', 'blur', 'bounce', 'center', 'fg', 'flip', 'font', 'jelly', 'jump', 'position', 'rainbow', 'rotate', 'scale', 'shake', 'sparkle', 'spin', 'tada', 'twitch', 'x2', 'x3', 'x4']
.map(tag => ({ displayText: tag, detailText: '$[' + tag + ' ]', replacement: '$[' + tag + ' ]', mfm: true }))
/**

View file

@ -88,10 +88,8 @@ const Gallery = {
set(this.sizes, id, { width, height })
},
rowStyle (row) {
if (row.audio) {
return { 'padding-bottom': '25%' } // fixed reduced height for audio
} else if (!row.minimal && !row.grid) {
return { 'padding-bottom': `${(100 / (row.items.length + 0.6))}%` }
if (!row.audio && !row.minimal && !row.grid) {
return { 'aspect-ratio': `1/${(1 / (row.items.length + 0.6))}` }
}
},
itemStyle (id, row) {

View file

@ -96,9 +96,15 @@
.gallery-row {
position: relative;
height: 0;
width: 100%;
flex-grow: 1;
.Status & {
max-height: 30em;
}
&.-audio {
aspect-ratio: 4/1; // this is terrible, but it's how it was before so I'm not changing it >:(
}
&:not(:first-child) {
margin-top: 0.5em;

View file

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

View file

@ -336,6 +336,7 @@ const PostStatusForm = {
watch: {
'newStatus': {
deep: true,
flush: 'sync',
handler () {
this.statusChanged()
}

View file

@ -121,6 +121,19 @@ export default {
}
}
const mfmStyleFromDataAttributes = (attributes) => {
// CSS selectors can check if a data-* attribute is true, but can't use other values, so we want to add them to the style attribute
// Here we turn e.g. `{'data-mfm-some': '1deg', 'data-mfm-thing': '5s'}` to "--mfm-some: 1deg;--mfm-thing: 5s;"
// Note that we only add the value to `style` when they contain only letters, numbers, dot, or minus signs
// At the moment of writing, this should be enough for legitimate purposes and reduces the chance of injection by using special characters
// There is a special case for the `color` value, who is provided without `#`, but requires this in the `style` attribute
return Object.keys(attributes).filter(
(key) => key.startsWith('data-mfm-') && attributes[key] !== true && /^[a-zA-Z0-9.\-]*$/.test(attributes[key])
).map(
(key) => '--mfm-' + key.substr(9) + (key === 'data-mfm-color' ? ': #' : ': ') + attributes[key] + ';'
).reduce((a,v) => a+v, '')
}
// Processor to use with html_tree_converter
const processItem = (item, index, array, what) => {
// Handle text nodes - just add emoji
@ -191,6 +204,15 @@ export default {
if (this.handleLinks && attrs?.['class']?.includes?.('h-card')) {
return ['', children.map(processItem), '']
}
let mfm_style = mfmStyleFromDataAttributes(attrs)
if (mfm_style !== '') {
return [
opener.slice(0,-1) + ' style="' + mfm_style + '">',
children.map(processItem),
closer
]
}
}
if (children !== undefined) {

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

@ -159,6 +159,16 @@
{{ $t('settings.show_page_backgrounds') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="centerAlignBio">
{{ $t('settings.center_align_bio') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="compactUserInfo">
{{ $t('settings.compact_user_info') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }}
@ -269,6 +279,11 @@
{{ $t('settings.right_sidebar') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="widenTimeline">
{{ $t('settings.widen_timeline') }}
</BooleanSetting>
</li>
<li>
<ChoiceSetting
v-if="user"

View file

@ -7,7 +7,9 @@ const VersionTab = {
data () {
const instance = this.$store.state.instance
return {
backendCommitUrl: instance.backendCommitUrl,
backendVersion: instance.backendVersion,
frontendCommitUrl: instance.frontendCommitUrl,
frontendVersion: instance.frontendVersion
}
},

View file

@ -41,7 +41,8 @@ const StatusContent = {
postLength: this.status.text.length,
parseReadyDone: false,
renderMisskeyMarkdown,
translateFrom: null
translateFrom: null,
translating: false
}
},
computed: {
@ -135,7 +136,10 @@ const StatusContent = {
},
translateStatus () {
const translateTo = this.$store.getters.mergedConfig.translationLanguage || this.$store.state.instance.interfaceLanguage
this.$store.dispatch('translateStatus', { id: this.status.id, language: translateTo, from: this.translateFrom })
this.translating = true
this.$store.dispatch(
'translateStatus', { id: this.status.id, language: translateTo, from: this.translateFrom }
).finally(() => { this.translating = false })
}
}
}

View file

@ -3,6 +3,7 @@
.StatusBody {
display: flex;
flex-direction: column;
overflow: hidden;
.translation {
border: 1px solid var(--accent, $fallback--link);
@ -23,24 +24,6 @@
transition: 0.05s;
}
._mfm_x2_ {
.emoji {
height: 100px;
}
}
._mfm_x3_ {
.emoji {
height: 150px;
}
}
._mfm_x4_ {
.emoji {
height: 200px;
}
}
.attachments {
margin-top: 0.5em;
}

View file

@ -1,7 +1,7 @@
<template>
<div
class="StatusBody"
:class="{ '-compact': compact, 'mfm-disabled': !renderMisskeyMarkdown }"
:class="{ '-compact': compact }"
>
<div class="body">
<div
@ -91,6 +91,7 @@
{{ ' ' }}
<button
class="btn button-default"
:disabled="translating"
@click="translateStatus"
>
{{ $t('status.translate') }}

View file

@ -0,0 +1,423 @@
/**
* "FEP-c16b: Formatting MFM functions" attributes that Akkoma supports
*/
.StatusContent:not(.mfm-disabled) {
/* The following are the non-animated MFM */
.mfm-center {
display: block;
text-align: center;
}
.mfm-flip {
display: inline-block;
transform: scaleX(-1);
}
.mfm-flip[data-mfm-v] {
transform: scaleY(-1);
}
.mfm-flip[data-mfm-v][data-mfm-h] {
transform: scale(-1, -1);
}
.mfm-font[data-mfm-serif] {
font-family: serif;
}
.mfm-font[data-mfm-monospace] {
font-family: monospace;
}
.mfm-font[data-mfm-cursive] {
font-family: cursive;
}
.mfm-font[data-mfm-fantasy] {
font-family: fantasy;
}
.mfm-font[data-mfm-emoji] {
font-family: emoji;
}
.mfm-font[data-mfm-math] {
font-family: math;
}
.mfm-blur {
filter: blur(6px);
transition: filter 0.3s;
&:hover {
filter: blur(0);
}
}
.mfm-rotate {
display: inline-block;
transform: rotate(calc(var(--mfm-deg, 90) * 1deg));
transform-origin: center center;
}
.mfm-x2 {
--mfm-zoom-size: 200%;
}
.mfm-x3 {
--mfm-zoom-size: 400%;
}
.mfm-x4 {
--mfm-zoom-size: 600%;
}
.mfm-x2,
.mfm-x3,
.mfm-x4,
.mfm-tada {
.emoji {
--emoji-size: 2em;
}
font-size: var(--mfm-zoom-size);
.mfm-x2,
.mfm-x3,
.mfm-x4,
.mfm-tada {
/* only half effective */
font-size: calc(var(--mfm-zoom-size) / 2 + 50%);
.mfm-x2,
.mfm-x3,
.mfm-x4,
.mfm-tada {
/* disabled */
font-size: 100%;
}
}
}
.mfm-position {
display: inline-block;
transform: translate(calc(var(--mfm-x, 0) * 1em), calc(var(--mfm-y, 0) * 1em));
}
.mfm-scale {
display: inline-block;
transform: scale(var(--mfm-x, 1), var(--mfm-y, 1));
}
.mfm-fg {
color: var(--mfm-color, #f00);
}
.mfm-bg {
background-color: var(--mfm-color, #0f0);
}
/* The following are the animated MFM */
/* .mfm-hover means that we should only play animation when hovering over the StatusContent
* So either StatusContent does not have this class,
* or it has the class and we are hovering over StatusContent
*/
&:not(.mfm-hover:not(:hover)) {
.mfm-jelly {
display: inline-block;
animation: mfm-rubberBand var(--mfm-speed, 1s) linear infinite both;
}
.mfm-twitch {
display: inline-block;
animation: mfm-twitch var(--mfm-speed, 0.5s) ease infinite;
}
.mfm-shake {
display: inline-block;
animation: mfm-shake var(--mfm-speed, 0.5s) ease infinite;
}
.mfm-spin {
display: inline-block;
animation: mfm-spin var(--mfm-speed, 1.5s) linear infinite;
}
.mfm-spin[data-mfm-y] {
animation-name: mfm-spinY;
}
.mfm-spin[data-mfm-x] {
animation-name: mfm-spinX;
}
.mfm-spin[data-mfm-alternate] {
animation-direction: alternate;
}
.mfm-spin[data-mfm-left] {
animation-direction: reverse;
}
.mfm-jump {
display: inline-block;
animation: mfm-jump var(--mfm-speed, 0.75s) linear infinite;
}
.mfm-bounce {
display: inline-block;
animation: mfm-bounce var(--mfm-speed, 0.75s) linear infinite;
transform-origin: center bottom;
}
.mfm-rainbow {
animation: mfm-rainbow var(--mfm-speed, 1s) linear infinite;
}
.mfm-tada {
display: inline-block;
animation: mfm-tada var(--mfm-speed, 1s) linear infinite both;
--mfm-zoom-size: 150%;
}
}
/* animation keyframes */
@keyframes mfm-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes mfm-spinX {
0% { transform: perspective(128px) rotateX(0deg); }
100% { transform: perspective(128px) rotateX(360deg); }
}
@keyframes mfm-spinY {
0% { transform: perspective(128px) rotateY(0deg); }
100% { transform: perspective(128px) rotateY(360deg); }
}
@keyframes mfm-jump {
0% { transform: translateY(0); }
25% { transform: translateY(-16px); }
50% { transform: translateY(0); }
75% { transform: translateY(-8px); }
100% { transform: translateY(0); }
}
@keyframes mfm-bounce {
0% { transform: translateY(0) scale(1, 1); }
25% { transform: translateY(-16px) scale(1, 1); }
50% { transform: translateY(0) scale(1, 1); }
75% { transform: translateY(0) scale(1.5, 0.75); }
100% { transform: translateY(0) scale(1, 1); }
}
@keyframes mfm-twitch {
0% { transform: translate(7px, -2px); }
5% { transform: translate(-3px, 1px); }
10% { transform: translate(-7px, -1px); }
15% { transform: translate(0, -1px); }
20% { transform: translate(-8px, 6px); }
25% { transform: translate(-4px, -3px); }
30% { transform: translate(-4px, -6px); }
35% { transform: translate(-8px, -8px); }
40% { transform: translate(4px, 6px); }
45% { transform: translate(-3px, 1px); }
50% { transform: translate(2px, -10px); }
55% { transform: translate(-7px, 0); }
60% { transform: translate(-2px, 4px); }
65% { transform: translate(3px, -8px); }
70% { transform: translate(6px, 7px); }
75% { transform: translate(-7px, -2px); }
80% { transform: translate(-7px, -8px); }
85% { transform: translate(9px, 3px); }
90% { transform: translate(-3px, -2px); }
95% { transform: translate(-10px, 2px); }
100% { transform: translate(-2px, -6px); }
}
@keyframes mfm-shake {
0% { transform: translate(-3px, -1px) rotate(-8deg); }
5% { transform: translate(0, -1px) rotate(-10deg); }
10% { transform: translate(1px, -3px) rotate(0deg); }
15% { transform: translate(1px, 1px) rotate(11deg); }
20% { transform: translate(-2px, 1px) rotate(1deg); }
25% { transform: translate(-1px, -2px) rotate(-2deg); }
30% { transform: translate(-1px, 2px) rotate(-3deg); }
35% { transform: translate(2px, 1px) rotate(6deg); }
40% { transform: translate(-2px, -3px) rotate(-9deg); }
45% { transform: translate(0, -1px) rotate(-12deg); }
50% { transform: translate(1px, 2px) rotate(10deg); }
55% { transform: translate(0, -3px) rotate(8deg); }
60% { transform: translate(1px, -1px) rotate(8deg); }
65% { transform: translate(0, -1px) rotate(-7deg); }
70% { transform: translate(-1px, -3px) rotate(6deg); }
75% { transform: translate(0, -2px) rotate(4deg); }
80% { transform: translate(-2px, -1px) rotate(3deg); }
85% { transform: translate(1px, -3px) rotate(-10deg); }
90% { transform: translate(1px, 0) rotate(3deg); }
95% { transform: translate(-2px, 0) rotate(-3deg); }
100% { transform: translate(2px, 1px) rotate(2deg); }
}
@keyframes mfm-rubberBand {
0% { transform: scale3d(1, 1, 1); }
30% { transform: scale3d(1.25, 0.75, 1); }
40% { transform: scale3d(0.75, 1.25, 1); }
50% { transform: scale3d(1.15, 0.85, 1); }
65% { transform: scale3d(0.95, 1.05, 1); }
75% { transform: scale3d(1.05, 0.95, 1); }
100% { transform: scale3d(1, 1, 1); }
}
@keyframes mfm-rainbow {
0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); }
100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); }
}
@keyframes mfm-tada {
0%,
100% { transform: scale3d(1, 1, 1); }
10%,
20% { transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); }
30%,
50%,
70%,
90% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); }
40%,
60%,
80% { transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); }
}
/**
* Legacy MFM
* This is for backwards compatibility with posts formatted on Akkoma before support for FEP-c16b
* Note that it uses the keyframes as defined above for the FEP-c16b compatible MFM representation
*/
.mfm {
display: inline-block;
}
/* The following are the legacy non-animated MFM */
._mfm_flip_[data-h][data-v] {
transform: scale(-1, -1);
}
._mfm_flip_[data-v] {
transform: scaleY(-1);
}
._mfm_flip_:not([data-v]) {
transform: scaleX(-1);
}
._mfm_x2_ {
font-size: 200%;
}
._mfm_x3_ {
font-size: 400%;
}
._mfm_x4_ {
font-size: 600%;
}
._mfm_x2_ {
.emoji {
height: 100px;
}
}
._mfm_x3_ {
.emoji {
height: 150px;
}
}
._mfm_x4_ {
.emoji {
height: 200px;
}
}
._mfm_blur_ {
filter: blur(6px);
transition: filter 0.3s;
}
._mfm_blur_:hover {
filter: blur(0);
}
._mfm_rotate_ {
transform: rotate(90deg);
transform-origin: center center;
}
/* The following are the legacy animated MFM */
/* .mfm-hover means that we should only play animation when hovering over the StatusContent
* So either StatusContent does not have this class,
* or it has the class and we are hovering over StatusContent
*/
&:not(.mfm-hover:not(:hover)) {
._mfm_tada_ {
font-size: 150%;
animation: mfm-tada 1s linear infinite both;
}
._mfm_jelly_ {
animation: mfm-rubberBand 1s linear infinite both;
}
._mfm_twitch_ {
animation: mfm-twitch 0.5s ease infinite;
}
._mfm_shake_ {
animation: mfm-shake 0.5s ease infinite;
}
._mfm_spin_ {
animation: mfm-spin 0.5s linear infinite;
}
._mfm_spin_[data-x] {
animation-name: mfm-spinX;
}
._mfm_spin_[data-y] {
animation-name: mfm-spinY;
}
._mfm_spin_[left] {
animation-direction: reverse;
}
._mfm_spin_[alternate] {
animation-direction: alternate;
}
._mfm_jump_ {
animation: mfm-jump 0.75s linear infinite;
}
._mfm_bounce_ {
animation: mfm-bounce 0.75s linear infinite;
transform-origin: center bottom;
}
._mfm_rainbow_ {
animation: mfm-rainbow 1s linear infinite;
}
}
}

View file

@ -64,6 +64,7 @@
</template>
<script src="./status_content.js"></script>
<style lang="scss" src="./mfm.scss" />
<style lang="scss">
.StatusContent {
flex: 1;
@ -75,23 +76,6 @@
height: 50px;
}
}
&.mfm-hover:not(:hover) {
.mfm {
animation: none !important;
}
}
&.mfm-disabled {
span {
font-size: 100% !important;
}
.mfm {
animation: none !important;
}
.emoji {
height: 32px !important;
}
}
}
.quote-inline,

View file

@ -117,6 +117,11 @@ export default {
shouldConfirmMute () {
return this.mergedConfig.modalOnMute
},
compactUserInfo () {
return this.$store.getters.mergedConfig.compactUserInfo
&& (this.$store.state.interface.layoutType !== 'mobile')
&& this.switcher
},
...mapGetters(['mergedConfig'])
},
components: {

View file

@ -21,6 +21,13 @@
position: relative;
}
.user-buttons {
grid-area: edit;
display: flex;
padding: .5em 0 .5em 0;
justify-self: end;
}
.panel-body {
word-wrap: break-word;
border-bottom-right-radius: inherit;
@ -53,7 +60,6 @@
}
&-bio {
text-align: center;
display: block;
line-height: 1.3;
padding: 1em;
@ -100,15 +106,14 @@
padding: 0 26px;
.container {
min-width: 0;
padding: 16px 0 6px;
display: flex;
align-items: flex-start;
max-height: 56px;
> * {
min-width: 0;
}
display: grid;
grid-template-areas:
"pfp name edit"
"pfp summary summary"
"stats stats stats";
grid-template-columns: auto 1fr auto;
align-items: start;
.Avatar {
--_avatarShadowBox: var(--avatarShadow);
@ -123,6 +128,7 @@
}
&-avatar-link {
grid-area: pfp;
position: relative;
cursor: pointer;
@ -153,8 +159,8 @@
.external-link-button, .edit-profile-button {
cursor: pointer;
width: 2.5em;
text-align: center;
width: 2.3em;
text-align: right;
margin: -0.5em 0;
padding: 0.5em 0;
@ -165,69 +171,102 @@
}
.user-summary {
display: block;
grid-area: summary;
display: grid;
grid-template-areas:
"name name name name name"
"hand role lock avg _";
grid-template-columns:
auto auto auto auto 1fr;
justify-items: start;
margin-left: 0.6em;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 0;
// This is so that text doesn't get overlapped by avatar's shadow if it has
// big one
z-index: 1;
line-height: 2em;
margin-top: -0.6em;
--emoji-size: 1.7em;
.top-line,
.bottom-line {
display: flex;
}
}
.user-name {
text-overflow: ellipsis;
overflow: hidden;
flex: 1 1 auto;
margin-right: 1em;
font-size: 1.1em;
}
.bottom-line {
font-weight: light;
font-size: 1.1em;
align-items: baseline;
.lock-icon {
.user-locked {
margin-left: 0.5em;
grid-area: lock;
}
.user-screen-name {
min-width: 1px;
flex: 0 1 auto;
max-width: 100%;
text-overflow: ellipsis;
overflow: hidden;
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
grid-area: hand;
font-size: 1.1em;
}
.dailyAvg {
min-width: 1px;
flex: 0 0 auto;
margin-left: 1em;
font-size: 0.7em;
color: $fallback--text;
color: var(--text, $fallback--text);
grid-area: avg;
}
.user-role {
flex: none;
color: $fallback--text;
color: var(--alertNeutralText, $fallback--text);
background-color: $fallback--fg;
background-color: var(--alertNeutral, $fallback--fg);
.user-roles {
display: flex;
grid-area: role;
.user-role {
color: $fallback--text;
color: var(--alertNeutralText, $fallback--text);
background-color: $fallback--fg;
background-color: var(--alertNeutral, $fallback--fg);
}
}
}
.user-counts {
grid-area: stats;
display: flex;
line-height:16px;
padding-top: 0.5em;
text-align: center;
justify-content: space-around;
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
align-self: center;
.user-count {
padding: .5em 0 .5em 0;
margin: 0 .5em;
h5 {
font-size:1em;
font-weight: bolder;
margin: 0 0 0.25em;
}
a {
text-decoration: none;
}
}
}
.user-name {
text-align: start;
text-overflow: ellipsis;
overflow: hidden;
margin-left: 0.55em;
font-size: 1.1em;
grid-area: name;
align-self: center;
white-space: nowrap;
max-width: 100%;
z-index: 1; // so shadow from user avatar doesn't overlap it
margin-top: -0.5em;
}
.user-meta {
margin-bottom: .15em;
display: flex;
@ -290,34 +329,21 @@
margin: 0;
}
}
&.-compact {
.container {
grid-template-areas:
"pfp name stats edit"
"pfp summary stats edit";
grid-template-columns: auto auto 1fr auto;
}
.user-counts {
padding-top: 0;
justify-content: space-evenly;
}
}
}
.sidebar .edit-profile-button {
display: none;
}
.user-counts {
display: flex;
line-height:16px;
padding: .5em 1.5em 0em 1.5em;
text-align: center;
justify-content: space-between;
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
flex-wrap: wrap;
}
.user-count {
flex: 1 0 auto;
padding: .5em 0 .5em 0;
margin: 0 .5em;
h5 {
font-size:1em;
font-weight: bolder;
margin: 0 0 0.25em;
}
a {
text-decoration: none;
}
}

View file

@ -9,7 +9,10 @@
class="background-image"
/>
<div class="panel-heading -flexible-height">
<div class="user-info">
<div
class="user-info"
:class="{ '-compact': this.compactUserInfo }"
>
<div class="container">
<a
v-if="allowZoomingAvatar"
@ -29,6 +32,7 @@
</a>
<router-link
v-else
class="user-info-avatar-link"
:to="userProfileLink(user)"
>
<UserAvatar
@ -36,15 +40,80 @@
:user="user"
/>
</router-link>
<RichContent
:title="user.name"
class="user-name"
:html="user.name"
:emoji="user.emoji"
/>
<div class="user-summary">
<div class="top-line">
<RichContent
:title="user.name"
class="user-name"
:html="user.name"
:emoji="user.emoji"
<router-link
class="user-screen-name"
:title="user.screen_name_ui"
:to="userProfileLink(user)"
>
@{{ user.screen_name_ui }}
</router-link>
<span class="user-roles" v-if="!hideBio && (user.deactivated || !!visibleRole || user.bot)">
<span
v-if="user.deactivated"
class="alert user-role"
>
{{ $t('user_card.deactivated') }}
</span>
<span
v-if="!!visibleRole"
class="alert user-role"
>
{{ $t(`general.role.${visibleRole}`) }}
</span>
<span
v-if="user.bot"
class="alert user-role"
>
{{ $t('user_card.bot') }}
</span>
</span>
<span class="user-locked" v-if="user.locked">
<FAIcon
class="lock-icon"
icon="lock"
size="sm"
/>
<button
</span>
<span
v-if="!mergedConfig.hideUserStats && !hideBio"
class="dailyAvg"
>{{ dailyAvg }} {{ $t('user_card.per_day') }}</span>
</div>
<div
v-if="!mergedConfig.hideUserStats && switcher"
class="user-counts"
>
<div
class="user-count"
@click.prevent="setProfileView('statuses')"
>
<h5>{{ $t('user_card.statuses') }}</h5>
<span>{{ user.statuses_count }} <br></span>
</div>
<div
class="user-count"
@click.prevent="setProfileView('friends')"
>
<h5>{{ $t('user_card.followees') }}</h5>
<span>{{ hideFollowsCount ? $t('user_card.hidden') : user.friends_count }}</span>
</div>
<div
class="user-count"
@click.prevent="setProfileView('followers')"
>
<h5>{{ $t('user_card.followers') }}</h5>
<span>{{ hideFollowersCount ? $t('user_card.hidden') : user.followers_count }}</span>
</div>
</div>
<div class="user-buttons">
<button
v-if="!isOtherUser && user.is_local"
class="button-unstyled edit-profile-button"
@click.stop="openProfileTab"
@ -83,47 +152,6 @@
:user="user"
:relationship="relationship"
/>
</div>
<div class="bottom-line">
<router-link
class="user-screen-name"
:title="user.screen_name_ui"
:to="userProfileLink(user)"
>
@{{ user.screen_name_ui }}
</router-link>
<template v-if="!hideBio">
<span
v-if="user.deactivated"
class="alert user-role"
>
{{ $t('user_card.deactivated') }}
</span>
<span
v-if="!!visibleRole"
class="alert user-role"
>
{{ $t(`general.role.${visibleRole}`) }}
</span>
<span
v-if="user.bot"
class="alert user-role"
>
{{ $t('user_card.bot') }}
</span>
</template>
<span v-if="user.locked">
<FAIcon
class="lock-icon"
icon="lock"
size="sm"
/>
</span>
<span
v-if="!mergedConfig.hideUserStats && !hideBio"
class="dailyAvg"
>{{ dailyAvg }} {{ $t('user_card.per_day') }}</span>
</div>
</div>
</div>
<div class="user-meta">
@ -278,38 +306,13 @@
v-if="!hideBio"
class="panel-body"
>
<div
v-if="!mergedConfig.hideUserStats && switcher"
class="user-counts"
>
<div
class="user-count"
@click.prevent="setProfileView('statuses')"
>
<h5>{{ $t('user_card.statuses') }}</h5>
<span>{{ user.statuses_count }} <br></span>
</div>
<div
class="user-count"
@click.prevent="setProfileView('friends')"
>
<h5>{{ $t('user_card.followees') }}</h5>
<span>{{ hideFollowsCount ? $t('user_card.hidden') : user.friends_count }}</span>
</div>
<div
class="user-count"
@click.prevent="setProfileView('followers')"
>
<h5>{{ $t('user_card.followers') }}</h5>
<span>{{ hideFollowersCount ? $t('user_card.hidden') : user.followers_count }}</span>
</div>
</div>
<RichContent
v-if="!hideBio"
class="user-card-bio"
:html="user.description_html"
:emoji="user.emoji"
:handle-links="true"
:style='{"text-align": this.$store.getters.mergedConfig.centerAlignBio ? "center" : "start"}'
/>
</div>
<teleport to="#modal">

View file

@ -482,6 +482,7 @@
"blocks_tab": "Blocks",
"bot": "Dies ist ein Bot Account",
"btnRadius": "Knöpfe",
"center_align_bio": "Zentrale Textausrichtung in der Bio",
"cBlue": "Blau (Antworten, folgt dir)",
"cGreen": "Grün (Retweet)",
"cOrange": "Orange (Favorisieren)",
@ -496,6 +497,7 @@
"checkboxRadius": "Auswahlfelder",
"collapse_subject": "Beiträge mit Inhaltswarnungen einklappen",
"columns": "Spalten",
"compact_user_info": "Kompakte Benutzerinfos wenn genug Platz",
"composing": "Verfassen",
"confirm_dialogs": "Bestätigung erforderlich für:",
"confirm_dialogs_approve_follow": "Annehmen einer Followanfrage",
@ -934,6 +936,7 @@
"title": "Version"
},
"virtual_scrolling": "Anzeige der Zeitleiste optimieren",
"widen_timeline": "Zeitleiste verbreitern, um horizontalen Platz zu füllen",
"word_filter": "Wortfilter",
"wordfilter": "Wortfilter"
},

View file

@ -495,6 +495,7 @@
"boosts_follow_def_vis": "Make boosts follow default visibility",
"bot": "This is a bot account",
"btnRadius": "Buttons",
"center_align_bio": "Center text in user bio",
"cBlue": "Blue (Reply, follow)",
"cGreen": "Green (Retweet)",
"cOrange": "Orange (Favorite)",
@ -509,6 +510,7 @@
"checkboxRadius": "Checkboxes",
"collapse_subject": "Collapse posts with content warnings",
"columns": "Columns",
"compact_user_info": "Compact user info when enough space",
"composing": "Composing",
"confirm_dialogs": "Require confirmation for:",
"confirm_dialogs_approve_follow": "Accepting a follow request",
@ -968,6 +970,7 @@
},
"virtual_scrolling": "Optimize timeline rendering",
"use_blurhash": "Use blurhashes for NSFW thumbnails",
"widen_timeline": "Widen the Timeline to fill horizontal space",
"word_filter": "Word filter",
"wordfilter": "Wordfilter"
},

View file

@ -503,7 +503,13 @@
"columns": "Colonne",
"composing": "Composizione",
"confirm_new_password": "Conferma la nuova password",
"conversation_display": "Stile di visualizzazione delle conversazioni",
"conversation_display_linear": "Stile lineare",
"conversation_display_tree": "Stile ad albero",
"conversation_other_replies_button": "Mostra il bottone \"altre risposte\"",
"conversation_other_replies_button_below": "Sotto i post",
"current_avatar": "La tua icona attuale",
"current_mascot": "La tua mascotte attuale",
"current_password": "La tua password attuale",
"data_import_export_tab": "Importa o esporta dati",
"default_vis": "Visibilità predefinita dei messaggi",
@ -511,11 +517,15 @@
"delete_account_description": "Elimina definitivamente i tuoi dati e disattiva il tuo profilo.",
"delete_account_error": "C'è stato un problema durante l'eliminazione del tuo profilo. Se il problema persiste contatta l'amministratore della tua stanza.",
"delete_account_instructions": "Digita la tua password nel campo sottostante per eliminare il tuo profilo.",
"disable_sticky_headers": "Non fissare i titoli delle colonne in cima allo schermo",
"discoverable": "Permetti la scoperta di questo profilo a servizi di ricerca ed altro",
"domain_mutes": "Domini",
"download_backup": "Scarica",
"email_language": "Lingua delle email ricevute dal server",
"emoji_reactions_on_timeline": "Mostra reazioni nelle sequenze",
"enable_web_push_notifications": "Abilita notifiche web push",
"enter_current_password_to_confirm": "Inserisci la tua password per identificarti",
"expert_mode": "Mostra avanzate",
"export_theme": "Salva impostazioni",
"file_export_import": {
"backup_restore": "Archiviazione impostazioni",
@ -543,18 +553,23 @@
"hide_all_muted_posts": "Nascondi messaggi silenziati",
"hide_attachments_in_convo": "Nascondi gli allegati presenti nelle conversazioni",
"hide_attachments_in_tl": "Nascondi gli allegati presenti nelle sequenze",
"hide_bot_indication": "Nascondi indicatore bot nei post",
"hide_favorites_description": "Non mostrare la lista dei miei preferiti (gli utenti verranno comunque notificati)",
"hide_filtered_statuses": "Nascondi messaggi filtrati",
"hide_followers_count_description": "Non mostrare quanti seguaci ho",
"hide_followers_description": "Non mostrare i miei seguaci",
"hide_follows_count_description": "Non mostrare quanti utenti seguo",
"hide_follows_description": "Non mostrare chi seguo",
"hide_isp": "Nascondi pannello della stanza",
"hide_list_aliases_error_action": "Chiudi",
"hide_media_previews": "Nascondi anteprime",
"hide_muted_posts": "Nascondi messaggi degli utenti silenziati",
"hide_muted_threads": "Nascondi conversazioni silenziate",
"hide_post_stats": "Nascondi statistiche dei messaggi (es. il numero di preferenze)",
"hide_shoutbox": "Nascondi muro dei graffiti",
"hide_user_stats": "Nascondi statistiche dell'utente (es. il numero di seguaci)",
"hide_wallpaper": "Nascondi sfondo della stanza",
"hide_wordfiltered_statuses": "Nascondi post filtrati per parola",
"import_blocks_from_a_csv_file": "Importa blocchi da un file CSV",
"import_followers_from_a_csv_file": "Importa una lista di chi segui da un file CSV",
"import_mutes_from_a_csv_file": "Importa silenziati da un file CSV",
@ -567,10 +582,14 @@
"invalid_theme_imported": "Il file selezionato non è un tema supportato da Pleroma. Il tuo tema non è stato modificato.",
"limited_availability": "Non disponibile nel tuo browser",
"links": "Collegamenti",
"list_aliases_error": "Errore nel recupero degli alias: {error}",
"list_backups_error": "Errore nel recupero della lista dei backup: {error}",
"lock_account_description": "Vaglia manualmente i nuovi seguaci",
"loop_video": "Riproduci video in ciclo continuo",
"loop_video_silent_only": "Riproduci solo video muti in ciclo continuo (es. le \"gif\" di Mastodon)",
"mascot": "Mascotte di MastodonFE",
"max_thumbnails": "Numero massimo di anteprime per messaggio",
"mention_links": "Collegamenti delle menzioni",
"mfa": {
"authentication_methods": "Metodi di accesso",
"confirm_and_enable": "Conferma ed abilita OTP",
@ -594,6 +613,12 @@
},
"minimal_scopes_mode": "Riduci opzioni di visibilità",
"more_settings": "Altre impostazioni",
"move_account": "Sposta account",
"move_account_error": "Errore nello spostamento dell'account: {error}",
"move_account_notes": "Se vuoi spostare questo account da qualche altra parte, devi andare all'account di destinazione e aggiungere un alias che punta qui.",
"move_account_target": "Account di destinazione (es. {example})",
"moved_account": "Account spostato.",
"mute_bot_posts": "Silenzia post dei bot",
"mute_export": "Esporta silenziati",
"mute_export_button": "Esporta i silenziati in un file CSV",
"mute_import": "Carica silenziati",
@ -603,6 +628,7 @@
"mutes_tab": "Silenziati",
"name": "Nome",
"name_bio": "Nome ed introduzione",
"new_alias_target": "Aggiungi nuovo alias (es. {example})",
"new_email": "Nuova email",
"new_password": "Nuova password",
"no_blocks": "Nessun utente bloccato",
@ -620,6 +646,7 @@
"notification_visibility_likes": "Preferiti",
"notification_visibility_mentions": "Menzioni",
"notification_visibility_moves": "Migrazioni utenti",
"notification_visibility_polls": "Termine dei poll in cui hai votato",
"notification_visibility_repeats": "Condivisioni",
"notifications": "Notifiche",
"nsfw_clickthrough": "Fai click per visualizzare gli allegati offuscati",
@ -628,7 +655,9 @@
"panelRadius": "Pannelli",
"pause_on_unfocused": "Interrompi l'aggiornamento continuo mentre la scheda è in secondo piano",
"play_videos_in_modal": "Riproduci video in un riquadro a sbalzo",
"post_look_feel": "Aspetto dei post",
"post_status_content_type": "Tipo di contenuto dei messaggi",
"posts": "Post",
"preload_images": "Precarica immagini",
"presets": "Valori predefiniti",
"profile_background": "Sfondo del tuo profilo",
@ -642,6 +671,8 @@
"profile_tab": "Profilo",
"radii_help": "Imposta il raggio degli angoli (in pixel)",
"refresh_token": "Aggiorna token",
"remove_alias": "Rimuovi questo alias",
"remove_backup": "Elimina",
"replies_in_timeline": "Risposte nelle sequenze",
"reply_visibility_all": "Mostra tutte le risposte",
"reply_visibility_following": "Mostra solo le risposte rivolte a me o agli utenti che seguo",
@ -666,12 +697,15 @@
"security_tab": "Sicurezza",
"sensitive_by_default": "Tutti i miei messaggi sono scabrosi",
"set_new_avatar": "Scegli una nuova icona",
"set_new_mascot": "Imposta nuova mascotte",
"set_new_profile_background": "Scegli un nuovo sfondo",
"set_new_profile_banner": "Scegli un nuovo gonfalone",
"setting_changed": "Valore personalizzato",
"setting_server_side": "Questa impostazione è legata al tuo profilo e ha effetto su tutte le sessioni e tutti i client",
"settings": "Impostazioni",
"show_admin_badge": "Mostra l'insegna di amministratore sul mio profilo",
"show_moderator_badge": "Mostra l'insegna di moderatore sul mio profilo",
"show_scrollbars": "Mostra le barre di scorrimento delle colonne laterali",
"stop_gifs": "Riproduci GIF al passaggio del cursore",
"streaming": "Mostra automaticamente i nuovi messaggi quando sei in cima alla pagina",
"style": {
@ -780,66 +814,80 @@
},
"filter_hint": {
"always_drop_shadow": "Attenzione: quest'ombra usa sempre {0} se il tuo browser lo supporta.",
"avatar_inset": "Tieni presente che combinare ombre (sia incluse che non) sulle icone utente potrebbe dare risultati strani con quelle trasparenti.",
"drop_shadow_syntax": "{0} non supporta il parametro {1} né la keyword {2}.",
"inset_classic": "Le ombre incluse usano {0}",
"spread_zero": "Lo spandimento maggiore di zero si azzera sulle ombre"
"avatar_inset": "Tieni presente che combinare ombre (sia incavate che non) sulle icone utente potrebbe dare risultati strani con avatar trasparenti.",
"drop_shadow_syntax": "{0} non supporta il parametro {1} con la keyword {2}.",
"inset_classic": "Le ombre incavate usano {0}",
"spread_zero": "Le ombre con espansione maggiore di zero appariranno come se l'espansione fosse zero"
},
"hintV3": "Per le ombre puoi anche usare la sintassi {0} per sfruttare il secondo colore.",
"inset": "Includi",
"override": "Sostituisci",
"shadow_id": "Ombra numero {value}",
"spread": "Spandi"
"hintV3": "Per le ombre puoi anche usare la sintassi {0} per usare l'altro slot colore.",
"inset": "Incavatura",
"override": "Sovrascrivi",
"shadow_id": "Ombra #{value}",
"spread": "Espansione"
},
"switcher": {
"clear_all": "Azzera tutto",
"clear_opacity": "Rimuovi opacità",
"clear_opacity": "Azzera opacità",
"help": {
"fe_downgraded": "L'interfaccia è stata portata ad una versione precedente.",
"fe_upgraded": "Lo schema dei temi è stato aggiornato insieme all'interfaccia.",
"future_version_imported": "Il tema importato è stato creato per una versione più recente dell'interfaccia.",
"migration_napshot_gone": "Anteprima del tema non trovata, non tutto potrebbe essere come ricordi.",
"migration_snapshot_ok": "Ho caricato l'anteprima del tema. Puoi provare a caricarne i contenuti.",
"older_version_imported": "Il tema importato è stato creato per una versione precedente dell'interfaccia.",
"snapshot_missing": "Il tema non è provvisto di anteprima, quindi potrebbe essere diverso da come appare.",
"fe_downgraded": "La versione di PleromaFE è riportata ad una versione precedente.",
"fe_upgraded": "Il motore dei temi di PleromaFE è stato aggiornato insieme all'interfaccia.",
"future_version_imported": "Il tema importato è stato creato per una versione più nuova del frontend.",
"migration_napshot_gone": "Per qualche motivo non è stata trovata l'anteprima del tema, non tutto potrebbe essere come ricordi.",
"migration_snapshot_ok": "Per sicurezza, è stata caricata l'anteprima del tema. Puoi provare a caricarne i contenuti.",
"older_version_imported": "Il file importato è stato creato per una versione precedente del frontend.",
"snapshot_missing": "Il file non è provvisto di anteprima, quindi potrebbe essere diverso da come appare.",
"snapshot_present": "Tutti i valori sono sostituiti dall'anteprima del tema. Puoi invece caricare i suoi contenuti.",
"snapshot_source_mismatch": "Conflitto di versione: probabilmente l'interfaccia è stata portata indietro e poi aggiornata di nuovo. Se hai modificato il tema con una vecchia versione usa il tema precedente, altrimenti puoi usare il nuovo.",
"upgraded_from_v2": "L'interfaccia è stata aggiornata, il tema potrebbe essere diverso da come lo ricordi.",
"v2_imported": "Il tema importato è stato creato per una vecchia interfaccia. Non tutto potrebbe essere come inteso."
"snapshot_source_mismatch": "Conflitto di versione: probabilmente il frontend è stato deaggiornato e poi aggiornato di nuovo. Se hai modificato il tema con una vecchia versione usa il tema precedente, altrimenti usa quello nuovo.",
"upgraded_from_v2": "PleromaFE è stato aggiornato, il tema potrebbe essere un pochino diverso da come lo ricordi.",
"v2_imported": "Il file importato è stato creato per un vecchio frontend. Cerchiamo di massimizzare la compatibilità, ma potrebbero esserci inconsistenze."
},
"keep_as_is": "Mantieni tal quale",
"keep_as_is": "Mantieni com'è",
"keep_color": "Mantieni colori",
"keep_fonts": "Mantieni font",
"keep_opacity": "Mantieni opacità",
"keep_roundness": "Mantieni vertici",
"keep_shadows": "Mantieni ombre",
"load_theme": "Carica tema",
"reset": "Reimposta",
"reset": "Azzera",
"save_load_hint": "Le opzioni \"mantieni\" conservano le impostazioni correnti quando selezioni o carichi un tema, e le salvano quando ne esporti uno. Quando nessuna casella è selezionata, tutte le impostazioni correnti saranno salvate nel tema.",
"use_snapshot": "Versione precedente",
"use_source": "Nuova versione"
}
},
"subject_input_always_show": "Mostra sempre il campo Oggetto",
"subject_line_behavior": "Copia oggetto quando rispondi",
"subject_line_email": "Come nelle email: \"re: oggetto\"",
"subject_line_mastodon": "Come in Mastodon: copia tal quale",
"subject_input_always_show": "Mostra sempre il campo avvertenza sul contenuto",
"subject_line_behavior": "Copia avvertenza sul contenuto quando rispondi",
"subject_line_email": "Come nelle email: \"re: avvertenza\"",
"subject_line_mastodon": "Come su Mastodon: copia com'è",
"subject_line_noop": "Non copiare",
"text": "Testo",
"theme": "Tema",
"theme_help": "Usa colori esadecimali (#rrggbb) per personalizzare il tuo schema di colori.",
"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.",
"theme_help_v2_2": "Le icone vicino alcuni elementi sono indicatori del contrasto fra testo e sfondo, passaci sopra col puntatore per ulteriori informazioni. Se usani trasparenze, questi indicatori mostrano il peggior caso possibile.",
"theme_help": "Usa colori esadecimali (#rrvvbb) per personalizzare il tuo tema colori.",
"theme_help_v2_1": "Puoi anche sovrascrivere colore ed opacità di alcuni elementi spuntando la casella. Usa il pulsante \"Azzera\" per azzerare tutte le sovrascritture.",
"theme_help_v2_2": "Le icone vicino alcuni elementi sono indicatori del contrasto fra testo e sfondo, passaci sopra col puntatore per ulteriori informazioni. Se usano la trasparenza, questi indicatori mostrano come sarebbero nel peggior caso possibile.",
"third_column_mode": "Quando c'è abbastanza spazio, mostra una terza colonna contenente",
"third_column_mode_none": "Non mostrare proprio la terza colonna",
"third_column_mode_notifications": "Colonna notifiche",
"third_column_mode_postform": "Modulo post principale e navigazione",
"token": "Token",
"tooltipRadius": "Suggerimenti/avvisi",
"tooltipRadius": "Suggerimenti/allerte",
"translation_language": "Lingua finale di traduzione automatica",
"tree_advanced": "Mostra bottoni aggiuntivi per aprire e chiudere catene di risposte nelle conversazioni",
"tree_fade_ancestors": "Mostra antenati del post corrente in testo semitrasparente",
"type_domains_to_mute": "Cerca domini da silenziare",
"upload_a_photo": "Carica un'immagine",
"upload_a_photo": "Carica una foto",
"useStreamingApi": "Ricevi messaggi e notifiche in tempo reale",
"useStreamingApiWarning": "(Sconsigliato, sperimentale, può saltare messaggi)",
"useStreamingApiWarning": "",
"use_blurhash": "Usa blurhash per anteprime NSFW",
"use_contain_fit": "Non ritagliare le anteprime degli allegati",
"use_one_click_nsfw": "Apri media offuscati con un solo click",
"use_one_click_nsfw": "Apri allegati NSFW con un solo click",
"user_accepts_direct_messages_from": "Accetta post «diretti» da",
"user_accepts_direct_messages_from_everybody": "Tutti",
"user_accepts_direct_messages_from_nobody": "Nessuno",
"user_accepts_direct_messages_from_people_i_follow": "Persone che seguo",
"user_mutes": "Utenti",
"user_settings": "Impostazioni Utente",
"user_profile_default_tab": "Scheda predefinita sul profilo degli utenti",
"user_profiles": "Profili utente",
"user_settings": "Impostazioni utente",
"valid_until": "Valido fino a",
"values": {
"false": "no",
@ -847,86 +895,141 @@
},
"version": {
"backend_version": "Versione backend",
"frontend_version": "Versione interfaccia",
"frontend_version": "Versione frontend",
"title": "Versione"
},
"virtual_scrolling": "Velocizza l'elaborazione delle sequenze",
"word_filter": "Parole filtrate"
"virtual_scrolling": "Velocizza rendering sequenze",
"word_filter": "Filtro per parola",
"wordfilter": "Filtro per parola"
},
"settings_profile": {
"creating": "Creazione del nuovo profilo di impostazioni \"{profile}\"…",
"synchronization_error": "Non è stato possibile sincronizzare le impostazioni: {err}",
"synchronized": "Impostazioni sincronizzate!",
"synchronizing": "Sincronizzazione del profilo di impostazioni \"{profile}\"…"
},
"status": {
"ancestor_follow": "Vedi {numReplies} altra risposta sotto questo post | Vedi {numReplies} altre risposte sotto questo post",
"ancestor_follow_with_icon": "{icon} {text}",
"attachment_stop_flash": "Ferma Flash player",
"bookmark": "Aggiungi segnalibro",
"copy_link": "Copia collegamento",
"delete": "Elimina messaggio",
"delete_confirm": "Vuoi veramente eliminare questo messaggio?",
"collapse_attachments": "Riduci allegati",
"copy_link": "Copia collegamento al post",
"delete": "Elimina post",
"delete_confirm": "Vuoi davvero eliminare questo post?",
"delete_confirm_accept_button": "Sì, eliminalo",
"delete_confirm_cancel_button": "No, tienilo",
"delete_confirm_title": "Conferma eliminazione",
"edit": "Modifica",
"edit_history": "Cronologia modifiche",
"edit_history_modal_title": "Modificato {historyCount} volta | Modificato {historyCount} volte",
"edited_at": "Modificato {time}",
"expand": "Espandi",
"external_source": "Vai all'origine",
"external_source": "Fonte originale",
"favorites": "Preferiti",
"hide_content": "Nascondi contenuti",
"hide_full_subject": "Nascondi oggetto intero",
"hide_attachment": "Nascondi allegato",
"hide_content": "Nascondi contenuto",
"hide_full_subject": "Nascondi avvertenza sul contenuto intera",
"many_attachments": "Il post ha {number} allegato | Il post ha {number} allegati",
"mentions": "Menzioni",
"move_down": "Muovi allegato a destra",
"move_up": "Muovi allegato a sinistra",
"mute_conversation": "Silenzia conversazione",
"nsfw": "DISDICEVOLE",
"pin": "Intesta al profilo",
"pinned": "Intestato",
"nsfw": "NSFW",
"open_gallery": "Apri galleria",
"override_translation_source_language": "Sovrascrivi lingua di origine",
"pin": "Fissa in cima al profilo",
"pinned": "Fissato",
"plus_more": "+{number} altri",
"repeats": "Condivisi",
"redraft": "Elimina e correggi",
"redraft_confirm": "Vuoi davvero eliminare e correggere questo post? Le interazioni al post originale non saranno mantenute.",
"redraft_confirm_accept_button": "Sì, elimina e correggi",
"redraft_confirm_cancel_button": "No, tieni l'originale",
"redraft_confirm_title": "Conferma elimina e correggi",
"remove_attachment": "Rimuovi allegato",
"repeat_confirm": "Vuoi davvero condividere questo post?",
"repeat_confirm_accept_button": "Sì, condividilo",
"repeat_confirm_cancel_button": "No, non condividere",
"repeat_confirm_title": "Conferma condivisione",
"repeats": "Condivisioni",
"replies_list": "Risposte:",
"replies_list_with_others": "Mostra {numReplies} altra risposta | Mostra {numReplies} altre risposte",
"reply_to": "In risposta a",
"show_content": "Mostra contenuti",
"show_full_subject": "Mostra oggetto intero",
"status_deleted": "Questo messagio è stato cancellato",
"status_unavailable": "Messaggio non disponibile",
"thread_muted": "Discussione silenziata",
"show_all_attachments": "Mostra tutti gli allegati",
"show_all_conversation": "Mostra conversazione intera ({numStatus} altro post) | Mostra conversazione intera ({numStatus} altri post)",
"show_all_conversation_with_icon": "{icon} {text}",
"show_attachment_description": "Anteprima descrizione (apri l'allegato per la descrizione intera)",
"show_attachment_in_modal": "Mostra allegato in una finestra",
"show_content": "Mostra contenuto",
"show_full_subject": "Mostra tutta l'avvertenza sul contenuto",
"show_only_conversation_under_this": "Mostra solo le risposte a questo post",
"status_deleted": "Questo post è stato eliminato",
"status_unavailable": "Post non disponibile",
"thread_follow": "Visualizza {numStatus} altra risposta | Visualizza {numStatus} altre risposte",
"thread_follow_with_icon": "{icon} {text}",
"thread_hide": "Nascondi questa conversazione",
"thread_muted": "Conversazione silenziata",
"thread_muted_and_words": ", contiene:",
"thread_show": "Mostra questa conversazione",
"thread_show_full": "Mostra {numStatus} risposta | Mostra tutte e {numStatus} le risposte",
"thread_show_full_with_icon": "{icon} {text}",
"translate": "Traduci",
"translated_from": "Tradotto da {language}",
"unbookmark": "Rimuovi segnalibro",
"unmute_conversation": "Riabilita conversazione",
"unpin": "De-intesta",
"unmute_conversation": "Desilenzia conversazione",
"unpin": "Rimuovi dalla cima del profilo",
"you": "(Tu)"
},
"time": {
"in_future": "fra {0}",
"in_past": "{0} fa",
"now": "adesso",
"now_short": "adesso",
"now": "proprio adesso",
"now_short": "ora",
"unit": {
"days": "{0} giorni",
"days": "{0} giorno | {0} giorni",
"days_short": "{0} g",
"hours": "{0} ore",
"hours_short": "{0} h",
"minutes": "{0} minuti",
"hours": "{0} ora | {0} ore",
"hours_short": "{0} ora | {0} ore",
"minutes": "{0} minuto | {0} minuti",
"minutes_short": "{0} min",
"months": "{0} mesi",
"months_short": "{0} mes",
"seconds": "{0} secondi",
"months": "{0} mese | {0} mesi",
"months_short": "{0} mese | {0} mesi",
"seconds": "{0} secondo | {0} secondi",
"seconds_short": "{0} sec",
"weeks": "{0} settimane",
"weeks_short": "{0} stm",
"years": "{0} anni",
"weeks": "{0} settimana | {0} settimane",
"weeks_short": "{0} sett",
"years": "{0} anno | {0} anni",
"years_short": "{0} a"
}
},
"timeline": {
"collapse": "Ripiega",
"collapse": "Riduci",
"conversation": "Conversazione",
"error": "Errore nel caricare la sequenza: {0}",
"load_older": "Carica messaggi precedenti",
"no_more_statuses": "Fine dei messaggi",
"no_retweet_hint": "Il messaggio è diretto o solo per seguaci e non può essere condiviso",
"no_statuses": "Nessun messaggio",
"follow_tag": "Segui hashtag",
"load_older": "Carica post precedenti",
"no_more_statuses": "Non ci sono altri post",
"no_retweet_hint": "Il messaggio è «solo per follower» o «diretto», quindi non può essere condiviso",
"no_statuses": "Nessun post",
"reload": "Ricarica",
"repeated": "ha condiviso",
"show_new": "Mostra nuovi",
"socket_broke": "Connessione tempo reale interrotta: codice {0}",
"socket_broke": "Connessione tempo reale interrotta: CloseEvent codice {0}",
"socket_reconnected": "Connesso in tempo reale",
"unfollow_tag": "Smetti di seguire hashtag",
"up_to_date": "Aggiornato"
},
"toast": {
"no_translation_target_set": "Nessuna lingua finale di traduzione impostata: la traduzione potrebbe fallire. Imposta una lingua finale di traduzione nelle tue impostazioni."
},
"tool_tip": {
"accept_follow_request": "Accetta seguace",
"add_reaction": "Reagisci",
"accept_follow_request": "Accetta richiesta di follow",
"add_reaction": "Aggiungi reazione",
"bookmark": "Aggiungi segnalibro",
"favorite": "Gradisci",
"media_upload": "Carica allegati",
"reject_follow_request": "Rifiuta seguace",
"favorite": "Rendi preferito",
"media_upload": "Carica media",
"quote": "Cita",
"reject_follow_request": "Rifiuta richiesta di follow",
"repeat": "Condividi",
"reply": "Rispondi",
"user_settings": "Impostazioni utente"
@ -934,7 +1037,7 @@
"upload": {
"error": {
"base": "Caricamento fallito.",
"default": "Riprova in seguito",
"default": "Riprova più tardi",
"file_too_big": "File troppo pesante [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"message": "Caricamento fallito: {0}"
},
@ -948,79 +1051,115 @@
},
"user_card": {
"admin_menu": {
"activate_account": "Attiva profilo",
"deactivate_account": "Disattiva profilo",
"delete_account": "Elimina profilo",
"activate_account": "Riattiva account",
"deactivate_account": "Disattiva account",
"delete_account": "Elimina account",
"delete_user": "Elimina utente",
"disable_any_subscription": "Rendi utente non seguibile",
"disable_remote_subscription": "Blocca i tentativi di seguirlo da altre stanze",
"force_nsfw": "Oscura tutti i messaggi",
"force_unlisted": "Nascondi tutti i messaggi",
"grant_admin": "Crea Amministratore",
"grant_moderator": "Crea Moderatore",
"delete_user_data_and_deactivate_confirmation": "Questo eliminerà permanentemente i dati dall'account e lo disattiverà. Sei sicuro al 100%?",
"disable_any_subscription": "Proibisci a tutti di seguire l'utente",
"disable_remote_subscription": "Proibisci ad istanze remote di seguire l'utente",
"force_nsfw": "Marca tutti i post come NSFW",
"force_unlisted": "Rendi tutti i post «non in elenco»",
"grant_admin": "Rendi amministratore",
"grant_moderator": "Rendi moderatore",
"moderation": "Moderazione",
"quarantine": "I messaggi non arriveranno alle altre stanze",
"revoke_admin": "Divesti Amministratore",
"revoke_moderator": "Divesti Moderatore",
"sandbox": "Rendi tutti i messaggi solo per seguaci",
"strip_media": "Rimuovi ogni allegato ai messaggi"
"quarantine": "Impedisci la federazione dei post degli utenti",
"revoke_admin": "Rimuovi da amministratore",
"revoke_moderator": "Rimuovi da moderatore",
"sandbox": "Rendi tutti i messaggi \"solo per follower\"",
"strip_media": "Rimuovi media dai messaggi"
},
"approve": "Approva",
"approve": "Accetta",
"approve_confirm": "Sei sicuro di voler permettere a questo utente di seguirti?",
"approve_confirm_accept_button": "Sì, accetta",
"approve_confirm_cancel_button": "No, annulla",
"approve_confirm_title": "Accetta richiesta di follow",
"block": "Blocca",
"block_confirm": "Sei sicuro di voler bloccare {user}?",
"block_confirm_accept_button": "Sì, blocca",
"block_confirm_cancel_button": "No, non bloccare",
"block_confirm_title": "Blocca utente",
"block_progress": "Blocco…",
"blocked": "Bloccato!",
"blocks_you": "Ti blocca!",
"bot": "Bot",
"deny": "Nega",
"deactivated": "Disattivato",
"deny": "Rifiuta",
"deny_confirm": "Sei sicuro di voler rifiutare la richiesta di follow di questo utente?",
"deny_confirm_accept_button": "Sì, rifiuta",
"deny_confirm_cancel_button": "No, annulla",
"deny_confirm_title": "Rifiuta richiesta di follow",
"domain_muted": "Sblocca dominio",
"edit_profile": "Modifica profilo",
"favorites": "Preferiti",
"follow": "Segui",
"follow_cancel": "Annulla richiesta",
"follow_progress": "Richiedo…",
"follow_sent": "Richiesta inviata!",
"follow_unfollow": "Disconosci",
"followees": "Segue",
"followers": "Seguaci",
"following": "Seguìto!",
"follow_tag": "Segui l'hashtag",
"follow_unfollow": "Smetti di seguire",
"followed_tags": "Hashtag seguiti",
"followed_users": "Utenti seguiti",
"followees": "Seguiti",
"followers": "Follower",
"following": "Seguito!",
"follows_you": "Ti segue!",
"hidden": "Nascosto",
"hide_repeats": "Nascondi condivisioni",
"highlight": {
"disabled": "Nessun risalto",
"side": "Nastro a lato",
"solid": "Un colore",
"striped": "A righe"
"disabled": "Nessuno sfondo",
"side": "Striscia laterale",
"solid": "Sfondo monocolore",
"striped": "Sfondo a righe"
},
"its_you": "Sei tu!",
"media": "Media",
"mention": "Menziona",
"message": "Contatta",
"mute": "Silenzia",
"mute_progress": "Silenzio…",
"mute_confirm": "Sei sicuro di voler silenziare {user}?",
"mute_confirm_accept_button": "Sì, silenzia",
"mute_confirm_cancel_button": "No, non silenziare",
"mute_confirm_title": "Silenzia utente",
"mute_domain": "Blocca dominio",
"mute_progress": "Silenziando…",
"muted": "Silenziato",
"not_following_any_hashtags": "Non stai seguendo nessun hashtag",
"note": "Nota privata",
"per_day": "al giorno",
"remote_follow": "Segui da remoto",
"remove_follower": "Rimuovi follower",
"replies": "Con risposte",
"report": "Segnala",
"requested_by": "Ha chiesto di seguirti",
"show_repeats": "Mostra condivisioni",
"statuses": "Messaggi",
"subscribe": "Abbònati",
"statuses": "Post",
"subscribe": "Iscriviti",
"unblock": "Sblocca",
"unblock_progress": "Sblocco…",
"unmute": "Riabilita",
"unmute_progress": "Riabilito…",
"unsubscribe": "Disdici"
"unfollow_confirm": "Sei sicuro di voler smettere di seguire {user}?",
"unfollow_confirm_accept_button": "Sì, smetti di seguire",
"unfollow_confirm_cancel_button": "No, non smettere di seguire",
"unfollow_confirm_title": "Smetti di seguire l'utente",
"unfollow_tag": "Smetti di seguire l'hashtag",
"unmute": "Desilenzia",
"unmute_progress": "Desilenziamento…",
"unsubscribe": "Disiscriviti"
},
"user_profile": {
"field_validated": "Collegamento verificato",
"profile_does_not_exist": "Spiacente, questo profilo non esiste.",
"profile_loading_error": "Spiacente, c'è stato un errore nel caricamento del profilo.",
"timeline_title": "Sequenza dell'utente"
},
"user_reporting": {
"add_comment_description": "La segnalazione sarà inviata ai moderatori della tua stanza. Puoi motivarla qui sotto:",
"additional_comments": "Osservazioni accessorie",
"forward_description": "Il profilo appartiene ad un'altra stanza. Inviare la segnalazione anche a quella?",
"add_comment_description": "La segnalazione sarà inviata ai moderatori della tua istanza. Puoi fornire una motivazione per cui stai segnalando questo account qui sotto:",
"additional_comments": "Commenti aggiuntivi",
"forward_description": "Il profilo appartiene ad un altro server. Inviare la segnalazione anche a quello?",
"forward_to": "Inoltra a {0}",
"generic_error": "C'è stato un errore nell'elaborazione della tua richiesta.",
"submit": "Invia",
"title": "Segnalo {0}"
"title": "Segnala {0}"
},
"who_to_follow": {
"more": "Altro",

124
src/i18n/lt.json Normal file
View file

@ -0,0 +1,124 @@
{
"about": {
"bubble_instances": "Vietiniai burbulo serveriai",
"bubble_instances_description": "Administratorių parinkti serveriai, kurie atstovauja šios serverio vietinę teritoriją",
"mrf": {
"federation": "Federacija",
"keyword": {
"ftl_removal": "Pašalinimas iš „Viso žinomo tinklo“ laiko skalės",
"is_replaced_by": "→",
"keyword_policies": "Raktažodžių politika",
"reject": "Atmesti",
"replace": "Pakeisti"
},
"mrf_policies": "Įjungta MRF politika",
"mrf_policies_desc": "MRF politika valdo serverio federacijos elgseną. Įjungtos toliau nurodytos politikos:",
"simple": {
"accept": "Priimti",
"accept_desc": "Šis serveris priima žinutes tik iš toliau nurodytų serverių:",
"ftl_removal": "Pašalinimas iš „Žinomo tinklo“ laiko skalės",
"ftl_removal_desc": "Šis serveris pašalina šiuos serverius iš „Žinomo tinklo“ laiko skalės:",
"instance": "Serveris",
"media_nsfw": "Medija priverstinai nustatyta kaip jautri",
"media_nsfw_desc": "Šis serveris priverčia nustatyti mediją kaip jautrią toliau nurodytų serverių įrašuose:",
"media_removal": "Medijos pašalinimas",
"media_removal_desc": "Šis serveris pašalina mediją iš toliau nurodytų serverių įrašų:",
"not_applicable": "Nėra",
"quarantine": "Karantinas",
"quarantine_desc": "Šis serveris nesiųs įrašų į toliau nurodytus serverius:",
"reason": "Priežastis",
"reject": "Atmesti",
"reject_desc": "Šis serveris nepriims žinučių iš toliau nurodytų serverių:",
"simple_policies": "Konkretaus serverio politika"
}
},
"staff": "Personalas"
},
"announcements": {
"all_day_prompt": "Tai visos dienos renginys",
"cancel_edit_action": "Atsisakyti",
"close_error": "Užverti",
"delete_action": "Ištrinti",
"edit_action": "Redaguoti",
"end_time_display": "Pasibaigia {time}",
"end_time_prompt": "Pabaigos laikas: ",
"inactive_message": "Šis skelbimas neaktyvus",
"mark_as_read_action": "Žymėti kaip skaitytą",
"page_header": "Skelbimai",
"post_action": "Siųsti",
"post_error": "Klaida: {error}",
"post_form_header": "Skelbti skelbimą"
},
"chats": {
"chats": "Pokalbiai",
"delete": "Ištrinti",
"more": "Daugiau",
"new": "Naujas pokalbis",
"you": "Jūs:"
},
"display_date": {
"today": "Šiandien"
},
"domain_mute_card": {
"mute": "Nutildyti",
"mute_progress": "Nutildoma…",
"unmute": "Atšaukti nutildymą",
"unmute_progress": "Atšaukiamas nutildymas…"
},
"emoji": {
"add_emoji": "Įterpti jaustuką",
"custom": "Pasirinktinis jaustukas",
"emoji": "Jaustukas",
"stickers": "Lipdukai",
"unicode": "Unikodo jaustukas"
},
"exporter": {
"export": "Eksportuoti"
},
"file_type": {
"audio": "Garso įrašas",
"file": "Failas",
"image": "Vaizdas",
"video": "Vaizdo įrašas"
},
"general": {
"more": "Daugiau",
"scope_in_timeline": {
"direct": "Tiesioginis",
"local": "Vietinis šį įrašą gali matyti tik jūsų serveris",
"private": "Tik sekėjams",
"public": "Vieša",
"unlisted": "Neįtrauktas į sąrašą"
},
"show_less": "Rodyti mažiau",
"show_more": "Rodyti daugiau",
"submit": "Pateikti",
"verify": "Patvirtinti"
},
"image_cropper": {
"cancel": "Atšaukti"
},
"importer": {
"submit": "Pateikti"
},
"user_card": {
"follow_tag": "Sekti saitažodį",
"not_following_any_hashtags": "Nesekate jokių saitažodžių.",
"unfollow_confirm_accept_button": "Taip, nebesekti",
"unfollow_confirm_cancel_button": "Ne, nenaikinti sekimą",
"unfollow_confirm_title": "Nebesekti naudotoją",
"unfollow_tag": "Nebesekti saitažodį"
},
"user_reporting": {
"additional_comments": "Papildomi komentarai",
"forward_description": "Paskyra yra iš kito serverio. Siųsti ataskaitos kopiją ir ten?",
"forward_to": "Persiųsti į {0}",
"generic_error": "Įvyko klaida apdorojant jūsų užklausą.",
"submit": "Pateikti",
"title": "Pranešama apie {0}"
},
"who_to_follow": {
"more": "Daugiau",
"who_to_follow": "Ką sekti"
}
}

View file

@ -599,7 +599,7 @@
"links": "Łącza",
"list_aliases_error": "Błąd pobierania aliasów: {error}",
"list_backups_error": "Błąd pobierania listy kopii zapasowych: {error}",
"lock_account_description": "Spraw, by konto mogli wyświetlać tylko zatwierdzeni obserwujący",
"lock_account_description": "Wymagaj potwierdzenia nowych śledzących",
"loop_video": "Zapętlaj filmy",
"loop_video_silent_only": "Zapętlaj tylko filmy bez dźwięku (np. mastodonowe „gify”)",
"mascot": "Maskotka Mastodon FE",
@ -679,6 +679,7 @@
"pad_emoji": "Dodaj odstęp z obu stron emoji podczas dodawania selektorem",
"panelRadius": "Panele",
"pause_on_unfocused": "Wstrzymuj strumieniowanie kiedy karta nie jest aktywna",
"permit_followback_description": "Automatycznie potwierdź śledzenie przez użytkowników którch już śledzisz",
"play_videos_in_modal": "Odtwarzaj filmy bezpośrednio w przeglądarce mediów",
"post_look_feel": "Wygląd wpisów",
"post_status_content_type": "Domyślny typ zawartości wpisów",
@ -1148,7 +1149,7 @@
"followed_users": "Śledzeni użytkownicy",
"followees": "Obserwowani",
"followers": "Obserwujący",
"following": "Obserwowany!",
"following": "Obserwujesz!",
"follows_you": "Obserwuje cię!",
"hidden": "Ukryte",
"hide_repeats": "Ukryj powtórzenia",

View file

@ -56,6 +56,8 @@ export const defaultState = {
autohideFloatingPostButton: false,
pauseOnUnfocused: true,
displayPageBackgrounds: true,
centerAlignBio: false,
compactUserInfo: true,
stopGifs: undefined,
replyVisibility: 'all',
thirdColumnMode: 'notifications',
@ -77,6 +79,7 @@ export const defaultState = {
hideScopeNotice: false,
useStreamingApi: false,
sidebarRight: undefined, // instance default
widenTimeline: undefined, // instance default
subjectLineBehavior: undefined, // instance default
alwaysShowSubjectInput: undefined, // instance default
postContentType: undefined, // instance default

View file

@ -67,6 +67,7 @@ const defaultState = {
showNavShortcuts: true,
showWiderShortcuts: true,
sidebarRight: false,
widenTimeline: false,
subjectLineBehavior: 'email',
theme: 'pleroma-dark',
virtualScrolling: true,
@ -83,6 +84,8 @@ const defaultState = {
conversationOtherRepliesButton: 'below',
conversationTreeFadeAncestors: false,
maxDepthInThread: 6,
backendCommitUrl: 'https://iceshrimp.dev/iceshrimp/akkoma-fe/commit/',
frontendCommitUrl: 'https://iceshrimp.dev/iceshrimp/Iceshrimp.NET/commit/',
// Nasty stuff
customEmoji: [],

View file

@ -1,227 +0,0 @@
.mfm {
display: inline-block;
}
._mfm_tada_ {
font-size: 150%;
animation: mfm-tada 1s linear infinite both;
}
._mfm_jelly_ {
animation: mfm-jelly 1s linear infinite both;
}
._mfm_twitch_ {
animation: mfm-twitch 0.5s ease infinite;
}
._mfm_shake_ {
animation: mfm-shake 0.5s ease infinite;
}
._mfm_spin_ {
animation: mfm-spin 0.5s linear infinite;
}
._mfm_spin_[data-x] {
animation-name: mfm-spinX;
}
._mfm_spin_[data-y] {
animation-name: mfm-spinY;
}
._mfm_spin_[left] {
animation-direction: reverse;
}
._mfm_spin_[alternate] {
animation-direction: alternate;
}
._mfm_jump_ {
animation: mfm-jump 0.75s linear infinite;
}
._mfm_bounce_ {
animation: mfm-bounce 0.75s linear infinite;
transform-origin: center bottom;
}
._mfm_flip_[data-h][data-v] {
transform: scale(-1, -1);
}
._mfm_flip_[data-v] {
transform: scaleY(-1);
}
._mfm_flip_:not([data-v]) {
transform: scaleX(-1);
}
._mfm_x2_ {
font-size: 200%;
}
._mfm_x3_ {
font-size: 400%;
}
._mfm_x4_ {
font-size: 600%;
}
._mfm_blur_ {
filter: blur(6px);
transition: filter 0.3s
}
._mfm_blur_:hover {
filter: blur(0px);
}
._mfm_rainbow_ {
animation: mfm-rainbow 1s linear infinite;
}
._mfm_rotate_ {
transform: rotate(90deg);
transform-origin: center center;
}
/* sparkle */
@keyframes mfm-tada {
from {
transform: scale3d(1, 1, 1);
}
10%,
20% {
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
}
30%,
50%,
70%,
90% {
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
}
40%,
60%,
80% {
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
}
to {
transform: scale3d(1, 1, 1);
}
}
@keyframes bounce {
0% {
transform: scaleX(0.9) scaleY(0.9);
}
19% {
transform: scaleX(1.1) scaleY(1.1);
}
48% {
transform: scaleX(0.95) scaleY(0.95);
}
100% {
transform: scaleX(1) scaleY(1);
}
}
@keyframes mfm-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes mfm-spinX {
0% { transform: perspective(128px) rotateX(0deg); }
100% { transform: perspective(128px) rotateX(360deg); }
}
@keyframes mfm-spinY {
0% { transform: perspective(128px) rotateY(0deg); }
100% { transform: perspective(128px) rotateY(360deg); }
}
@keyframes mfm-jump {
0% { transform: translateY(0); }
25% { transform: translateY(-16px); }
50% { transform: translateY(0); }
75% { transform: translateY(-8px); }
100% { transform: translateY(0); }
}
@keyframes mfm-bounce {
0% { transform: translateY(0) scale(1, 1); }
25% { transform: translateY(-16px) scale(1, 1); }
50% { transform: translateY(0) scale(1, 1); }
75% { transform: translateY(0) scale(1.5, 0.75); }
100% { transform: translateY(0) scale(1, 1); }
}
@keyframes mfm-twitch {
0% { transform: translate(7px, -2px); }
5% { transform: translate(-3px, 1px); }
10% { transform: translate(-7px, -1px); }
15% { transform: translate(0, -1px); }
20% { transform: translate(-8px, 6px); }
25% { transform: translate(-4px, -3px); }
30% { transform: translate(-4px, -6px); }
35% { transform: translate(-8px, -8px); }
40% { transform: translate(4px, 6px); }
45% { transform: translate(-3px, 1px); }
50% { transform: translate(2px, -10px); }
55% { transform: translate(-7px, 0); }
60% { transform: translate(-2px, 4px); }
65% { transform: translate(3px, -8px); }
70% { transform: translate(6px, 7px); }
75% { transform: translate(-7px, -2px); }
80% { transform: translate(-7px, -8px); }
85% { transform: translate(9px, 3px); }
90% { transform: translate(-3px, -2px); }
95% { transform: translate(-10px, 2px); }
100% { transform: translate(-2px, -6px); }
}
@keyframes mfm-shake {
0% { transform: translate(-3px, -1px) rotate(-8deg); }
5% { transform: translate(0, -1px) rotate(-10deg); }
10% { transform: translate(1px, -3px) rotate(0deg); }
15% { transform: translate(1px, 1px) rotate(11deg); }
20% { transform: translate(-2px, 1px) rotate(1deg); }
25% { transform: translate(-1px, -2px) rotate(-2deg); }
30% { transform: translate(-1px, 2px) rotate(-3deg); }
35% { transform: translate(2px, 1px) rotate(6deg); }
40% { transform: translate(-2px, -3px) rotate(-9deg); }
45% { transform: translate(0, -1px) rotate(-12deg); }
50% { transform: translate(1px, 2px) rotate(10deg); }
55% { transform: translate(0, -3px) rotate(8deg); }
60% { transform: translate(1px, -1px) rotate(8deg); }
65% { transform: translate(0, -1px) rotate(-7deg); }
70% { transform: translate(-1px, -3px) rotate(6deg); }
75% { transform: translate(0, -2px) rotate(4deg); }
80% { transform: translate(-2px, -1px) rotate(3deg); }
85% { transform: translate(1px, -3px) rotate(-10deg); }
90% { transform: translate(1px, 0) rotate(3deg); }
95% { transform: translate(-2px, 0) rotate(-3deg); }
100% { transform: translate(2px, 1px) rotate(2deg); }
}
@keyframes mfm-jelly {
from { transform: scale3d(1, 1, 1); }
30% { transform: scale3d(1.25, 0.75, 1); }
40% { transform: scale3d(0.75, 1.25, 1); }
50% { transform: scale3d(1.15, 0.85, 1); }
65% { transform: scale3d(0.95, 1.05, 1); }
75% { transform: scale3d(1.05, 0.95, 1); }
to { transform: scale3d(1, 1, 1); }
}
@keyframes mfm-rainbow {
0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); }
100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); }
}

View file

@ -40,6 +40,64 @@ describe('RichContent', () => {
expect(wrapper.html().replace(/\n/g, '')).to.eql(compwrap(html))
})
it('it adds a # to the MFM color style value', () => {
const html_ok = '<span class="mfm-fg" data-mfm-color="fff">this text is not white</span>'
const expected_ok = '<span class="mfm-fg" data-mfm-color="fff" style="--mfm-color: #fff;">this text is not white</span>'
const wrapper_ok = shallowMount(RichContent, {
global,
props: {
attentions,
handleLinks: true,
greentext: true,
emoji: [],
html: html_ok
}
})
expect(wrapper_ok.html()).to.eql(compwrap(expected_ok))
})
it('does not allow injection through MFM data- attributes', () => {
const html_ok = '<span class="mfm-spin" data-mfm-speed="-0.2s">brrr</span>'
const expected_ok = '<span class="mfm-spin" data-mfm-speed="-0.2s" style="--mfm-speed: -0.2s;">brrr</span>'
const wrapper_ok = shallowMount(RichContent, {
global,
props: {
attentions,
handleLinks: true,
greentext: true,
emoji: [],
html: html_ok
}
})
const html_nok1 = '<span class="mfm-spin" data-mfm-speed="<">brrr</span>'
const wrapper_nok1 = shallowMount(RichContent, {
global,
props: {
attentions,
handleLinks: true,
greentext: true,
emoji: [],
html: html_nok1
}
})
const html_nok2 = '<span class="mfm-spin" data-mfm-speed="\\">brrr</span>'
const wrapper_nok2 = shallowMount(RichContent, {
global,
props: {
attentions,
handleLinks: true,
greentext: true,
emoji: [],
html: html_nok2
}
})
expect(wrapper_ok.html()).to.eql(compwrap(expected_ok))
expect(wrapper_nok1.html()).to.eql(compwrap(html_nok1))
expect(wrapper_nok2.html()).to.eql(compwrap(html_nok2))
})
it('unescapes everything as needed', () => {
const html = [
p('Testing &#39;em all'),