-<section class="section sectionContainerList dashboardBoxRecentActivity" id="boxRecentActivity{@$boxID}">
+<section class="section dashboardBoxRecentActivity">
<header class="sectionHeader">
<h2 class="sectionTitle">{lang}wcf.user.recentActivity{/lang}</h2>
</header>
{assign var='__events' value=$eventList->getObjects()}
{assign var='__lastEvent' value=$__events|end}
- <ul class="containerList recentActivityList"
- data-last-event-time="{@$lastEventTime}"
- data-last-event-id="{if $__lastEvent}{@$__lastEvent->eventID}{else}0{/if}"
+ <div class="recentActivityList"
+ id="boxRecentActivity{$boxID}"
+ data-last-event-time="{$lastEventTime}"
+ data-last-event-id="{if $__lastEvent}{$__lastEvent->eventID}{else}0{/if}"
data-filtered-by-followed-users="{if $filteredByFollowedUsers}true{else}false{/if}"
- data-user-id="0"
- data-box-id="{@$boxID}"
+ data-box-id="{$boxID}"
>
{if $canFilterByFollowedUsers}
- <li class="containerListButtonGroup jsOnly jsRecentActivitySwitchContext">
+ <div class="recentActivityList__switchContext">
<ul class="buttonGroup">
- <li><a href="#" class="button small{if !$filteredByFollowedUsers} active{/if}">{lang}wcf.user.recentActivity.scope.all{/lang}</a></li>
- <li><a href="#" class="button small{if $filteredByFollowedUsers} active{/if}">{lang}wcf.user.recentActivity.scope.followedUsers{/lang}</a></li>
+ <li>
+ <button type="button" class="recentActivityList__switchContextButton button small{if !$filteredByFollowedUsers} active{/if}">
+ {lang}wcf.user.recentActivity.scope.all{/lang}
+ </button>
+ </li>
+ <li>
+ <button type="button" class="recentActivityList__switchContextButton button small{if $filteredByFollowedUsers} active{/if}">
+ {lang}wcf.user.recentActivity.scope.followedUsers{/lang}
+ </button>
+ </li>
</ul>
-
- {if $filteredByFollowedUsersOverride}
- <p class="info recentActivityFollowedNoResults">{lang}wcf.user.recentActivity.scope.followedUsers.noResults{/lang}</p>
- {/if}
- </li>
+ </div>
+
+ {if $filteredByFollowedUsers && !$__events|count}
+ <div class="recentActivityList__showMoreButton">
+ <small>{lang}wcf.user.recentActivity.scope.followedUsers.noResults{/lang}</small>
+ </div>
+ {/if}
{/if}
{include file='recentActivityListItem'}
- </ul>
+ </div>
</section>
<script data-relocate="true">
- require(['Language', 'WoltLabSuite/Core/Ui/User/Activity/Recent'], function (Language, UiUserActivityRecent) {
- Language.addObject({
- 'wcf.user.recentActivity.more': '{jslang}wcf.user.recentActivity.more{/jslang}',
- 'wcf.user.recentActivity.noMoreEntries': '{jslang}wcf.user.recentActivity.noMoreEntries{/jslang}'
- });
-
- new UiUserActivityRecent('boxRecentActivity{@$boxID}');
+ require(['WoltLabSuite/Core/Component/User/RecentActivity/Loader'], ({ setup }) => {
+ {jsphrase name='wcf.user.recentActivity.more'}
+ {jsphrase name='wcf.user.recentActivity.noMoreEntries'}
+
+ setup(document.getElementById('boxRecentActivity{unsafe:$boxID|encodeJS}'));
});
</script>
{hascontent}
- <script data-relocate="true">
- $(function() {
- WCF.Language.addObject({
- 'wcf.user.recentActivity.more': '{jslang}wcf.user.recentActivity.more{/jslang}',
- 'wcf.user.recentActivity.noMoreEntries': '{jslang}wcf.user.recentActivity.noMoreEntries{/jslang}'
- });
-
- new WCF.User.RecentActivityLoader({@$userID});
- });
- </script>
-
- <ul id="recentActivities" class="containerList recentActivityList" data-last-event-time="{@$lastEventTime}">
+ <div id="recentActivities" class="recentActivityList recentActivityList--userProfileContent" data-last-event-time="{$lastEventTime}" data-user-id="{$userID}">
{content}
{include file='recentActivityListItem'}
{/content}
- </ul>
+ </div>
+
+ <script data-relocate="true">
+ require(['WoltLabSuite/Core/Component/User/RecentActivity/Loader'], ({ setup }) => {
+ {jsphrase name='wcf.user.recentActivity.more'}
+ {jsphrase name='wcf.user.recentActivity.noMoreEntries'}
+
+ setup(document.getElementById('recentActivities'));
+ });
+ </script>
{hascontentelse}
<div class="section">
{if $placeholder|isset}{$placeholder}{/if}
{include file='header'}
{if $eventList|count}
- <div class="section sectionContainerList">
- <ul id="recentActivities" class="containerList recentActivityList" data-last-event-time="{@$lastEventTime}">
- {include file='recentActivityListItem'}
- </ul>
+ <div id="recentActivities" class="section recentActivityList" data-last-event-time="{@$lastEventTime}">
+ {include file='recentActivityListItem'}
</div>
<footer class="contentFooter">
{/if}
<script data-relocate="true">
- $(function() {
- WCF.Language.addObject({
- 'wcf.user.recentActivity.more': '{jslang}wcf.user.recentActivity.more{/jslang}',
- 'wcf.user.recentActivity.noMoreEntries': '{jslang}wcf.user.recentActivity.noMoreEntries{/jslang}'
- });
-
- new WCF.User.RecentActivityLoader(null);
+ require(['WoltLabSuite/Core/Component/User/RecentActivity/Loader'], ({ setup }) => {
+ {jsphrase name='wcf.user.recentActivity.more'}
+ {jsphrase name='wcf.user.recentActivity.noMoreEntries'}
+
+ setup(document.getElementById('recentActivities'));
});
</script>
{foreach from=$eventList item=event}
- <li>
- <div class="box48{if $__wcf->getUserProfileHandler()->isIgnoredUser($event->getUserProfile()->userID, 2)} ignoredUserContent{/if}">
+ <div class="
+ recentActivityListItem
+ {if $event->isIgnoredContent()}ignoredUserContent{/if}
+ {if !$event->getDescription()}recentActivityListItem--compact{/if}
+ ">
+ <div class="recentActivityListItem__avatar">
{user object=$event->getUserProfile() type='avatar48' ariaHidden='true' tabindex='-1'}
-
- <div>
- <div class="containerHeadline">
- <h3>
- {event name='beforeUsername'}
- {user object=$event->getUserProfile()}
- <small class="separatorLeft">{@$event->time|time}</small>
- </h3>
- <div>{@$event->getTitle()}</div>
- <small class="containerContentType">{lang}wcf.user.recentActivity.{@$event->getObjectTypeName()}{/lang}</small>
- </div>
-
- {if $event->getDescription() !== ''}
- <div class="containerContent{if !$event->isRawHtml()} htmlContent{/if}">{@$event->getDescription()}</div>
- {/if}
+ </div>
+
+ <h3 class="recentActivityListItem__title">
+ {if $event->getLink()}
+ <a href="{$event->getLink()}" class="recentActivityListItem__link">{unsafe:$event->getTitle()}</a>
+ {else}
+ {unsafe:$event->getTitle()}
+ {/if}
+ </h3>
+
+ {if $event->getDescription()}
+ <div class="recentActivityListItem__description{if !$event->isRawHtml()} htmlContent{/if}">
+ {unsafe:$event->getDescription()}
</div>
+ {/if}
+
+ <div class="recentActivityListItem__time">
+ {time time=$event->time}
</div>
- </li>
+ </div>
{/foreach}
use wcf\data\user\UserProfile;
use wcf\system\cache\runtime\UserProfileRuntimeCache;
use wcf\system\user\activity\event\UserActivityEventHandler;
+use wcf\system\user\UserProfileHandler;
/**
* Provides methods for viewable user activity events.
*/
protected $isRawHtml = false;
+ /**
+ * @since 6.1
+ */
+ protected string $link = '';
+
/**
* Marks this event as accessible for current user.
*/
{
return $this->isRawHtml;
}
+
+ /**
+ * @since 6.1
+ */
+ public function setLink(string $link): void
+ {
+ $this->link = $link;
+ }
+
+ /**
+ * @since 6.1
+ */
+ public function getLink(): string
+ {
+ return $this->link;
+ }
+
+ /**
+ * @since 6.1
+ */
+ public function isIgnoredContent(): bool
+ {
+ return UserProfileHandler::getInstance()->getUserProfile()->isIgnoredUser($this->getUserProfile()->userID, 2);
+ }
}
margin-left: 5px;
}
}
-
- > .recentActivityFollowedNoResults {
- text-align: left;
- }
}
@include screen-md-down {
}
}
-.recentActivityList {
- .box48 {
- max-height: 500px;
- overflow: hidden;
-
- > a:first-child {
- align-self: flex-start;
- }
- }
-}
-
.flexibleCategoryList {
position: relative;
--- /dev/null
+.recentActivityList {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+
+ &.recentActivityList--userProfileContent {
+ padding-top: 20px;
+ }
+}
+
+.recentActivityListItem {
+ display: grid;
+ grid-template-areas:
+ "avatar title"
+ "avatar description"
+ "avatar time";
+ grid-template-columns: min-content 1fr;
+ column-gap: 15px;
+ row-gap: 5px;
+ position: relative;
+
+ &.recentActivityListItem--compact {
+ grid-template-areas:
+ "avatar title"
+ "avatar time";
+ }
+
+ &:not(:last-child) {
+ padding-bottom: 20px;
+ border-bottom: 1px solid var(--wcfContentBorderInner);
+ }
+}
+
+.recentActivityListItem__avatar {
+ grid-area: avatar;
+}
+
+.recentActivityListItem__title {
+ grid-area: title;
+
+ @include wcfFontHeadline;
+}
+
+.recentActivityListItem__description {
+ grid-area: description;
+ margin-top: 5px;
+}
+
+.recentActivityListItem__time {
+ grid-area: time;
+ color: var(--wcfContentDimmedText);
+
+ @include wcfFontSmall;
+}
+
+.recentActivityListItem__link {
+ color: inherit;
+
+ &::before {
+ content: "";
+ inset: 0;
+ position: absolute;
+ }
+
+ &:hover,
+ &:focus {
+ color: inherit;
+ }
+}
+
+.recentActivityList__showMoreButton {
+ display: flex;
+ justify-content: center;
+}
+
+.recentActivityList__switchContext {
+ border-bottom: 1px solid var(--wcfContentBorderInner);
+ display: flex;
+ justify-content: end;
+ padding-bottom: 20px;
+}