@@ -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"