Overhaul recent activity visuals
authorMarcel Werk <burntime@woltlab.com>
Thu, 15 Feb 2024 15:32:39 +0000 (16:32 +0100)
committerMarcel Werk <burntime@woltlab.com>
Thu, 15 Feb 2024 15:32:39 +0000 (16:32 +0100)
com.woltlab.wcf/templates/boxRecentActivity.tpl
com.woltlab.wcf/templates/recentActivities.tpl
com.woltlab.wcf/templates/recentActivityList.tpl
com.woltlab.wcf/templates/recentActivityListItem.tpl
wcfsetup/install/files/lib/data/user/activity/event/ViewableUserActivityEvent.class.php
wcfsetup/install/files/style/layout/containerList.scss
wcfsetup/install/files/style/ui/recentActivityList.scss [new file with mode: 0644]

index aa23e1a75770a8a01162276f1028f60a53723774..f6345b97e6ae1fd8096c53da2acf3e3ee6e955aa 100644 (file)
@@ -1,41 +1,49 @@
-<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>
index cb05498a4fe6854039ac3ec39f839768d05bd4f9..32960ff4a3049471a3493f93f4495fb54af6ebad 100644 (file)
@@ -1,20 +1,18 @@
 {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}
index 561aa137baf5c640cd4d88a9810ea1408abc3d8d..fd77e9ad41773ec5668f07e765e8496bfd8a8c86 100644 (file)
@@ -1,10 +1,8 @@
 {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>
 
index 65638ee84ece32130650510432b20dc0981019a8..dbd2b36d4f31e2f014e66ab69c0eed43cd5cccb3 100644 (file)
@@ -1,23 +1,29 @@
 {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}
index 34626a8437ce80a1824acb41598258601fa77304..dd0c8aa7c277b1e291c75e9bd3bf4c58957cc6b9 100644 (file)
@@ -6,6 +6,7 @@ use wcf\data\DatabaseObjectDecorator;
 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.
@@ -60,6 +61,11 @@ class ViewableUserActivityEvent extends DatabaseObjectDecorator
      */
     protected $isRawHtml = false;
 
+    /**
+     * @since 6.1
+     */
+    protected string $link = '';
+
     /**
      * Marks this event as accessible for current user.
      */
@@ -183,4 +189,28 @@ class ViewableUserActivityEvent extends DatabaseObjectDecorator
     {
         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);
+    }
 }
index a2de5f116df63f09e99d1e04aeec0a3941ab1022..28f541ee0a14e3a7e94145ee71138a5629d50c26 100644 (file)
                                        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;
 
diff --git a/wcfsetup/install/files/style/ui/recentActivityList.scss b/wcfsetup/install/files/style/ui/recentActivityList.scss
new file mode 100644 (file)
index 0000000..fc5a3fd
--- /dev/null
@@ -0,0 +1,81 @@
+.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;
+}