Page MenuHomePhorge

No OneTemporary

Size
27 KB
Referenced Files
None
Subscribers
None
diff --git a/src/components/notification/notification.scss b/src/components/notification/notification.scss
index 3e2fa54a52..8ba66a0e14 100644
--- a/src/components/notification/notification.scss
+++ b/src/components/notification/notification.scss
@@ -1,93 +1,230 @@
// TODO Copypaste from Status, should unify it somehow
.Notification {
+ box-sizing: border-box;
border-bottom: 1px solid;
border-color: var(--border);
overflow-wrap: break-word;
text-wrap: pretty;
.status-content {
cursor: pointer;
}
--emoji-size: 1em;
&:hover {
--_still-image-img-visibility: visible;
--_still-image-canvas-visibility: hidden;
--_still-image-label-visibility: hidden;
}
&.-muted {
padding: 0.25em 0.6em;
height: 1.2em;
line-height: 1.2em;
text-overflow: ellipsis;
overflow: hidden;
display: flex;
flex-wrap: nowrap;
gap: 1ex;
& .status-username,
& .mute-thread,
& .mute-words {
white-space: nowrap;
}
& .status-username,
& .mute-words {
text-overflow: ellipsis;
overflow: hidden;
}
.status-username {
font-weight: normal;
flex: 0 1 auto;
margin-right: 0.2em;
font-size: smaller;
}
.mute-thread {
flex: 0 0 auto;
}
.mute-words {
flex: 1 0 5em;
margin-left: 0.2em;
&::before {
content: " ";
}
}
.unmute {
flex: 0 0 auto;
margin-left: auto;
display: block;
}
}
.type-icon {
margin: 0 0.1em;
}
&.-type--repeat .type-icon {
color: var(--cGreen);
}
&.-type--follow .type-icon {
color: var(--cBlue);
}
&.-type--follow-request .type-icon {
color: var(--cBlue);
}
&.-type--like .type-icon {
color: var(--cOrange);
}
&.-type--move .type-icon {
color: var(--cBlue);
}
+
+ .Status {
+ flex: 1;
+ }
+
+ &:hover .animated.Avatar {
+ canvas {
+ display: none;
+ }
+
+ img {
+ visibility: visible;
+ }
+ }
+
+ &.-non-mention {
+ display: flex;
+ flex: 1;
+ flex-wrap: nowrap;
+ padding: 0.6em;
+ min-width: 0;
+ }
+
+ .follow-request-accept {
+ &:hover {
+ color: var(--text);
+ }
+ }
+
+ .follow-request-reject {
+ &:hover {
+ color: var(--cRed);
+ }
+ }
+
+ .follow-text,
+ .move-text {
+ padding: 0.5em 0;
+ overflow-wrap: break-word;
+ display: flex;
+ justify-content: space-between;
+
+ .follow-name {
+ display: block;
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+
+ time {
+ white-space: nowrap;
+ }
+
+ .notification-right {
+ flex: 1;
+ padding-left: 0.8em;
+ min-width: 0;
+ margin-right: calc(var(--status-margin) / -2);
+
+ .button-unstyled {
+ margin: calc(var(--status-margin) / -2) 0;
+ padding: calc(var(--status-margin) / 2);
+ }
+ }
+
+ .emoji-reaction-emoji {
+ font-size: 1.3em;
+ max-width: 1.25em;
+ height: 1.25em;
+ width: auto;
+
+ &.-wide {
+ max-width: 3.75em;
+ }
+ }
+
+ .emoji-reaction-emoji-image {
+ vertical-align: middle;
+ object-fit: contain;
+ }
+
+ .notification-details {
+ min-width: 0;
+ line-height: var(--post-line-height);
+ position: relative;
+ overflow: hidden;
+ width: 100%;
+ flex: 1 1 0;
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+
+ .name-and-action {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ line-height: 1.3;
+ }
+
+ .username {
+ font-weight: bolder;
+ max-width: 100%;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .timeago {
+ margin-right: 0.2em;
+ }
+
+ .status-content {
+ margin: 0;
+ max-height: 300px;
+ }
+
+ h1 {
+ overflow-wrap: break-word;
+ text-wrap: pretty;
+ margin: 0 0 0.3em;
+ padding: 0;
+ font-size: 1em;
+ line-height: 1.5;
+
+ small {
+ font-weight: lighter;
+ }
+ }
+
+ p {
+ margin: 0;
+ margin-top: 0;
+ margin-bottom: 0.3em;
+ }
+ }
}
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 95fcfca41b..29d83e86cf 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -1,276 +1,276 @@
<template>
<article
v-if="notification.type === 'mention' || notification.type === 'status'"
ref="root"
>
<Status
class="Notification panel-body"
:compact="true"
:status-id="notification.status?.id"
@click="interacted"
/>
</article>
<article
v-else
ref="root"
class="NotificationParent panel-body"
:class="{ '-expandable': expandable }"
>
<div
v-if="needMute && !unmuted"
:id="'notif-' +notification.id"
:aria-expanded="statusExpanded"
:aria-controls="'notif-' +notification.id"
class="Notification container -muted"
>
<small>
<UserLink
:user="notification.from_profile"
:at="false"
/>
</small>
<button
class="button-unstyled unmute"
@click.prevent="toggleMute"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="eye-slash"
/>
</button>
</div>
<div
v-else
- class="Notification non-mention"
+ class="Notification -non-mention"
:class="[userClass, { highlighted: userStyle }, '-type--' + notification.type]"
:style="[ userStyle ]"
>
<a
class="avatar-container"
:href="$router.resolve(userProfileLink).href"
@click.prevent
>
<UserPopover
:user-id="notification.from_profile.id"
:overlay-centers="true"
>
<UserAvatar
class="post-avatar"
:compact="true"
:user-id="notification.from_profile.id"
/>
</UserPopover>
</a>
<div class="notification-right">
<span class="notification-details">
<div class="name-and-action">
<!-- eslint-disable vue/no-v-html -->
<bdi v-if="!!notification.from_profile.name_html">
<RichContent
class="username"
:title="'@'+notification.from_profile.screen_name_ui"
:html="notification.from_profile.name_html"
:emoji="notification.from_profile.emoji"
:allow-non-square-emoji="allowNonSquareEmoji"
:pause-mfm="pauseMfm"
:scale-mfm="scaleMfm"
:is-local="notification.from_profile.is_local"
/>
</bdi>
<!-- eslint-enable vue/no-v-html -->
<span
v-else
class="username"
:title="'@'+notification.from_profile.screen_name_ui"
>
{{ notification.from_profile.name }}
</span>
{{ ' ' }}
<span v-if="notification.type === 'like'">
<FAIcon
class="type-icon"
icon="star"
/>
{{ ' ' }}
<small>{{ $t('notifications.favorited_you') }}</small>
</span>
<span v-if="notification.type === 'repeat'">
<FAIcon
class="type-icon"
icon="retweet"
:title="$t('tool_tip.repeat')"
/>
{{ ' ' }}
<small>{{ $t('notifications.repeated_you') }}</small>
</span>
<span v-if="notification.type === 'follow'">
<FAIcon
class="type-icon"
icon="user-plus"
/>
{{ ' ' }}
<small>{{ $t('notifications.followed_you') }}</small>
</span>
<span v-if="notification.type === 'follow_request'">
<FAIcon
class="type-icon"
icon="user"
/>
{{ ' ' }}
<small>{{ $t('notifications.follow_request') }}</small>
</span>
<span v-if="notification.type === 'move'">
<FAIcon
class="type-icon"
icon="suitcase-rolling"
/>
{{ ' ' }}
<small>{{ $t('notifications.migrated_to') }}</small>
</span>
<span v-if="notification.type === 'pleroma:emoji_reaction'">
<small>
<i18n-t
scope="global"
keypath="notifications.reacted_with"
>
<img
v-if="notification.emoji_url"
class="emoji-reaction-emoji emoji-reaction-emoji-image"
:src="notification.emoji_url"
:alt="notification.emoji"
:title="notification.emoji"
:class="{ ['-wide']: allowNonSquareEmoji }"
>
<span
v-else
class="emoji-reaction-emoji"
>{{ notification.emoji }}</span>
</i18n-t>
</small>
</span>
<span v-if="notification.type === 'pleroma:report'">
<small>{{ $t('notifications.submitted_report') }}</small>
</span>
<span v-if="notification.type === 'poll'">
<FAIcon
class="type-icon"
icon="poll-h"
/>
{{ ' ' }}
<small>{{ $t('notifications.poll_ended') }}</small>
</span>
</div>
<div
v-if="isStatusNotification"
class="timeago"
>
<router-link
v-if="notification.status"
:to="{ name: 'conversation', params: { statusId: notification.status.id } }"
class="timeago-link faint"
:aria-label="$t('status.open_in_thread_view')"
>
<Timeago
:time="notification.created_at"
:auto-update="240"
/>
</router-link>
<button
class="button-unstyled expand-icon"
:title="$t('tool_tip.toggle_expand')"
:aria-expanded="statusExpanded"
@click.prevent="toggleStatusExpanded"
>
<FAIcon
class="fa-scale-110"
fixed-width
:icon="statusExpanded ? 'compress-alt' : 'expand-alt'"
/>
</button>
</div>
<div
v-else
class="timeago"
>
<span class="faint">
<Timeago
:time="notification.created_at"
:auto-update="240"
/>
</span>
</div>
<button
v-if="needMute"
class="button-unstyled"
:title="$t('tool_tip.toggle_mute')"
:aria-expanded="!unmuted"
@click.prevent="toggleMute"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="eye-slash"
/>
</button>
</span>
<div
v-if="notification.type === 'follow' || notification.type === 'follow_request'"
class="follow-text"
>
<UserLink
class="follow-name"
:user="notification.from_profile"
/>
<div
v-if="notification.type === 'follow_request'"
style="white-space: nowrap;"
>
<button
class="button-unstyled"
:title="$t('tool_tip.accept_follow_request')"
@click="() => approve(user.id)"
>
<FAIcon
icon="check"
class="fa-scale-110 fa-old-padding follow-request-accept"
/>
</button>
<button
class="button-unstyled"
:title="$t('tool_tip.reject_follow_request')"
@click="() => deny(user.id)"
>
<FAIcon
icon="times"
class="fa-scale-110 fa-old-padding follow-request-reject"
/>
</button>
</div>
</div>
<div
v-else-if="notification.type === 'move'"
class="move-text"
>
<UserLink
:user="notification.target"
/>
</div>
<Report
v-else-if="notification.type === 'pleroma:report'"
:report-id="notification.report.id"
/>
<template v-else>
<StatusContent
class="status-content"
:compact="!statusExpanded"
:status="status"
:collapse="!statusExpanded"
@click="onContentClick"
/>
</template>
</div>
</div>
</article>
</template>
<script src="./notification.js"></script>
<style src="./notification.scss" lang="scss"></style>
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index 32839ebbf4..cd9650cc87 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -1,185 +1,30 @@
.Notifications {
&:not(.minimal) {
// a bit of a hack to allow scrolling below notifications
padding-bottom: 15em;
}
.loadmore-error {
color: var(--text);
}
.notification {
position: relative;
.notification-overlay {
position: absolute;
inset: 0;
pointer-events: none;
}
&.unseen {
.notification-overlay {
background-image: linear-gradient(135deg, var(--badgeNotification) 4px, transparent 10px);
}
}
- }
-}
-
-/* stylelint-disable-next-line no-descending-specificity */
-.notification {
- box-sizing: border-box;
-
- /* TODO cleanup this */
- .Status {
- flex: 1;
- }
-
- &:hover .animated.Avatar {
- canvas {
- display: none;
- }
-
- img {
- visibility: visible;
- }
- }
-
- &:last-child .Notification {
- border-bottom: none;
- }
-
- .non-mention {
- display: flex;
- flex: 1;
- flex-wrap: nowrap;
- padding: 0.6em;
- min-width: 0;
-
- .avatar-container {
- width: 32px;
- height: 32px;
- }
- }
-
- .follow-request-accept {
- &:hover {
- color: var(--text);
- }
- }
-
- .follow-request-reject {
- &:hover {
- color: var(--cRed);
- }
- }
-
- .follow-text,
- .move-text {
- padding: 0.5em 0;
- overflow-wrap: break-word;
- display: flex;
- justify-content: space-between;
-
- .follow-name {
- display: block;
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
-
- time {
- white-space: nowrap;
- }
-
- .notification-right {
- flex: 1;
- padding-left: 0.8em;
- min-width: 0;
-
- .timeago {
- min-width: 3em;
- text-align: right;
- }
-
- .timeago-link {
- margin-right: 0.2em;
- }
-
- .expand-icon {
- .svg-inline--fa {
- margin-left: 0.25em;
- }
- }
- }
-
- .emoji-reaction-emoji {
- font-size: 1.3em;
- max-width: 1.25em;
- height: 1.25em;
- width: auto;
-
- &.-wide {
- max-width: 3.75em;
- }
- }
-
- .emoji-reaction-emoji-image {
- vertical-align: middle;
- object-fit: contain;
- }
-
- .notification-details {
- min-width: 0;
- line-height: var(--post-line-height);
- position: relative;
- overflow: hidden;
- width: 100%;
- flex: 1 1 0;
- display: flex;
- flex-wrap: nowrap;
- justify-content: space-between;
-
- .name-and-action {
- flex: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .username {
- font-weight: bolder;
- max-width: 100%;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .timeago {
- margin-right: 0.2em;
- }
-
- .status-content {
- margin: 0;
- max-height: 300px;
- }
-
- h1 {
- overflow-wrap: break-word;
- text-wrap: pretty;
- margin: 0 0 0.3em;
- padding: 0;
- font-size: 1em;
- line-height: 1.5;
-
- small {
- font-weight: lighter;
- }
- }
- p {
- margin: 0;
- margin-top: 0;
- margin-bottom: 0.3em;
+ &:last-child .Notification {
+ border-bottom: none;
}
}
}
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index f69eba0928..643fa7dae5 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -1,110 +1,110 @@
<template>
<teleport
:disabled="minimalMode || disableTeleport"
:to="teleportTarget"
>
<component
:is="noHeading ? 'div' : 'aside'"
ref="root"
:class="{ minimal: minimalMode }"
class="Notifications"
:aria-label="$t('notifications.notifications')"
>
<div :class="mainClass">
<div
v-if="!noHeading"
class="notifications-heading panel-heading -sticky"
>
<h1 class="title">
{{ $t('notifications.notifications') }}
<span
v-if="unseenCountBadgeText"
class="badge -notification unseen-count"
>{{ unseenCountBadgeText }}</span>
</h1>
<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>
<button
v-if="unseenCount"
class="button-default read-button"
type="button"
@click.prevent="markAsSeen"
>
{{ $t('notifications.read') }}
</button>
<NotificationFilters class="rightside-button" />
</div>
<div
role="feed"
>
<article
v-if="showExtraNotifications"
class="notification"
>
<extra-notifications />
</article>
<article
v-for="notification in notificationsToDisplay"
:key="notification.id"
class="notification"
:class="{unseen: !minimalMode && shouldShowUnseen(notification)}"
@click="e => notificationClicked(notification)"
>
<div class="notification-overlay" />
- <notification
+ <Notification
:notification="notification"
@interacted="e => notificationInteracted(notification)"
/>
</article>
</div>
<div class="panel-footer">
<div
v-if="bottomedOut"
class="new-status-notification text-center faint"
>
{{ $t('notifications.no_more_notifications') }}
</div>
<button
v-else-if="!loading"
class="button-unstyled -link text-center"
@click.prevent="fetchOlderNotifications()"
>
<div class="new-status-notification text-center">
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }}
</div>
</button>
<div
v-else
class="new-status-notification text-center"
>
<FAIcon
icon="circle-notch"
spin
size="lg"
/>
</div>
</div>
</div>
</component>
</teleport>
</template>
<script src="./notifications.js"></script>
<style lang="scss" src="./notifications.scss"></style>
diff --git a/src/components/status/status.scss b/src/components/status/status.scss
index 0ed48c7f56..c9741efc38 100644
--- a/src/components/status/status.scss
+++ b/src/components/status/status.scss
@@ -1,368 +1,364 @@
.Status {
min-width: 0;
white-space: normal;
overflow-wrap: break-word;
text-wrap: pretty;
display: flex;
flex-direction: column;
&:hover {
--_still-image-img-visibility: visible;
--_still-image-canvas-visibility: hidden;
--_still-image-label-visibility: hidden;
}
.gravestone {
padding: var(--status-margin);
display: flex;
.deleted-text {
margin: 0.5em 0;
align-items: center;
}
}
.status-container {
display: flex;
padding: var(--status-margin);
gap: var(--status-margin);
> * {
min-width: 0;
}
}
.pin {
display: flex;
align-items: center;
justify-content: flex-end;
margin-right: 0.5em;
}
._misclick-prevention & {
pointer-events: none;
.attachments {
pointer-events: initial;
cursor: initial;
}
}
.left-side {
flex: 0 0 auto;
}
.right-side {
flex: 1 1 auto;
display: flex;
flex-direction: column;
gap: calc(var(--status-margin) / 2);
}
.usercard {
margin-bottom: var(--status-margin);
}
.status-username {
white-space: nowrap;
overflow: hidden;
max-width: 85%;
font-weight: bold;
flex-shrink: 1;
margin-right: 0.4em;
text-overflow: ellipsis;
--_still_image-label-scale: 0.25;
--emoji-size: 1em;
}
.status-favicon {
height: 1.2em;
width: 1.2em;
margin-right: 0.4em;
object-fit: contain;
}
.heading-name-row {
display: flex;
justify-content: space-between;
line-height: 1.3;
a {
display: inline-block;
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;
width: 100%
}
}
.account-name {
display: inline-block;
min-width: 1em;
margin-right: 0.4em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1 1 0;
&.unknown {
min-width: 8em;
}
}
.heading-left {
display: flex;
min-width: 0;
}
.heading-right {
display: flex;
flex-shrink: 0;
align-self: baseline;
word-break: keep-all;
- margin-right: -0.25em;
+ margin-right: calc(var(--status-margin) / -2);
.visibility-icon,
.button-unstyled {
- margin: -0.25em 0;
- padding: 0.25em;
+ margin: calc(var(--status-margin) / -2) 0;
+ padding: calc(var(--status-margin) / 2);
}
}
.glued-label {
display: inline-flex;
white-space: nowrap;
}
- .timeago {
- margin-right: 0.25em;
- }
-
& .heading-reply-row,
& .heading-edited-row {
position: relative;
align-content: baseline;
font-size: 0.85em;
line-height: 130%;
max-width: 100%;
align-items: stretch;
}
& .reply-to-popover,
& .reply-to-no-popover,
& .mentions {
min-width: 0;
margin-right: 0.4em;
flex-shrink: 0;
}
.reply-glued-label {
margin-right: 0.5em;
}
.reply-to-popover {
.faint-link:hover {
// override default
text-decoration: none;
}
&.-strikethrough {
.reply-to::after {
content: "";
display: block;
position: absolute;
top: 50%;
width: 100%;
border-bottom: 1px solid var(--faint);
pointer-events: none;
}
}
}
& .mentions,
& .reply-to {
white-space: nowrap;
position: relative;
}
& .mentions-text,
& .reply-to-text {
color: var(--faint);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mentions-line {
display: inline;
}
.replies {
margin-top: 0.25em;
line-height: 1.3;
font-size: 0.85em;
display: flex;
flex-wrap: wrap;
& > * {
margin-right: 0.4em;
}
}
.reply-link {
height: 17px;
}
.repeat-info {
display: flex;
align-items: center;
padding: 0.4em var(--status-margin);
.repeater-avatar {
flex: 0 0 1.5em;
border-radius: var(--roundness);
margin-left: 2em; // 3.5 (poster avatar size) - 1.5 (repeater avatar size)
width: 1.5em;
height: 1.5em;
}
.right-side {
display: flex;
flex-direction: row;
flex: 1 1 auto;
overflow-x: hidden;
text-overflow: ellipsis;
margin-right: 0;
.repeater-name {
flex: 0 1 auto;
margin: 0;
}
.repeat-label {
white-space: nowrap;
flex: 0 0 auto;
.repeat-icon {
vertical-align: middle;
color: var(--cGreen);
}
}
.emoji {
width: 1em;
height: 1em;
vertical-align: middle;
object-fit: contain;
}
}
}
.status-actions {
position: relative;
width: 100%;
display: grid;
grid-template-columns: 1fr;
grid-auto-columns: 1fr;
grid-auto-flow: column;
margin-top: var(--status-margin);
}
.muted {
padding: 0.25em 0.6em;
height: 1.2em;
line-height: 1.2em;
text-overflow: ellipsis;
overflow: hidden;
display: flex;
flex-wrap: nowrap;
gap: 1ex;
& .status-username,
& .mute-reason {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.status-username {
font-weight: normal;
flex: 0 1 auto;
margin-right: 0.2em;
font-size: smaller;
display: flex;
}
.unmute {
flex: 0 0 auto;
margin-left: auto;
display: block;
}
}
.reply-form {
padding-top: 0;
padding-bottom: 0;
}
.reply-body {
flex: 1;
}
.favs-repeated-users {
margin-top: var(--status-margin);
}
.stats {
width: 100%;
display: flex;
line-height: 1em;
}
.avatar-row {
flex: 1;
position: relative;
display: flex;
align-items: center;
overflow: hidden;
&::before {
content: "";
position: absolute;
height: 100%;
width: 1px;
left: 0;
background-color: var(--textFaint);
}
}
.stat-count {
margin-right: var(--status-margin);
user-select: none;
.stat-title {
color: var(--textFaint);
font-size: 0.85em;
text-transform: uppercase;
position: relative;
}
.stat-number {
font-weight: bolder;
font-size: 1.1em;
line-height: 1em;
color: var(--text);
}
&:hover .stat-title {
text-decoration: underline;
}
}
.thread-tree-show-replies-button {
display: block;
padding: var(--status-margin);
padding-left: var(--status-margin);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Oct 10, 7:14 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1785091
Default Alt Text
(27 KB)

Event Timeline