diff --git a/src/App.scss b/src/App.scss index 0de5a3577..be3f0df22 100644 --- a/src/App.scss +++ b/src/App.scss @@ -145,8 +145,8 @@ h4 { } code { - background: var(--background); - border: 1px solid var(--border); + background: var(--bg); + border: 1px solid var(--fg); border-radius: var(--roundness); padding: 0 0.2em; diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 00605657e..1bc9f3858 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -97,7 +97,7 @@ const conversation = { }, data() { return { - focused: null, + highlight: null, expanded: false, threadDisplayStatusObject: {}, // id => 'showing' | 'hidden' inlineDivePosition: null, @@ -389,9 +389,6 @@ const conversation = { canDive() { return this.isTreeView && this.isExpanded }, - maybeFocused() { - return this.isExpanded ? this.focused : null - }, ...mapPiniaState(useMergedConfigStore, ['mergedConfig']), ...mapState({ mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus, @@ -414,7 +411,7 @@ const conversation = { oldConversationId && newConversationId === oldConversationId ) { - this.setFocused(this.originalStatusId) + this.setHighlight(this.originalStatusId) } else { this.fetchConversation() } @@ -442,7 +439,7 @@ const conversation = { }).then(({ data: { ancestors, descendants } }) => { this.$store.dispatch('addNewStatuses', { statuses: ancestors }) this.$store.dispatch('addNewStatuses', { statuses: descendants }) - this.setFocused(this.originalStatusId) + this.setHighlight(this.originalStatusId) }) } else { this.loadStatusError = null @@ -460,12 +457,18 @@ const conversation = { }) } }, + isFocused(id) { + return this.isExpanded && id === this.highlight + }, getReplies(id) { return this.replies[id] || [] }, - setFocused(id) { + maybeHighlight() { + return this.isExpanded ? this.highlight : null + }, + setHighlight(id) { if (!id) return - this.focused = id + this.highlight = id if (!this.streamingEnabled) { this.$store.dispatch('fetchStatus', id) @@ -530,7 +533,7 @@ const conversation = { // only used when we are not on a page undive() { this.inlineDivePosition = null - this.setFocused(this.statusId) + this.setHighlight(this.statusId) }, tryScrollTo(id) { if (!id) { @@ -548,7 +551,7 @@ const conversation = { // contain scrolling calls, as we do not want the page to jump // when we scroll with an expanded conversation. // - // Now the method is to rely solely on the `focused` watcher + // Now the method is to rely solely on the `highlight` watcher // in `status` components. // In linear views, all statuses are rendered at all times, but // in tree views, it is possible that a change in active status @@ -556,9 +559,9 @@ const conversation = { // status becomes an ancestor status, and thus they will be // different). // Here, let the components be rendered first, in order to trigger - // the `focused` watcher. + // the `highlight` watcher. this.$nextTick(() => { - this.setFocused(id) + this.setHighlight(id) }) }, goToCurrent() { diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 684a5de92..9bd8a96f9 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -96,7 +96,8 @@ :replies="getReplies(status.id)" :expandable="!isExpanded" - :focused="maybeFocused === status.id" + :focused="isFocused(status.id)" + :highlight="maybeHighlight" :inline-expanded="collapsable && isExpanded" :show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]" :in-profile="inProfile" @@ -106,7 +107,7 @@ :show-other-replies-as-button="showOtherRepliesButtonInsideStatus" can-dive - @goto="setFocused" + @goto="setHighlight" @dive="() => diveIntoStatus(status.id)" @suspendable-state-change="onStatusSuspendStateChange" /> @@ -153,8 +154,9 @@ :pinned-status-ids-object="pinnedStatusIdsObject" :profile-user-id="profileUserId" + :is-focused-function="isFocused" :get-replies="getReplies" - :focused="maybeFocused" + :highlight="maybeHighlight" :toggle-expanded="toggleExpanded" :simple="treeViewIsSimple" @@ -164,7 +166,7 @@ :total-reply-depth="totalReplyDepth" :can-dive="canDive" - @goto="setFocused" + @goto="setHighlight" @dive="diveIntoStatus" @suspendable-state-change="onStatusSuspendStateChange" /> @@ -183,14 +185,15 @@ :replies="getReplies(status.id)" :expandable="!isExpanded" - :focused="maybeFocused === status.id || maybeFocused === status.retweeted_status?.id" + :focused="isFocused(status.id)" + :highlight="maybeHighlight === status.id" :inline-expanded="collapsable && isExpanded" :show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]" :in-profile="inProfile" :in-conversation="isExpanded" :profile-user-id="profileUserId" - @goto="setFocused" + @goto="setHighlight" @toggle-expanded="toggleExpanded" @suspendable-state-change="onStatusSuspendStateChange" /> diff --git a/src/components/error_modal/error_modal.vue b/src/components/error_modal/error_modal.vue index ef2654b2e..7429e8bdc 100644 --- a/src/components/error_modal/error_modal.vue +++ b/src/components/error_modal/error_modal.vue @@ -25,10 +25,7 @@
{{ $t('general.generic_error_details') }} - +
diff --git a/src/components/global_error/global_error.vue b/src/components/global_error/global_error.vue index 2b6e83655..3c3901d4f 100644 --- a/src/components/global_error/global_error.vue +++ b/src/components/global_error/global_error.vue @@ -13,10 +13,7 @@
{{ $t('general.generic_error_details') }} - +
diff --git a/src/components/palette_editor/palette_editor.vue b/src/components/palette_editor/palette_editor.vue index b27b21f00..5b89f2af2 100644 --- a/src/components/palette_editor/palette_editor.vue +++ b/src/components/palette_editor/palette_editor.vue @@ -4,11 +4,9 @@ :class="{ '-compact': compact, '-apply': apply, '-mobile': mobile }" >
-
+
-
{{ ' ' }}
@@ -137,15 +134,11 @@ const mobile = computed(() => { }) const contrast = computed(() => { - if (props.modelValue == null) return null const bg = hex2rgb(props.modelValue.bg) - const text = hex2rgb(props.modelValue.text) - const link = hex2rgb(props.modelValue.link) - if (text == null || link == null) return null return { - text: hints(getContrastRatio(bg, text)), - link: hints(getContrastRatio(bg, link)), + text: hints(getContrastRatio(bg, hex2rgb(props.modelValue.text))), + link: hints(getContrastRatio(bg, hex2rgb(props.modelValue.link))), } }) @@ -239,6 +232,15 @@ const updatePalette = (paletteKey, value) => { grid-column: 1 / span 2; } } + + .color-input { + display: grid; + gap: 0.5em; + + label { + flex: 1; + } + } } } diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index cdaebe2ff..fc17a529f 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -313,134 +313,7 @@ export default { const newChildren = Array.isArray(children) ? [...children].reverse().map(processItemReverse).reverse() : children - const attrs = getAttrs(opener) - const newAttrs = { ...attrs } - const fullAttrs = getAttrs(opener, () => true) - const classname = fullAttrs['class'] - const isMFM = classname?.startsWith('mfm-') - if (isMFM) { - const mfmOperator = /^mfm-(\w+)$/.exec(classname)?.[1] - newAttrs['class'] = 'mfm' - newAttrs['data-mfm-operator'] = mfmOperator - switch(mfmOperator) { - case 'position': { - const x = fullAttrs['data-mfm-x'].replace(/\.+$/,'') || 0 - const y = fullAttrs['data-mfm-y'].replace(/\.+$/,'') || 0 - newAttrs.style = [ - 'transform:', - `translate(calc(${x} * (var(--emoji-size) / 2)), `, - `calc(${y} * (var(--emoji-size) / 2)))`, - ].join(' ') - break - } - case 'scale': { - const x = fullAttrs['data-mfm-x'].replace(/\.+$/,'') || 1 - const y = fullAttrs['data-mfm-y'].replace(/\.+$/,'') || 1 - newAttrs.style = [ - 'transform:', - `scale(${x}, ${y})`, - ].join(' ') - break - } - case 'rotate': { - const deg = fullAttrs['data-mfm-deg'] || 0 - newAttrs.style = [ - `transform: rotate(${deg}deg)`, - 'transform-origin: center', - ].join(';') - break - } - case 'bg': { - const color = fullAttrs['data-mfm-color'] || 0 - newAttrs.style = [ - `background-color: #${color}`, - ].join(' ') - break - } - case 'fg': { - const color = fullAttrs['data-mfm-color'] || 0 - newAttrs.style = [ - `color: #${color}`, - ].join(';') - break - } - case 'spin': { - const speed = fullAttrs['data-mfm-speed'] || '1s' - const delay = fullAttrs['data-mfm-delay'] || 0 - const left = fullAttrs['data-mfm-left'] != null - const alternate = fullAttrs['data-mfm-alternate'] != null - const y = fullAttrs['data-mfm-y'] != null - const x = fullAttrs['data-mfm-x'] != null - - const anim = [ - x ? 'mfm-spinX' : null, - y ? 'mfm-spinY' : null, - 'mfm-spin' - ].filter(a => a)[0] - - const direction = [ - alternate ? 'alternate' : null, - left ? 'reverse' : null, - 'normal', - ].filter(a => a)[0] - - newAttrs.style = [ - `animation-name: ${anim}`, - `animation-duration: ${speed}`, - 'animation-iteration-count: infinite', - `animation-delay: ${delay}`, - `animation-direction: ${direction}`, - 'animation-fill-mode: none', - 'animation-timing-function: linear', - ].join(';') - break - } - case 'flip': { - newAttrs.style = 'transform: scaleX(-1)' - break - } - case 'border': { - const width = fullAttrs['data-mfm-width'] || '0' - const style = fullAttrs['data-mfm-style'] || 'solid' - const color = fullAttrs['data-mfm-color'] || 'transparent' - const radius = fullAttrs['data-mfm-radius'] || '0' - const noclip = fullAttrs['data-mfm-noclip'] || false - - newAttrs.style = [ - `border: ${width} ${style} ${color}`, - `border-radius: ${radius}`, - `overflow: ${noclip ? 'visible' : 'clip'}` - ].join(';') - break - } - case 'tada': - case 'jelly': - case 'twitch': - case 'shake': - case 'jump': - case 'bounce': { - const speed = fullAttrs['data-mfm-speed'] || '1s' - const delay = fullAttrs['data-mfm-delay'] || 0 - - const rules = [ - `animation-name: mfm-${mfmOperator}`, - `animation-duration: ${speed}`, - 'animation-iteration-count: infinite', - `animation-delay: ${delay}`, - 'animation-direction: normal', - 'animation-fill-mode: none', - 'animation-timing-function: linear', - ].join(';') - newAttrs.style = rules - break - } - default: - console.log(mfmOperator, opener) - console.log(mfmOperator) - break - } - } - return {newChildren} + return {newChildren} } else { return } diff --git a/src/components/rich_content/rich_content.scss b/src/components/rich_content/rich_content.scss index f048e529e..33effc623 100644 --- a/src/components/rich_content/rich_content.scss +++ b/src/components/rich_content/rich_content.scss @@ -1,17 +1,6 @@ .RichContent { font-family: var(--font); - .mfm { - display: inline-block; - font-size: calc(var(--emoji-size) / 2); - - .emoji { - /* Misskey's emoji width knows no bounds */ - /* stylelint-disable-next-line declaration-no-important */ - max-width: unset !important; - } - } - &.-faint { color: var(--text); /* stylelint-disable declaration-no-important */ @@ -117,289 +106,3 @@ a .RichContent { /* stylelint-disable-next-line declaration-no-important */ color: var(--link) !important; } - -@keyframes mfm-spin { - 0% { - transform: rotate(0deg); - } - - 100% { - transform: rotate(360deg); - } -} - -@keyframes mfm-spinX { - 0% { - transform: perspective(8em) rotateX(0); - } - - 100% { - transform: perspective(8em) rotateX(360deg); - } -} - -@keyframes mfm-spinY { - 0% { - transform: perspective(8em) rotateY(0); - } - - 100% { - transform: perspective(8em) rotateY(360deg); - } -} - -@keyframes mfm-jump { - 0% { - transform: translateY(0) - } - - 25% { - transform: translateY(-1em) - } - - 50% { - transform: translateY(0) - } - - 75% { - transform: translateY(-0.5em) - } - - 100% { - transform: translateY(0) - } -} - -@keyframes mfm-bounce { - 0% { - transform: translateY(0) scale(1) - } - - 25% { - transform: translateY(-16px) scale(1) - } - - 50% { - transform: translateY(0) scale(1) - } - - 75% { - transform: translateY(0) scale(1.5,.75) - } - - 100% { - transform: translateY(0) scale(1) - } -} - -@keyframes mfm-twitch { - 0% { - transform: translate(7px,-2px) - } - - 5% { - transform: translate(-3px,1px) - } - - 10% { - transform: translate(-7px,-1px) - } - - 15% { - transform: translateY(-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) - } - - 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: translateY(-1px) rotate(-10deg) - } - - 10% { - transform: translate(1px,-3px) rotate(0) - } - - 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: translateY(-1px)rotate(-12deg) - } - - 50% { - transform: translate(1px,2px)rotate(10deg) - } - - 55% { - transform: translateY(-3px)rotate(8deg) - } - - 60% { - transform: translate(1px,-1px)rotate(8deg) - } - - 65% { - transform: translateY(-1px)rotate(-7deg) - } - - 70% { - transform: translate(-1px,-3px)rotate(6deg) - } - - 75% { - transform: translateY(-2px)rotate(4deg) - } - - 80% { - transform: translate(-2px,-1px)rotate(3deg) - } - - 85% { - transform: translate(1px,-3px)rotate(-10deg) - } - - 90% { - transform: translate(1px)rotate(3deg) - } - - 95% { - transform: translate(-2px)rotate(-3deg) - } - - 100% { - transform: translate(2px,1px)rotate(2deg) - } -} - -@keyframes mfm-rubberBand { - 0% { - transform: scale(1) - } - - 30% { - transform: scale(1.25,.75) - } - - 40% { - transform: scale(.75,1.25) - } - - 50% { - transform: scale(1.15,.85) - } - - 65% { - transform: scale(.95,1.05) - } - - 75% { - transform: scale(1.05,.95) - } - - 100% { - transform: scale(1) - } -} - -@keyframes mfm-rainbow { - 0% { - filter: hue-rotate()contrast(150%)saturate(150%) - } - - 100% { - filter: hue-rotate(360deg)contrast(150%)saturate(150%) - } -} diff --git a/src/components/status/status.js b/src/components/status/status.js index 996dc6437..0cfc7cdba 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -97,6 +97,7 @@ const Status = { expandable: Boolean, focused: Boolean, + highlight: Boolean, compact: Boolean, isPreview: Boolean, noHeading: Boolean, @@ -319,7 +320,7 @@ const Status = { }, shouldNotMute() { if (this.ignoreMute) return true - if (this.focused) return true + if (this.isFocused) return true const { status } = this const { reblog } = status return ( @@ -356,6 +357,16 @@ const Status = { this.muteFilterHits.some((x) => x.hide)) ) }, + isFocused() { + // retweet or root of an expanded conversation + if (this.focused) { + return true + } else if (!this.inConversation) { + return false + } + // use conversation highlight only when in conversation + return this.status.id === this.highlight + }, isReply() { return !!( this.status.in_reply_to_status_id && this.status.in_reply_to_user_id @@ -404,7 +415,7 @@ const Status = { shouldDisplayFavsAndRepeats() { return ( !this.hidePostStats && - this.focused && + this.isFocused && (this.combinedFavsAndRepeatsUsers.length > 0 || this.statusFromGlobalRepository.quotes_count) ) @@ -547,9 +558,9 @@ const Status = { toggleThreadDisplay() { this.controlledToggleThreadDisplay() }, - scrollIfFocused(focusedId) { + scrollIfHighlighted(highlightId) { if (this.$el.getBoundingClientRect == null) return - const id = focusedId + const id = highlightId if (this.status.id === id) { const rect = this.$el.getBoundingClientRect() if (rect.top < 100) { @@ -566,13 +577,13 @@ const Status = { }, }, watch: { - focused: function (id) { - this.scrollIfFocused(id) + highlight: function (id) { + this.scrollIfHighlighted(id) }, 'status.repeat_num': function (num) { // refetch repeats when repeat_num is changed in any way if ( - this.focused && + this.isFocused && this.statusFromGlobalRepository.rebloggedBy && this.statusFromGlobalRepository.rebloggedBy.length !== num ) { @@ -582,7 +593,7 @@ const Status = { 'status.fave_num': function (num) { // refetch favs when fave_num is changed in any way if ( - this.focused && + this.isFocused && this.statusFromGlobalRepository.favoritedBy && this.statusFromGlobalRepository.favoritedBy.length !== num ) { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 4dcc1e07d..f301ad890 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -3,7 +3,7 @@ v-if="!hideStatus" ref="root" class="Status" - :class="[{ '-focused': focused }, { '-conversation': inlineExpanded }]" + :class="[{ '-focused': isFocused }, { '-conversation': inlineExpanded }]" >
diff --git a/src/components/thread_tree/thread_tree.js b/src/components/thread_tree/thread_tree.js index 75232a259..7631d127f 100644 --- a/src/components/thread_tree/thread_tree.js +++ b/src/components/thread_tree/thread_tree.js @@ -19,8 +19,10 @@ const ThreadTree = { pinnedStatusIdsObject: Object, profileUserId: String, - focused: String, + isFocusedFunction: Function, + highlight: String, getReplies: Function, + setHighlight: Function, toggleExpanded: Function, simple: Boolean, diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index 556858ad7..72f8512e5 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -8,8 +8,9 @@ :inline-expanded="collapsable && isExpanded" :expandable="!isExpanded" :show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]" + :focused="isFocusedFunction(status.id)" :in-conversation="isExpanded" - :focused="focused === status.id || focused === status.retweeted_status?.id" + :highlight="highlight === status.id" :in-profile="inProfile" :profile-user-id="profileUserId" class="conversation-status conversation-status-treeview status-fadein panel-body" @@ -41,8 +42,10 @@ :pinned-status-ids-object="pinnedStatusIdsObject" :profile-user-id="profileUserId" + :is-focused-function="isFocusedFunction" :get-replies="getReplies" - :focused="focused" + :highlight="highlight" + :set-highlight="setHighlight" :toggle-expanded="toggleExpanded" :simple="simple"