Merge remote-tracking branch 'origin/develop' into sss-objects
This commit is contained in:
commit
4d5333102e
28 changed files with 788 additions and 983 deletions
1
changelog.d/better-scroll-button.add
Normal file
1
changelog.d/better-scroll-button.add
Normal file
|
|
@ -0,0 +1 @@
|
|||
Add support for detachable scrollTop button
|
||||
0
changelog.d/fix-wrap.skip
Normal file
0
changelog.d/fix-wrap.skip
Normal file
17
package.json
17
package.json
|
|
@ -72,19 +72,20 @@
|
|||
"babel-plugin-lodash": "3.3.4",
|
||||
"chai": "5.2.0",
|
||||
"chalk": "5.4.1",
|
||||
"chromedriver": "134.0.5",
|
||||
"chromedriver": "135.0.0",
|
||||
"connect-history-api-fallback": "2.0.0",
|
||||
"cross-spawn": "7.0.6",
|
||||
"custom-event-polyfill": "1.0.7",
|
||||
"eslint": "9.23.0",
|
||||
"eslint": "9.24.0",
|
||||
"vue-eslint-parser": "10.1.3",
|
||||
"eslint-config-standard": "17.1.0",
|
||||
"eslint-formatter-friendly": "7.0.0",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-n": "17.17.0",
|
||||
"eslint-plugin-promise": "7.2.1",
|
||||
"eslint-plugin-vue": "9.33.0",
|
||||
"eslint-plugin-vue": "10.0.0",
|
||||
"eventsource-polyfill": "0.9.6",
|
||||
"express": "4.21.2",
|
||||
"express": "5.1.0",
|
||||
"function-bind": "1.1.2",
|
||||
"http-proxy-middleware": "3.0.3",
|
||||
"iso-639-1": "3.1.5",
|
||||
|
|
@ -95,19 +96,19 @@
|
|||
"postcss": "8.5.3",
|
||||
"postcss-html": "^1.5.0",
|
||||
"postcss-scss": "^4.0.6",
|
||||
"sass": "1.86.1",
|
||||
"sass": "1.86.3",
|
||||
"selenium-server": "3.141.59",
|
||||
"semver": "7.7.1",
|
||||
"serve-static": "2.2.0",
|
||||
"shelljs": "0.9.2",
|
||||
"sinon": "20.0.0",
|
||||
"sinon-chai": "4.0.0",
|
||||
"stylelint": "16.17.0",
|
||||
"stylelint": "16.18.0",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-recommended": "^14.0.0",
|
||||
"stylelint-config-recommended": "^16.0.0",
|
||||
"stylelint-config-recommended-scss": "^14.0.0",
|
||||
"stylelint-config-recommended-vue": "^1.6.0",
|
||||
"stylelint-config-standard": "37.0.0",
|
||||
"stylelint-config-standard": "38.0.0",
|
||||
"vite": "^6.1.0",
|
||||
"vite-plugin-eslint2": "^5.0.3",
|
||||
"vite-plugin-stylelint": "^6.0.0",
|
||||
|
|
|
|||
23
src/App.js
23
src/App.js
|
|
@ -20,6 +20,8 @@ import { defineAsyncComponent } from 'vue'
|
|||
import { useShoutStore } from './stores/shout'
|
||||
import { useInterfaceStore } from './stores/interface'
|
||||
|
||||
import { throttle } from 'lodash'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
|
|
@ -58,16 +60,23 @@ export default {
|
|||
// Load the locale from the storage
|
||||
const val = this.$store.getters.mergedConfig.interfaceLanguage
|
||||
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
|
||||
window.addEventListener('resize', this.updateMobileState)
|
||||
document.getElementById('modal').classList = ['-' + this.layoutType]
|
||||
|
||||
// Create bound handlers
|
||||
this.updateScrollState = throttle(this.scrollHandler, 200)
|
||||
this.updateMobileState = throttle(this.resizeHandler, 200)
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('resize', this.updateMobileState)
|
||||
this.scrollParent.addEventListener('scroll', this.updateScrollState)
|
||||
|
||||
if (useInterfaceStore().themeApplied) {
|
||||
this.removeSplash()
|
||||
}
|
||||
},
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.updateMobileState)
|
||||
this.scrollParent.removeEventListener('scroll', this.updateScrollState)
|
||||
},
|
||||
computed: {
|
||||
themeApplied () {
|
||||
|
|
@ -146,13 +155,23 @@ export default {
|
|||
},
|
||||
noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
|
||||
showScrollbars () { return this.$store.getters.mergedConfig.showScrollbars },
|
||||
scrollParent () { return window; /* this.$refs.appContentRef */ },
|
||||
...mapGetters(['mergedConfig'])
|
||||
},
|
||||
methods: {
|
||||
updateMobileState () {
|
||||
resizeHandler () {
|
||||
useInterfaceStore().setLayoutWidth(windowWidth())
|
||||
useInterfaceStore().setLayoutHeight(windowHeight())
|
||||
},
|
||||
scrollHandler () {
|
||||
const scrollPosition = this.scrollParent === window ? window.scrollY : this.scrollParent.scrollTop
|
||||
|
||||
if (scrollPosition != 0) {
|
||||
this.$refs.appContentRef.classList.add(['-scrolled'])
|
||||
} else {
|
||||
this.$refs.appContentRef.classList.remove(['-scrolled'])
|
||||
}
|
||||
},
|
||||
removeSplash () {
|
||||
document.querySelector('#status').textContent = this.$t('splash.fun_' + Math.ceil(Math.random() * 4))
|
||||
const splashscreenRoot = document.querySelector('#splash')
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
<Notifications v-if="currentUser" />
|
||||
<div
|
||||
id="content"
|
||||
ref="appContentRef"
|
||||
class="app-layout container"
|
||||
:class="classes"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -177,7 +177,8 @@
|
|||
.text {
|
||||
flex: 2;
|
||||
margin: 8px;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
|
||||
h1 {
|
||||
font-size: 1rem;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.heading {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ export default {
|
|||
inset: 0;
|
||||
display: grid;
|
||||
place-items: center center;
|
||||
background-color: rgba(100 0 0 / 50%);
|
||||
background-color: rgb(100 0 0 / 50%);
|
||||
|
||||
.alert {
|
||||
padding: 0.5em 1em;
|
||||
|
|
@ -261,14 +261,14 @@ export default {
|
|||
.preview-window {
|
||||
--__grid-color1: rgb(102 102 102);
|
||||
--__grid-color2: rgb(153 153 153);
|
||||
--__grid-color1-disabled: rgba(102 102 102 / 20%);
|
||||
--__grid-color2-disabled: rgba(153 153 153 / 20%);
|
||||
--__grid-color1-disabled: rgb(102 102 102 / 20%);
|
||||
--__grid-color2-disabled: rgb(153 153 153 / 20%);
|
||||
|
||||
&.-light-grid {
|
||||
--__grid-color1: rgb(205 205 205);
|
||||
--__grid-color2: rgb(255 255 255);
|
||||
--__grid-color1-disabled: rgba(205 205 205 / 20%);
|
||||
--__grid-color2-disabled: rgba(255 255 255 / 20%);
|
||||
--__grid-color1-disabled: rgb(205 205 205 / 20%);
|
||||
--__grid-color2-disabled: rgb(255 255 255 / 20%);
|
||||
}
|
||||
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@
|
|||
max-width: 100%;
|
||||
|
||||
p {
|
||||
word-wrap: break-word;
|
||||
white-space: normal;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@
|
|||
flex: 1 1 0;
|
||||
line-height: 1.2;
|
||||
white-space: normal;
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
|
|
|
|||
|
|
@ -2,21 +2,24 @@
|
|||
<div class="image-cropper">
|
||||
<div v-if="dataUrl">
|
||||
<cropper-canvas
|
||||
ref="cropperCanvas"
|
||||
background
|
||||
class="image-cropper-canvas"
|
||||
ref="cropperCanvas"
|
||||
height="25em"
|
||||
>
|
||||
<cropper-image
|
||||
ref="cropperImage"
|
||||
:src="dataUrl"
|
||||
alt="Picture"
|
||||
ref="cropperImage"
|
||||
class="image-cropper-image"
|
||||
translatable
|
||||
scalable
|
||||
/>
|
||||
<cropper-shade hidden />
|
||||
<cropper-handle action="select" plain />
|
||||
<cropper-handle
|
||||
action="select"
|
||||
plain
|
||||
/>
|
||||
<cropper-selection
|
||||
ref="cropperSelection"
|
||||
initial-coverage="1"
|
||||
|
|
@ -25,17 +28,23 @@
|
|||
resizable
|
||||
@change="onCropperSelectionChange"
|
||||
>
|
||||
<cropper-grid role="grid" covered></cropper-grid>
|
||||
<cropper-crosshair centered></cropper-crosshair>
|
||||
<cropper-handle action="move" theme-color="rgba(255, 255, 255, 0.35)"></cropper-handle>
|
||||
<cropper-handle action="n-resize"></cropper-handle>
|
||||
<cropper-handle action="e-resize"></cropper-handle>
|
||||
<cropper-handle action="s-resize"></cropper-handle>
|
||||
<cropper-handle action="w-resize"></cropper-handle>
|
||||
<cropper-handle action="ne-resize"></cropper-handle>
|
||||
<cropper-handle action="nw-resize"></cropper-handle>
|
||||
<cropper-handle action="se-resize"></cropper-handle>
|
||||
<cropper-handle action="sw-resize"></cropper-handle>
|
||||
<cropper-grid
|
||||
role="grid"
|
||||
covered
|
||||
/>
|
||||
<cropper-crosshair centered />
|
||||
<cropper-handle
|
||||
action="move"
|
||||
theme-color="rgba(255, 255, 255, 0.35)"
|
||||
/>
|
||||
<cropper-handle action="n-resize" />
|
||||
<cropper-handle action="e-resize" />
|
||||
<cropper-handle action="s-resize" />
|
||||
<cropper-handle action="w-resize" />
|
||||
<cropper-handle action="ne-resize" />
|
||||
<cropper-handle action="nw-resize" />
|
||||
<cropper-handle action="se-resize" />
|
||||
<cropper-handle action="sw-resize" />
|
||||
</cropper-selection>
|
||||
</cropper-canvas>
|
||||
<div class="image-cropper-buttons-wrapper">
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@
|
|||
margin: 0.5em 0 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
line-height: 1.2em;
|
||||
|
||||
/* cap description at 3 lines, the 1px is to clean up some stray pixels
|
||||
|
|
|
|||
|
|
@ -93,4 +93,4 @@
|
|||
|
||||
<script src="./login_form.js"></script>
|
||||
|
||||
<style src="./login_form.scss"/>
|
||||
<style src="./login_form.scss" />
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ $modal-view-button-icon-margin: 0.5em;
|
|||
min-height: 1em;
|
||||
max-width: 500px;
|
||||
max-height: 9.5em;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
.modal-image {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
top: 100%;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
word-wrap: normal;
|
||||
white-space: nowrap;
|
||||
transition: opacity 0.2s ease;
|
||||
z-index: 1;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
.MentionsLine {
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
|
||||
.mention-link:not(:first-child)::before {
|
||||
content: " ";
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
.Notification {
|
||||
border-bottom: 1px solid;
|
||||
border-color: var(--border);
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
|
||||
&.Status {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
|
|
@ -31,8 +31,6 @@
|
|||
& .status-username,
|
||||
& .mute-thread,
|
||||
& .mute-words {
|
||||
word-wrap: normal;
|
||||
word-break: normal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,6 @@
|
|||
|
||||
.notification-details {
|
||||
min-width: 0;
|
||||
word-wrap: break-word;
|
||||
line-height: var(--post-line-height);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
|
@ -161,7 +160,8 @@
|
|||
}
|
||||
|
||||
h1 {
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
margin: 0 0 0.3em;
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
align-items: center;
|
||||
padding: 0.1em 0.25em;
|
||||
z-index: 1;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
.result-percentage {
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@
|
|||
min-height: calc(var(--post-line-height) * 1em);
|
||||
resize: none;
|
||||
background: transparent;
|
||||
text-wrap: stable;
|
||||
|
||||
&.scrollable-form {
|
||||
overflow-y: auto;
|
||||
|
|
|
|||
18
src/components/scroll_top_button/scroll_top_button.js
Normal file
18
src/components/scroll_top_button/scroll_top_button.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
const ScrollTopButton = {
|
||||
props: {
|
||||
fast: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scrollToTop() {
|
||||
const speed = this.fast ? 'instant' : 'smooth';
|
||||
|
||||
window.scrollTo({ top: 0, behavior: speed })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ScrollTopButton
|
||||
29
src/components/scroll_top_button/scroll_top_button.vue
Normal file
29
src/components/scroll_top_button/scroll_top_button.vue
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div class="rightside-button scroll-to-top">
|
||||
<button
|
||||
class="button-unstyled scroll-to-top-button"
|
||||
type="button"
|
||||
:title="$t('general.scroll_to_top')"
|
||||
@click="scrollToTop"
|
||||
>
|
||||
<FALayers class="fa-scale-110 fa-old-padding-layer">
|
||||
<FAIcon icon="arrow-up" />
|
||||
<FAIcon
|
||||
icon="minus"
|
||||
transform="up-7"
|
||||
/>
|
||||
</FALayers>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./scroll_top_button.js"></script>
|
||||
<style lang="scss">
|
||||
.scroll-to-top {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.-scrolled .scroll-to-top {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
.Status {
|
||||
min-width: 0;
|
||||
white-space: normal;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
|
||||
&:hover {
|
||||
--_still-image-img-visibility: visible;
|
||||
|
|
@ -92,7 +92,10 @@
|
|||
|
||||
a {
|
||||
display: inline-block;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -283,8 +286,6 @@
|
|||
|
||||
& .status-username,
|
||||
& .mute-reason {
|
||||
word-wrap: normal;
|
||||
word-break: normal;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@
|
|||
& .summary {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
text-wrap: pretty;
|
||||
line-height: var(--post-line-height);
|
||||
}
|
||||
|
||||
|
|
@ -54,19 +53,22 @@
|
|||
}
|
||||
|
||||
.text-wrapper {
|
||||
text-overflow: ellipsis;
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
||||
&.-tall-status {
|
||||
position: relative;
|
||||
height: 220px;
|
||||
height: 16em;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
|
||||
.media-body {
|
||||
min-height: 0;
|
||||
mask:
|
||||
linear-gradient(to top, white, transparent) bottom/100% 70px no-repeat,
|
||||
linear-gradient(to top, white, transparent) bottom/100% 8em no-repeat,
|
||||
linear-gradient(to top, white, white);
|
||||
|
||||
/* Autoprefixed seem to ignore this one, and also syntax is different */
|
||||
|
|
@ -87,16 +89,17 @@
|
|||
& .status-unhider,
|
||||
& .cw-status-hider {
|
||||
display: inline-block;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tall-status-hider {
|
||||
position: absolute;
|
||||
height: 70px;
|
||||
margin-top: 150px;
|
||||
line-height: 110px;
|
||||
height: 5em;
|
||||
margin-top: 10em;
|
||||
line-height: 8em;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +110,8 @@
|
|||
|
||||
& .status-unhider,
|
||||
& .cw-status-hider {
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: pretty;
|
||||
|
||||
svg {
|
||||
color: inherit;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import Conversation from '../conversation/conversation.vue'
|
|||
import TimelineMenu from '../timeline_menu/timeline_menu.vue'
|
||||
import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue'
|
||||
import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue'
|
||||
import ScrollTopButton from '../scroll_top_button/scroll_top_button.vue'
|
||||
import { debounce, throttle, keyBy } from 'lodash'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faCircleNotch, faCirclePlus, faCog, faMinus, faArrowUp, faCheck } from '@fortawesome/free-solid-svg-icons'
|
||||
|
|
@ -47,6 +48,7 @@ const Timeline = {
|
|||
},
|
||||
components: {
|
||||
Status,
|
||||
ScrollTopButton,
|
||||
Conversation,
|
||||
TimelineMenu,
|
||||
QuickFilterSettings,
|
||||
|
|
@ -144,9 +146,6 @@ const Timeline = {
|
|||
this.$store.commit('setLoading', { timeline: this.timelineName, value: false })
|
||||
},
|
||||
methods: {
|
||||
scrollToTop () {
|
||||
window.scrollTo({ top: this.$el.offsetTop })
|
||||
},
|
||||
stopBlockingClicks: debounce(function () {
|
||||
this.blockingClicks = false
|
||||
}, 1000),
|
||||
|
|
@ -251,7 +250,6 @@ const Timeline = {
|
|||
}
|
||||
},
|
||||
handleScroll: throttle(function (e) {
|
||||
this.showScrollTop = this.$el.offsetTop < window.scrollY
|
||||
this.determineVisibleStatuses()
|
||||
this.scrollLoad(e)
|
||||
}, 200),
|
||||
|
|
|
|||
|
|
@ -8,25 +8,7 @@
|
|||
v-if="!embedded"
|
||||
:timeline-name="timelineName"
|
||||
/>
|
||||
<div
|
||||
v-if="showScrollTop"
|
||||
class="rightside-button"
|
||||
>
|
||||
<button
|
||||
class="button-unstyled scroll-to-top-button"
|
||||
type="button"
|
||||
:title="$t('general.scroll_to_top')"
|
||||
@click="scrollToTop"
|
||||
>
|
||||
<FALayers class="fa-scale-110 fa-old-padding-layer">
|
||||
<FAIcon icon="arrow-up" />
|
||||
<FAIcon
|
||||
icon="minus"
|
||||
transform="up-7"
|
||||
/>
|
||||
</FALayers>
|
||||
</button>
|
||||
</div>
|
||||
<ScrollTopButton />
|
||||
<template v-if="mobileLayout">
|
||||
<div
|
||||
v-if="showLoadButton"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue