Merge branch 'fixes-roundup3' into 'develop'

Fixes Roundup 3

See merge request pleroma/pleroma-fe!2013
This commit is contained in:
HJ 2025-01-28 14:54:05 +00:00
commit 753f5fa65d
43 changed files with 314 additions and 269 deletions

View file

@ -9,7 +9,7 @@ var ora = require('ora')
var webpack = require('webpack') var webpack = require('webpack')
var webpackConfig = require('./webpack.prod.conf') var webpackConfig = require('./webpack.prod.conf')
console.log( console.info(
' Tip:\n' + ' Tip:\n' +
' Built files are meant to be served over an HTTP server.\n' + ' Built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n' ' Opening index.html over file:// won\'t work.\n'

View file

@ -27,14 +27,12 @@ module.exports = function () {
} }
if (warnings.length) { if (warnings.length) {
console.log('') console.warn(chalk.yellow('\nTo use this template, you must update following to modules:\n'))
console.log(chalk.yellow('To use this template, you must update following to modules:'))
console.log()
for (var i = 0; i < warnings.length; i++) { for (var i = 0; i < warnings.length; i++) {
var warning = warnings[i] var warning = warnings[i]
console.log(' ' + warning) console.warn(' ' + warning)
} }
console.log() console.warn()
process.exit(1) process.exit(1)
} }
} }

View file

@ -72,10 +72,10 @@ app.use(staticPath, express.static('./static'))
module.exports = app.listen(port, function (err) { module.exports = app.listen(port, function (err) {
if (err) { if (err) {
console.log(err) console.error(err)
return return
} }
var uri = 'http://localhost:' + port var uri = 'http://localhost:' + port
console.log('Listening at ' + uri + '\n') console.info('Listening at ' + uri + '\n')
// opn(uri) // opn(uri)
}) })

View file

@ -23,7 +23,8 @@ module.exports = merge(baseWebpackConfig, {
'COMMIT_HASH': JSON.stringify('DEV'), 'COMMIT_HASH': JSON.stringify('DEV'),
'DEV_OVERRIDES': JSON.stringify(config.dev.settings), 'DEV_OVERRIDES': JSON.stringify(config.dev.settings),
'__VUE_OPTIONS_API__': true, '__VUE_OPTIONS_API__': true,
'__VUE_PROD_DEVTOOLS__': false '__VUE_PROD_DEVTOOLS__': false,
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': false
}), }),
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
new webpack.HotModuleReplacementPlugin(), new webpack.HotModuleReplacementPlugin(),

View file

@ -50,7 +50,8 @@ var webpackConfig = merge(baseWebpackConfig, {
'COMMIT_HASH': JSON.stringify(commitHash), 'COMMIT_HASH': JSON.stringify(commitHash),
'DEV_OVERRIDES': JSON.stringify(undefined), 'DEV_OVERRIDES': JSON.stringify(undefined),
'__VUE_OPTIONS_API__': true, '__VUE_OPTIONS_API__': true,
'__VUE_PROD_DEVTOOLS__': false '__VUE_PROD_DEVTOOLS__': false,
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': false
}), }),
// extract css into its own file // extract css into its own file
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({

View file

View file

@ -8,10 +8,10 @@ try {
// and that's how actual BE reports its url // and that's how actual BE reports its url
settings.target = settings.target.replace(/\/$/, '') settings.target = settings.target.replace(/\/$/, '')
} }
console.log('Using local dev server settings (/config/local.json):') console.info('Using local dev server settings (/config/local.json):')
console.log(JSON.stringify(settings, null, 2)) console.info(JSON.stringify(settings, null, 2))
} catch (e) { } catch (e) {
console.log('Local dev server settings not found (/config/local.json)') console.info('Local dev server settings not found (/config/local.json)')
} }
const target = settings.target || 'http://localhost:4000/' const target = settings.target || 'http://localhost:4000/'

View file

@ -174,8 +174,7 @@ const getTOS = async ({ store }) => {
throw (res) throw (res)
} }
} catch (e) { } catch (e) {
console.warn("Can't load TOS") console.warn("Can't load TOS\n", e)
console.warn(e)
} }
} }
@ -189,8 +188,7 @@ const getInstancePanel = async ({ store }) => {
throw (res) throw (res)
} }
} catch (e) { } catch (e) {
console.warn("Can't load instance panel") console.warn("Can't load instance panel\n", e)
console.warn(e)
} }
} }
@ -220,8 +218,7 @@ const getStickers = async ({ store }) => {
throw (res) throw (res)
} }
} catch (e) { } catch (e) {
console.warn("Can't load stickers") console.warn("Can't load stickers\n", e)
console.warn(e)
} }
} }

View file

@ -3,6 +3,9 @@ import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
import { getBookmarkFolderEntries } from 'src/components/navigation/filter.js' import { getBookmarkFolderEntries } from 'src/components/navigation/filter.js'
export const BookmarkFoldersMenuContent = { export const BookmarkFoldersMenuContent = {
props: [
'showPin'
],
components: { components: {
NavigationEntry NavigationEntry
}, },

View file

@ -7,10 +7,12 @@
label: 'nav.all_bookmarks', label: 'nav.all_bookmarks',
icon: 'bookmark' icon: 'bookmark'
}" }"
:show-pin="showPin"
/> />
<NavigationEntry <NavigationEntry
v-for="item in folders" v-for="item in folders"
:key="item.id" :key="item.id"
:show-pin="showPin"
:item="item" :item="item"
/> />
</ul> </ul>

View file

@ -5,7 +5,7 @@ import ConfirmModal from './confirm_modal.vue'
import Select from 'src/components/select/select.vue' import Select from 'src/components/select/select.vue'
export default { export default {
props: ['type', 'user'], props: ['type', 'user', 'status'],
emits: ['hide', 'show', 'muted'], emits: ['hide', 'show', 'muted'],
data: () => ({ data: () => ({
showing: false, showing: false,
@ -61,9 +61,7 @@ export default {
}, },
methods: { methods: {
optionallyPrompt () { optionallyPrompt () {
console.log('Triggered')
if (this.shouldConfirm) { if (this.shouldConfirm) {
console.log('SHAWN!!')
this.show() this.show()
} else { } else {
this.doMute() this.doMute()

View file

@ -162,7 +162,6 @@ const EmojiPicker = {
} else { } else {
emojiSizeReal = emojiSizeValue emojiSizeReal = emojiSizeValue
} }
console.log(emojiSizeReal)
const fullEmojiSize = emojiSizeReal + (2 * 0.2 * fontSizeMultiplier * 14) const fullEmojiSize = emojiSizeReal + (2 * 0.2 * fontSizeMultiplier * 14)
this.emojiSize = fullEmojiSize this.emojiSize = fullEmojiSize
@ -319,7 +318,6 @@ const EmojiPicker = {
return this.emojiSize return this.emojiSize
}, },
itemPerRow () { itemPerRow () {
console.log('CALC', this.emojiSize, this.width)
return this.width ? Math.floor(this.width / this.emojiSize) : 6 return this.width ? Math.floor(this.width / this.emojiSize) : 6
}, },
activeGroupView () { activeGroupView () {

View file

@ -32,6 +32,7 @@
<p>{{ $t("about.mrf.simple.accept_desc") }}</p> <p>{{ $t("about.mrf.simple.accept_desc") }}</p>
<table> <table>
<tbody>
<tr> <tr>
<th>{{ $t("about.mrf.simple.instance") }}</th> <th>{{ $t("about.mrf.simple.instance") }}</th>
<th>{{ $t("about.mrf.simple.reason") }}</th> <th>{{ $t("about.mrf.simple.reason") }}</th>
@ -48,6 +49,7 @@
{{ entry.reason }} {{ entry.reason }}
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
@ -57,6 +59,7 @@
<p>{{ $t("about.mrf.simple.reject_desc") }}</p> <p>{{ $t("about.mrf.simple.reject_desc") }}</p>
<table> <table>
<tbody>
<tr> <tr>
<th>{{ $t("about.mrf.simple.instance") }}</th> <th>{{ $t("about.mrf.simple.instance") }}</th>
<th>{{ $t("about.mrf.simple.reason") }}</th> <th>{{ $t("about.mrf.simple.reason") }}</th>
@ -73,6 +76,7 @@
{{ entry.reason }} {{ entry.reason }}
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
@ -82,6 +86,7 @@
<p>{{ $t("about.mrf.simple.quarantine_desc") }}</p> <p>{{ $t("about.mrf.simple.quarantine_desc") }}</p>
<table> <table>
<tbody>
<tr> <tr>
<th>{{ $t("about.mrf.simple.instance") }}</th> <th>{{ $t("about.mrf.simple.instance") }}</th>
<th>{{ $t("about.mrf.simple.reason") }}</th> <th>{{ $t("about.mrf.simple.reason") }}</th>
@ -98,6 +103,7 @@
{{ entry.reason }} {{ entry.reason }}
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
@ -107,6 +113,7 @@
<p>{{ $t("about.mrf.simple.ftl_removal_desc") }}</p> <p>{{ $t("about.mrf.simple.ftl_removal_desc") }}</p>
<table> <table>
<tbody>
<tr> <tr>
<th>{{ $t("about.mrf.simple.instance") }}</th> <th>{{ $t("about.mrf.simple.instance") }}</th>
<th>{{ $t("about.mrf.simple.reason") }}</th> <th>{{ $t("about.mrf.simple.reason") }}</th>
@ -123,6 +130,7 @@
{{ entry.reason }} {{ entry.reason }}
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
@ -132,6 +140,7 @@
<p>{{ $t("about.mrf.simple.media_nsfw_desc") }}</p> <p>{{ $t("about.mrf.simple.media_nsfw_desc") }}</p>
<table> <table>
<tbody>
<tr> <tr>
<th>{{ $t("about.mrf.simple.instance") }}</th> <th>{{ $t("about.mrf.simple.instance") }}</th>
<th>{{ $t("about.mrf.simple.reason") }}</th> <th>{{ $t("about.mrf.simple.reason") }}</th>
@ -148,6 +157,7 @@
{{ entry.reason }} {{ entry.reason }}
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
@ -157,6 +167,7 @@
<p>{{ $t("about.mrf.simple.media_removal_desc") }}</p> <p>{{ $t("about.mrf.simple.media_removal_desc") }}</p>
<table> <table>
<tbody>
<tr> <tr>
<th>{{ $t("about.mrf.simple.instance") }}</th> <th>{{ $t("about.mrf.simple.instance") }}</th>
<th>{{ $t("about.mrf.simple.reason") }}</th> <th>{{ $t("about.mrf.simple.reason") }}</th>
@ -173,6 +184,7 @@
{{ entry.reason }} {{ entry.reason }}
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>

View file

@ -113,6 +113,7 @@
:class="{ '-expanded': showBookmarkFolders }" :class="{ '-expanded': showBookmarkFolders }"
> >
<BookmarkFoldersMenuContent <BookmarkFoldersMenuContent
:show-pin="editMode || forceEditMode"
class="timelines" class="timelines"
/> />
</div> </div>

View file

@ -1,6 +1,8 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { TIMELINES, ROOT_ITEMS, routeTo } from 'src/components/navigation/navigation.js' import { TIMELINES, ROOT_ITEMS, routeTo } from 'src/components/navigation/navigation.js'
import { getListEntries, filterNavigation } from 'src/components/navigation/filter.js' import { getBookmarkFolderEntries, getListEntries, filterNavigation } from 'src/components/navigation/filter.js'
import StillImage from 'src/components/still-image/still-image.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -34,12 +36,16 @@ const NavPanel = {
return routeTo(item, this.currentUser) return routeTo(item, this.currentUser)
} }
}, },
components: {
StillImage
},
computed: { computed: {
getters () { getters () {
return this.$store.getters return this.$store.getters
}, },
...mapState({ ...mapState({
lists: getListEntries, lists: getListEntries,
bookmarks: getBookmarkFolderEntries,
currentUser: state => state.users.currentUser, currentUser: state => state.users.currentUser,
followRequestCount: state => state.api.followRequests.length, followRequestCount: state => state.api.followRequests.length,
privateMode: state => state.instance.private, privateMode: state => state.instance.private,
@ -70,6 +76,7 @@ const NavPanel = {
.filter(([k]) => this.pinnedItems.has(k)) .filter(([k]) => this.pinnedItems.has(k))
.map(([k, v]) => ({ ...v, name: k })), .map(([k, v]) => ({ ...v, name: k })),
...this.lists.filter((k) => this.pinnedItems.has(k.name)), ...this.lists.filter((k) => this.pinnedItems.has(k.name)),
...this.bookmarks.filter((k) => this.pinnedItems.has(k.name)),
...Object ...Object
.entries({ ...ROOT_ITEMS }) .entries({ ...ROOT_ITEMS })
.filter(([k]) => this.pinnedItems.has(k)) .filter(([k]) => this.pinnedItems.has(k))

View file

@ -14,9 +14,14 @@
:icon="item.icon" :icon="item.icon"
/> />
<span <span
v-if="item.iconLetter" v-if="item.iconLetter && !item.iconEmoji"
class="iconLetter fa-scale-110 fa-old-padding" class="iconLetter fa-scale-110 fa-old-padding"
>{{ item.iconLetter }}</span> >{{ item.iconLetter }}</span>
<StillImage
v-if="item.iconEmoji"
class="bookmark-emoji"
:src="item.iconEmojiUrl"
/>
<div <div
v-if="item.badgeGetter && getters[item.badgeGetter]" v-if="item.badgeGetter && getters[item.badgeGetter]"
class="badge -dot" class="badge -dot"
@ -52,6 +57,13 @@
box-sizing: border-box; box-sizing: border-box;
height: 100%; height: 100%;
.bookmark-emoji {
height: 100%;
box-sizing: border-box;
padding: 0.5em;
}
& .bookmark-emoji,
& .svg-inline--fa, & .svg-inline--fa,
& .iconLetter { & .iconLetter {
margin: 0; margin: 0;

View file

@ -3,7 +3,6 @@
trigger="click" trigger="click"
class="QuickViewSettings" class="QuickViewSettings"
:bound-to="{ x: 'container' }" :bound-to="{ x: 'container' }"
:trigger-attrs="triggerAttrs"
> >
<template #content> <template #content>
<div <div

View file

@ -8,6 +8,10 @@
--funtextGreentext: var(--funtextGreentextFaint) !important; --funtextGreentext: var(--funtextGreentextFaint) !important;
--funtextCyantext: var(--funtextCyantextFaint) !important; --funtextCyantext: var(--funtextCyantextFaint) !important;
/* stylelint-enable declaration-no-important */ /* stylelint-enable declaration-no-important */
a {
color: var(--linkFaint);
}
} }
blockquote { blockquote {

View file

@ -30,6 +30,11 @@ const GeneralTab = {
value: mode, value: mode,
label: this.$t(`settings.conversation_display_${mode}`) label: this.$t(`settings.conversation_display_${mode}`)
})), })),
absoluteTime12hOptions: ['24h', '12h'].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.absolute_time_format_12h_${mode}`)
})),
conversationOtherRepliesButtonOptions: ['below', 'inside'].map(mode => ({ conversationOtherRepliesButtonOptions: ['below', 'inside'].map(mode => ({
key: mode, key: mode,
value: mode, value: mode,

View file

@ -249,6 +249,16 @@
{{ $t('settings.absolute_time_format_min_age') }} {{ $t('settings.absolute_time_format_min_age') }}
</UnitSetting> </UnitSetting>
</li> </li>
<li>
<ChoiceSetting
id="absoluteTime12h"
path="absoluteTime12h"
:options="absoluteTime12hOptions"
:expert="1"
>
{{ $t('settings.absolute_time_format_12h') }}
</ChoiceSetting>
</li>
</ul> </ul>
<h3>{{ $t('settings.attachments') }}</h3> <h3>{{ $t('settings.attachments') }}</h3>
<li> <li>
@ -462,22 +472,6 @@
{{ $t('settings.minimal_scopes_mode') }} {{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li>
<BooleanSetting
path="alwaysShowNewPostButton"
expert="1"
>
{{ $t('settings.always_show_post_button') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="autohideFloatingPostButton"
expert="1"
>
{{ $t('settings.autohide_floating_post_button') }}
</BooleanSetting>
</li>
<li> <li>
<BooleanSetting <BooleanSetting
path="padEmoji" path="padEmoji"
@ -501,7 +495,7 @@
{{ $t('settings.auto_save_draft') }} {{ $t('settings.auto_save_draft') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li v-if="!autoSaveDraft"> <li v-if="!mergedConfig.autoSaveDraft">
<ChoiceSetting <ChoiceSetting
id="unsavedPostAction" id="unsavedPostAction"
path="unsavedPostAction" path="unsavedPostAction"

View file

@ -130,7 +130,7 @@ export default {
const serialized = this.cValue.map(x => serializeShadow(x)).join(',') const serialized = this.cValue.map(x => serializeShadow(x)).join(',')
serialized.split(/,/).map(deserializeShadow) // validate serialized.split(/,/).map(deserializeShadow) // validate
const expandedShadow = flattenDeep(findShadow(this.cValue, { dynamicVars: {}, staticVars: this.staticVars })) const expandedShadow = flattenDeep(findShadow(this.cValue, { dynamicVars: {}, staticVars: this.staticVars }))
const fixedShadows = expandedShadow.map(x => ({ ...x, color: console.log(x) || rgb2hex(x.color) })) const fixedShadows = expandedShadow.map(x => ({ ...x, color: rgb2hex(x.color) }))
if (this.separateInset) { if (this.separateInset) {
result = { result = {

View file

@ -255,7 +255,7 @@ const Status = {
muteReasons () { muteReasons () {
return [ return [
this.userIsMuted ? 'user' : null, this.userIsMuted ? 'user' : null,
status.thread_muted ? 'thread' : null, this.status.thread_muted ? 'thread' : null,
(this.muteWordHits.length > 0) ? 'wordfilter' : null, (this.muteWordHits.length > 0) ? 'wordfilter' : null,
(this.muteBotStatuses && this.botStatus) ? 'bot' : null, (this.muteBotStatuses && this.botStatus) ? 'bot' : null,
(this.muteSensitiveStatuses && this.sensitiveStatus) ? 'nsfw' : null (this.muteSensitiveStatuses && this.sensitiveStatus) ? 'nsfw' : null
@ -280,6 +280,7 @@ const Status = {
case 'nsfw': return this.$t('status.sensitive_muted') case 'nsfw': return this.$t('status.sensitive_muted')
} }
} }
if (this.muteReasons.length > 1) {
return this.$t( return this.$t(
'status.multi_reason_mute', 'status.multi_reason_mute',
{ {
@ -288,6 +289,9 @@ const Status = {
}, },
this.muteReasons.length - 1 this.muteReasons.length - 1
) )
} else {
return mainReason()
}
}, },
muted () { muted () {
if (this.statusoid.user.id === this.currentUser.id) return false if (this.statusoid.user.id === this.currentUser.id) return false
@ -299,9 +303,9 @@ const Status = {
const { reblog } = status const { reblog } = status
const relationship = this.$store.getters.relationship(status.user.id) const relationship = this.$store.getters.relationship(status.user.id)
const relationshipReblog = reblog && this.$store.getters.relationship(reblog.user.id) const relationshipReblog = reblog && this.$store.getters.relationship(reblog.user.id)
return status.muted || return (status.muted && !status.thread_muted) ||
// Reprööt of a muted post according to BE // Reprööt of a muted post according to BE
(reblog && reblog.muted) || (reblog && reblog.muted && !reblog.thread_muted) ||
// Muted user // Muted user
relationship.muting || relationship.muting ||
// Muted user of a reprööt // Muted user of a reprööt

View file

@ -92,6 +92,9 @@ export default {
threadIsMuted () { threadIsMuted () {
return this.status.thread_muted return this.status.thread_muted
}, },
hideCustomEmoji () {
return !this.$store.state.instance.pleromaCustomEmojiReactionsAvailable
},
buttonInnerClass () { buttonInnerClass () {
return [ return [
this.button.name + '-button', this.button.name + '-button',

View file

@ -2,9 +2,9 @@
/* stylelint-disable declaration-no-important */ /* stylelint-disable declaration-no-important */
.quick-action { .quick-action {
display: grid; justify-content: space-between;
grid-template-columns: minmax(max-content, 1fr); display: flex;
grid-gap: 0.25em; align-items: baseline;
align-items: center; align-items: center;
height: 1.5em; height: 1.5em;
@ -12,6 +12,7 @@
overflow-x: hidden; overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
margin-left: 1em;
} }
.action-button-inner, .action-button-inner,
@ -25,6 +26,7 @@
align-self: stretch; align-self: stretch;
width: 1px; width: 1px;
background-color: var(--icon); background-color: var(--icon);
margin-left: 1em;
margin-right: 0.5em; margin-right: 0.5em;
} }
@ -35,6 +37,7 @@
border-radius: var(--roundness); border-radius: var(--roundness);
grid-template-columns: minmax(max-content, 1fr) auto; grid-template-columns: minmax(max-content, 1fr) auto;
.chevron-icon,
.extra-button, .extra-button,
.separator { .separator {
display: none; display: none;
@ -44,10 +47,30 @@
.action-button-inner { .action-button-inner {
display: grid; display: grid;
grid-gap: 1em; grid-gap: 1em;
grid-template-columns: max-content 1fr; grid-template-columns: max-content;
grid-auto-flow: column; grid-auto-flow: column;
grid-auto-columns: max-content; grid-auto-columns: max-content;
align-items: center; align-items: center;
@include unfocused-style {
.focus-marker {
visibility: hidden;
}
.active-marker {
visibility: visible;
}
}
@include focused-style {
.focus-marker {
visibility: visible;
}
.active-marker {
visibility: hidden;
}
}
} }
} }
@ -79,24 +102,4 @@
} }
} }
} }
@include unfocused-style {
.focus-marker {
visibility: hidden;
}
.active-marker {
visibility: visible;
}
}
@include focused-style {
.focus-marker {
visibility: visible;
}
.active-marker {
visibility: hidden;
}
}
} }

View file

@ -9,6 +9,7 @@
:class="buttonInnerClass" :class="buttonInnerClass"
role="menuitem" role="menuitem"
type="button" type="button"
:title="$t(button.label(funcArg))"
target="_blank" target="_blank"
:tabindex="0" :tabindex="0"
:disabled="buttonClass.disabled" :disabled="buttonClass.disabled"
@ -50,12 +51,6 @@
> >
{{ $t(button.label(funcArg)) }} {{ $t(button.label(funcArg)) }}
</span> </span>
<span
v-if="!extra && button.counter?.(funcArg) > 0"
class="action-counter"
>
{{ button.counter?.(funcArg) }}
</span>
<FAIcon <FAIcon
v-if="button.dropdown?.()" v-if="button.dropdown?.()"
class="chevron-icon" class="chevron-icon"
@ -64,15 +59,21 @@
fixed-width fixed-width
/> />
</component> </component>
<span
v-if="!extra && button.counter?.(funcArg) > 0"
class="action-counter"
>
{{ button.counter?.(funcArg) }}
</span>
<span <span
v-if="!extra && button.name === 'bookmark'" v-if="!extra && button.name === 'bookmark'"
class="separator" class="separator"
/> />
<Popover <Popover
v-if="button.name === 'bookmark'" v-if="button.name === 'bookmark'"
trigger="hover" :trigger="extra ? 'hover' : 'click'"
:placement="extra ? 'right' : 'top'" :placement="extra ? 'right' : 'top'"
:offset="{ y: 5 }" :offset="extra ? { x: 10 } : { y: 10 }"
:trigger-attrs="{ class: 'extra-button' }" :trigger-attrs="{ class: 'extra-button' }"
> >
<template #trigger> <template #trigger>

View file

@ -58,8 +58,8 @@ export default {
unmuteUser () { unmuteUser () {
return this.$store.dispatch('unmuteUser', this.user.id) return this.$store.dispatch('unmuteUser', this.user.id)
}, },
unmuteThread () { unmuteConversation () {
return this.$store.dispatch('unmuteConversation', this.user.id) return this.$store.dispatch('unmuteConversation', { id: this.status.id })
}, },
unmuteDomain () { unmuteDomain () {
return this.$store.dispatch('unmuteDomain', this.user.id) return this.$store.dispatch('unmuteDomain', this.user.id)

View file

@ -2,7 +2,7 @@
<div> <div>
<Popover <Popover
v-if="button.dropdown?.()" v-if="button.dropdown?.()"
trigger="hover" :trigger="$attrs.extra ? 'hover' : 'click'"
:offset="{ y: 5 }" :offset="{ y: 5 }"
:placement="$attrs.extra ? 'right' : 'top'" :placement="$attrs.extra ? 'right' : 'top'"
> >
@ -40,13 +40,13 @@
<div class="menu-item dropdown-item extra-action -icon"> <div class="menu-item dropdown-item extra-action -icon">
<button <button
class="main-button" class="main-button"
@click="toggleUserMute" @click="toggleConversationMute"
> >
<FAIcon <FAIcon
icon="folder-tree" icon="folder-tree"
fixed-width fixed-width
/> />
<template v-if="threadIsMuted"> <template v-if="conversationIsMuted">
{{ $t('status.unmute_conversation') }} {{ $t('status.unmute_conversation') }}
</template> </template>
<template v-else> <template v-else>
@ -81,19 +81,22 @@
v-bind="$attrs" v-bind="$attrs"
/> />
<teleport to="#modal"> <teleport to="#modal">
<mute-confirm <MuteConfirm
ref="confirmConversation" ref="confirmConversation"
type="conversation" type="conversation"
:status="status" :status="status"
/>
<mute-confirm
ref="confirmDomain"
type="domain"
:user="user" :user="user"
/> />
<mute-confirm <MuteConfirm
ref="confirmDomain"
type="domain"
:status="status"
:user="user"
/>
<MuteConfirm
ref="confirmUser" ref="confirmUser"
type="user" type="user"
:status="status"
:user="user" :user="user"
/> />
</teleport> </teleport>

View file

@ -51,9 +51,6 @@ const StatusActionButtons = {
currentUser () { currentUser () {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
hideCustomEmoji () {
return !this.$store.state.instance.pleromaCustomEmojiReactionsAvailable
},
funcArg () { funcArg () {
return { return {
status: this.status, status: this.status,
@ -71,7 +68,6 @@ const StatusActionButtons = {
return { return {
title: this.$t('status.more_actions'), title: this.$t('status.more_actions'),
'aria-controls': `popup-menu-${this.randomSeed}`, 'aria-controls': `popup-menu-${this.randomSeed}`,
'aria-expanded': this.expanded,
'aria-haspopup': 'menu' 'aria-haspopup': 'menu'
} }
} }

View file

@ -3,12 +3,11 @@
.StatusActionButtons { .StatusActionButtons {
.quick-action-buttons { .quick-action-buttons {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, 5em); grid-template-columns: repeat(auto-fill, 4em);
grid-auto-flow: row dense; grid-auto-flow: row dense;
grid-auto-rows: 1fr; grid-auto-rows: 1fr;
grid-gap: 1.25em 1em; grid-gap: 1.25em 1em;
margin-top: var(--status-margin); margin-top: var(--status-margin);
align-items: baseline;
} }
.pin-action-button { .pin-action-button {

View file

@ -28,6 +28,9 @@ export default {
} }
return DateUtils.durationStrToMs(this.$store.getters.mergedConfig.absoluteTimeFormatMinAge) <= this.relativeTimeMs return DateUtils.durationStrToMs(this.$store.getters.mergedConfig.absoluteTimeFormatMinAge) <= this.relativeTimeMs
}, },
time12hFormat () {
return this.$store.getters.mergedConfig.absoluteTimeFormat12h === '12h'
},
browserLocale () { browserLocale () {
return localeService.internalToBrowserLocale(this.$i18n.locale) return localeService.internalToBrowserLocale(this.$i18n.locale)
}, },
@ -57,22 +60,26 @@ export default {
if (DateUtils.isSameDay(this.timeAsDate, now)) { if (DateUtils.isSameDay(this.timeAsDate, now)) {
return new Intl.DateTimeFormat(this.browserLocale, { return new Intl.DateTimeFormat(this.browserLocale, {
minute: 'numeric', minute: 'numeric',
hour: 'numeric' hour: 'numeric',
hour12: this.time12hFormat
}) })
} else if (DateUtils.isSameMonth(this.timeAsDate, now)) { } else if (DateUtils.isSameMonth(this.timeAsDate, now)) {
return new Intl.DateTimeFormat(this.browserLocale, { return new Intl.DateTimeFormat(this.browserLocale, {
month: 'short', month: 'short',
day: 'numeric' day: 'numeric',
hour12: this.time12hFormat
}) })
} else if (DateUtils.isSameYear(this.timeAsDate, now)) { } else if (DateUtils.isSameYear(this.timeAsDate, now)) {
return new Intl.DateTimeFormat(this.browserLocale, { return new Intl.DateTimeFormat(this.browserLocale, {
month: 'short', month: 'short',
day: 'numeric' day: 'numeric',
hour12: this.time12hFormat
}) })
} else { } else {
return new Intl.DateTimeFormat(this.browserLocale, { return new Intl.DateTimeFormat(this.browserLocale, {
year: 'numeric', year: 'numeric',
month: 'short' month: 'short',
hour12: this.time12hFormat
}) })
} }
})() })()

View file

@ -311,7 +311,7 @@
/> />
</div> </div>
<teleport to="#modal"> <teleport to="#modal">
<mute-confirm <MuteConfirm
ref="confirmation" ref="confirmation"
type="user" type="user"
:user="user" :user="user"

View file

@ -2,23 +2,23 @@
const arg = process.argv[2] const arg = process.argv[2]
if (typeof arg === 'undefined') { if (typeof arg === 'undefined') {
console.log('This is a very simple and tiny tool that checks en.json with any other language and') console.info('This is a very simple and tiny tool that checks en.json with any other language and')
console.log('outputs all the things present in english but missing in foreign language.') console.info('outputs all the things present in english but missing in foreign language.')
console.log('') console.info('')
console.log('Usage: ./compare.js <lang> ') console.info('Usage: ./compare.js <lang> ')
console.log(' or') console.info(' or')
console.log(' node ./compare.js <lang>') console.info(' node ./compare.js <lang>')
console.log('') console.info('')
console.log('Where <lang> is name of .json file containing language. For ./fi.json it should be:') console.info('Where <lang> is name of .json file containing language. For ./fi.json it should be:')
console.log(' ./compare.js fi ') console.info(' ./compare.js fi ')
console.log('') console.info('')
console.log('Limitations: ') console.info('Limitations: ')
console.log('* This program does not work with languages left over in messages.js') console.info('* This program does not work with languages left over in messages.js')
console.log('* This program does not check for extra strings present in foreign language but missing') console.info('* This program does not check for extra strings present in foreign language but missing')
console.log(' in english.js (for now)') console.info(' in english.js (for now)')
console.log('') console.info('')
console.log('There are no other arguments or options. Make an issue if you encounter a bug or want') console.info('There are no other arguments or options. Make an issue if you encounter a bug or want')
console.log('some feature to be implemented. Merge requests are welcome as well.') console.info('some feature to be implemented. Merge requests are welcome as well.')
process.exit() process.exit()
} }
@ -35,10 +35,10 @@ function walker (a, b, path = []) {
const article = aType[0] === 'o' ? 'an' : 'a' const article = aType[0] === 'o' ? 'an' : 'a'
if (bType === 'undefined') { if (bType === 'undefined') {
console.log(`Foreign language is missing ${article} ${aType} at path ${currentPath.join('.')}`) console.warn(`Foreign language is missing ${article} ${aType} at path ${currentPath.join('.')}`)
} else if (aType === 'object') { } else if (aType === 'object') {
if (bType !== 'object') { if (bType !== 'object') {
console.log(`Type mismatch! English has ${aType} while foreign has ${bType} at path ${currentPath.join['.']}`) console.warn(`Type mismatch! English has ${aType} while foreign has ${bType} at path ${currentPath.join['.']}`)
} else { } else {
walker(aVal, bVal, currentPath) walker(aVal, bVal, currentPath)
} }

View file

@ -532,6 +532,9 @@
"emoji_reactions_scale": "Reactions scale factor", "emoji_reactions_scale": "Reactions scale factor",
"absolute_time_format": "Use absolute time format", "absolute_time_format": "Use absolute time format",
"absolute_time_format_min_age": "Only use for time older than this amount of time", "absolute_time_format_min_age": "Only use for time older than this amount of time",
"absolute_time_format_12h": "Time format",
"absolute_time_format_12h_12h": "12 hour format (i.e. 10:00 PM)",
"absolute_time_format_12h_24h": "24 hour format (i.e. 22:00)",
"export_theme": "Save preset", "export_theme": "Save preset",
"filtering": "Filtering", "filtering": "Filtering",
"wordfilter": "Wordfilter", "wordfilter": "Wordfilter",
@ -1256,7 +1259,7 @@
"copy_link": "Copy link to status", "copy_link": "Copy link to status",
"external_source": "External source", "external_source": "External source",
"muted_words": "Wordfiltered: {word} | Wordfiltered: {word} and {numWordsMore} more words", "muted_words": "Wordfiltered: {word} | Wordfiltered: {word} and {numWordsMore} more words",
"multi_reason_mute": "{main} | {main} + one more reason | {main} + {numReasonsMore} more reasons", "multi_reason_mute": "{main} + one more reason | {main} + {numReasonsMore} more reasons",
"muted_user": "User muted", "muted_user": "User muted",
"thread_muted": "Thread muted", "thread_muted": "Thread muted",
"thread_muted_and_words": ", has words:", "thread_muted_and_words": ", has words:",

View file

@ -193,6 +193,7 @@ export const defaultState = {
autoSaveDraft: undefined, // instance default autoSaveDraft: undefined, // instance default
useAbsoluteTimeFormat: undefined, // instance default useAbsoluteTimeFormat: undefined, // instance default
absoluteTimeFormatMinAge: undefined, // instance default absoluteTimeFormatMinAge: undefined, // instance default
absoluteTime12h: undefined, // instance default
imageCompression: true imageCompression: true
} }

View file

@ -131,6 +131,7 @@ const defaultState = {
autoSaveDraft: false, autoSaveDraft: false,
useAbsoluteTimeFormat: false, useAbsoluteTimeFormat: false,
absoluteTimeFormatMinAge: '0d', absoluteTimeFormatMinAge: '0d',
absoluteTime12h: '24h',
// Nasty stuff // Nasty stuff
customEmoji: [], customEmoji: [],
@ -314,8 +315,7 @@ const instance = {
}, {}) }, {})
commit('setInstanceOption', { name: 'emoji', value: injectRegionalIndicators(emoji) }) commit('setInstanceOption', { name: 'emoji', value: injectRegionalIndicators(emoji) })
} catch (e) { } catch (e) {
console.warn("Can't load static emoji") console.warn("Can't load static emoji\n", e)
console.warn(e)
} }
}, },
@ -382,8 +382,7 @@ const instance = {
throw (res) throw (res)
} }
} catch (e) { } catch (e) {
console.warn("Can't load custom emojis") console.warn("Can't load custom emojis\n", e)
console.warn(e)
} }
}, },
fetchEmoji ({ dispatch, state }) { fetchEmoji ({ dispatch, state }) {
@ -404,8 +403,7 @@ const instance = {
}) })
commit('setKnownDomains', result) commit('setKnownDomains', result)
} catch (e) { } catch (e) {
console.warn("Can't load known domains") console.warn("Can't load known domains\n", e)
console.warn(e)
} }
} }
} }

View file

@ -9,7 +9,8 @@ import {
groupBy, groupBy,
findLastIndex, findLastIndex,
takeRight, takeRight,
uniqWith uniqWith,
merge as _merge
} from 'lodash' } from 'lodash'
import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js' import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js'
@ -127,14 +128,8 @@ export const _getRecentData = (cache, live, isTest) => {
_version: a._version ?? b._version, _version: a._version ?? b._version,
_timestamp: a._timestamp ?? b._timestamp, _timestamp: a._timestamp ?? b._timestamp,
needUpload: b.needUpload ?? a.needUpload, needUpload: b.needUpload ?? a.needUpload,
prefsStorage: { prefsStorage: _merge(a.prefsStorage, b.prefsStorage),
...a.prefsStorage, flagStorage: _merge(a.flagStorage, b.flagStorage)
...b.prefsStorage
},
flagStorage: {
...a.flagStorage,
...b.flagStorage
}
}) })
result.recent = isTest ? result.recent : (result.recent && merge(defaultState, result.recent)) result.recent = isTest ? result.recent : (result.recent && merge(defaultState, result.recent))
result.stale = isTest ? result.stale : (result.stale && merge(defaultState, result.stale)) result.stale = isTest ? result.stale : (result.stale && merge(defaultState, result.stale))
@ -315,7 +310,7 @@ export const mutations = {
state.raw = live state.raw = live
let cache = state.cache let cache = state.cache
if (cache && cache._user !== userData.fqn) { if (cache && cache._user !== userData.fqn) {
console.warn('cache belongs to another user! reinitializing local cache!') console.warn('Cache belongs to another user! reinitializing local cache!')
cache = null cache = null
} }

View file

@ -276,8 +276,8 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
// NOOP, it is known status but we don't do anything about it for now // NOOP, it is known status but we don't do anything about it for now
}, },
default: (unknown) => { default: (unknown) => {
console.log('unknown status type') console.warn('unknown status type')
console.log(unknown) console.warn(unknown)
} }
} }
@ -549,11 +549,11 @@ const statuses = {
rootState.api.backendInteractor.unpinOwnStatus({ id: statusId }) rootState.api.backendInteractor.unpinOwnStatus({ id: statusId })
.then((status) => dispatch('addNewStatuses', { statuses: [status] })) .then((status) => dispatch('addNewStatuses', { statuses: [status] }))
}, },
muteConversation ({ rootState, commit }, statusId) { muteConversation ({ rootState, commit }, { id: statusId }) {
return rootState.api.backendInteractor.muteConversation({ id: statusId }) return rootState.api.backendInteractor.muteConversation({ id: statusId })
.then((status) => commit('setMutedStatus', status)) .then((status) => commit('setMutedStatus', status))
}, },
unmuteConversation ({ rootState, commit }, statusId) { unmuteConversation ({ rootState, commit }, { id: statusId }) {
return rootState.api.backendInteractor.unmuteConversation({ id: statusId }) return rootState.api.backendInteractor.unmuteConversation({ id: statusId })
.then((status) => commit('setMutedStatus', status)) .then((status) => commit('setMutedStatus', status))
}, },

View file

@ -1,7 +1,7 @@
import { invertLightness, contrastRatio, convert } from 'chromatism' import { invertLightness, contrastRatio, convert } from 'chromatism'
// useful for visualizing color when debugging // useful for visualizing color when debugging
export const consoleColor = (color) => console.log('%c##########', 'background: ' + color + '; color: ' + color) // const consoleColor = (color) => console.debug('%c##########', 'background: ' + color + '; color: ' + color)
/** /**
* Convert r, g, b values into hex notation. All components are [0-255] * Convert r, g, b values into hex notation. All components are [0-255]
@ -236,8 +236,8 @@ export const getTextColor = function (bg, text, preserve) {
let contrast = getContrastRatio(bg, text) let contrast = getContrastRatio(bg, text)
const result = convert(rgb2hex(workColor)).hsl const result = convert(rgb2hex(workColor)).hsl
const delta = result.l > 50 ? 1 : -1 const delta = result.l >= 50 ? 1 : -1
const multiplier = 10 const multiplier = 1
while (contrast < 4.5 && result.l > 20 && result.l < 80) { while (contrast < 4.5 && result.l > 20 && result.l < 80) {
result.l += delta * multiplier result.l += delta * multiplier
result.l = Math.min(100, Math.max(0, result.l)) result.l = Math.min(100, Math.max(0, result.l))

View file

@ -3,7 +3,7 @@ import utf8 from 'utf8'
export const newExporter = ({ export const newExporter = ({
filename = 'data', filename = 'data',
mime = 'application/json', mime = 'application/json',
extension = '.json', extension = 'json',
getExportedObject getExportedObject
}) => ({ }) => ({
exportData () { exportData () {

View file

@ -95,9 +95,10 @@ export const tryLoadCache = async () => {
if (!data) return null if (!data) return null
let cache let cache
try { try {
const decoded = new TextDecoder().decode(pako.inflate(data)) const inflated = pako.inflate(data)
const decoded = new TextDecoder().decode(inflated)
cache = JSON.parse(decoded) cache = JSON.parse(decoded)
console.info(`Loaded theme from cache, size=${cache}`) console.info(`Loaded theme from cache, compressed=${Math.ceil(data.length / 1024)}kiB size=${Math.ceil(inflated.length / 1024)}kiB`)
} catch (e) { } catch (e) {
console.error('Failed to decode theme cache:', e) console.error('Failed to decode theme cache:', e)
return false return false

View file

@ -539,7 +539,6 @@ describe('RichContent', () => {
`, `,
props: ['handleLinks', 'attentions', 'vhtml'] props: ['handleLinks', 'attentions', 'vhtml']
} }
console.log(1)
const ptest = (handleLinks, vhtml) => { const ptest = (handleLinks, vhtml) => {
const t0 = performance.now() const t0 = performance.now()
@ -562,11 +561,11 @@ describe('RichContent', () => {
return `Mount: ${t1 - t0}ms, destroy: ${t2 - t1}ms, avg ${(t1 - t0) / amount}ms - ${(t2 - t1) / amount}ms per item` return `Mount: ${t1 - t0}ms, destroy: ${t2 - t1}ms, avg ${(t1 - t0) / amount}ms - ${(t2 - t1) / amount}ms per item`
} }
console.log(`${amount} items with links handling:`) console.debug(`${amount} items with links handling:`)
console.log(ptest(true)) console.debug(ptest(true))
console.log(`${amount} items without links handling:`) console.debug(`${amount} items without links handling:`)
console.log(ptest(false)) console.debug(ptest(false))
console.log(`${amount} items plain v-html:`) console.debug(`${amount} items plain v-html:`)
console.log(ptest(false, true)) console.debug(ptest(false, true))
}) })
}) })

View file

@ -21,17 +21,17 @@ describe('ISS (de)serialization', () => {
const onlyComponent = componentsContext('./components/panel_header.style.js').default const onlyComponent = componentsContext('./components/panel_header.style.js').default
it.only(`(De)serialization of component ${onlyComponent.name} works`, () => { it.only(`(De)serialization of component ${onlyComponent.name} works`, () => {
const normalized = onlyComponent.defaultRules.map(x => ({ component: onlyComponent.name, ...x })) const normalized = onlyComponent.defaultRules.map(x => ({ component: onlyComponent.name, ...x }))
console.log('BEGIN INPUT ================') console.debug('BEGIN INPUT ================')
console.log(normalized) console.debug(normalized)
console.log('END INPUT ==================') console.debug('END INPUT ==================')
const serialized = serialize(normalized) const serialized = serialize(normalized)
console.log('BEGIN SERIAL ===============') console.debug('BEGIN SERIAL ===============')
console.log(serialized) console.debug(serialized)
console.log('END SERIAL =================') console.debug('END SERIAL =================')
const deserialized = deserialize(serialized) const deserialized = deserialize(serialized)
console.log('BEGIN DESERIALIZED =========') console.debug('BEGIN DESERIALIZED =========')
console.log(serialized) console.debug(serialized)
console.log('END DESERIALIZED ===========') console.debug('END DESERIALIZED ===========')
// for some reason comparing objects directly fails the assert // for some reason comparing objects directly fails the assert
expect(JSON.stringify(deserialized, null, 2)).to.equal(JSON.stringify(normalized, null, 2)) expect(JSON.stringify(deserialized, null, 2)).to.equal(JSON.stringify(normalized, null, 2))

View file

@ -60,7 +60,7 @@ const run = () => {
}, {}) }, {})
fs.writeFile(outputFilename, JSON.stringify(sorted, null, 2), 'utf8', (err) => { fs.writeFile(outputFilename, JSON.stringify(sorted, null, 2), 'utf8', (err) => {
if (err) console.log('Error writing file', err) if (err) console.error('Error writing file', err)
}) })
} }