Parcourir la source

Merge pull request #5606 from goforthanddie/dev

[Improvement] Display link to "Legal Notice" page if the page is active as required by German law
daniel il y a 2 mois
Parent
commit
34c5dc75ed

+ 1 - 0
app/Services/LandingService.php

@@ -52,6 +52,7 @@ class LandingService
             'domain' => config('pixelfed.domain.app'),
             'show_directory' => (bool) config_cache('instance.landing.show_directory'),
             'show_explore_feed' => (bool) config_cache('instance.landing.show_explore'),
+            'show_legal_notice_link' => (bool) config_cache('instance.has_legal_notice'),
             'open_registration' => (bool) $openReg,
             'curated_onboarding' => (bool) config_cache('instance.curated_registration.enabled'),
             'version' => config('pixelfed.version'),

+ 1 - 0
app/Util/Site/Config.php

@@ -29,6 +29,7 @@ class Config
             return [
                 'version' => config('pixelfed.version'),
                 'open_registration' => (bool) config_cache('pixelfed.open_registration'),
+                'show_legal_notice_link' => (bool) config_cache('instance.has_legal_notice'),
                 'uploader' => [
                     'max_photo_size' => (int) config_cache('pixelfed.max_photo_size'),
                     'max_caption_length' => (int) config_cache('pixelfed.max_caption_length'),

+ 32 - 30
resources/assets/components/landing/sections/footer.vue

@@ -1,37 +1,39 @@
 <template>
-	<div class="footer-component">
-		<div class="footer-component-links">
-			<a href="/site/help">Help</a>
-			<div class="spacer">·</div>
-			<a href="/site/terms">Terms</a>
-			<div class="spacer">·</div>
-			<a href="/site/privacy">Privacy</a>
-			<div class="spacer">·</div>
-			<a href="https://pixelfed.org/mobile-apps" target="_blank">Mobile Apps</a>
-		</div>
+    <div class="footer-component">
+        <div class="footer-component-links">
+            <a href="/site/help">Help</a>
+            <div class="spacer">·</div>
+            <a href="/site/terms">Terms</a>
+            <div class="spacer">·</div>
+            <a href="/site/privacy">Privacy</a>
+            <div class="spacer">·</div>
+            <a v-if="config.show_legal_notice_link" href="/site/legal-notice">Legal Notice</a>
+            <div v-if="config.show_legal_notice_link" class="spacer">·</div>
+            <a href="https://pixelfed.org/mobile-apps" target="_blank">Mobile Apps</a>
+        </div>
 
-		<div class="footer-component-attribution">
-			<div><span>© {{ getYear() }} {{config.domain}}</span></div>
-			<div class="spacer">·</div>
-			<div><a href="https://pixelfed.org" class="text-bluegray-500 font-weight-bold">Powered by Pixelfed</a></div>
-			<div class="spacer">·</div>
-			<div><span>v{{config.version}}</span></div>
-		</div>
-	</div>
+        <div class="footer-component-attribution">
+            <div><span>© {{ getYear() }} {{ config.domain }}</span></div>
+            <div class="spacer">·</div>
+            <div><a href="https://pixelfed.org" class="text-bluegray-500 font-weight-bold">Powered by Pixelfed</a></div>
+            <div class="spacer">·</div>
+            <div><span>v{{ config.version }}</span></div>
+        </div>
+    </div>
 </template>
 
 <script type="text/javascript">
-	export default {
-		data() {
-			return {
-				config: window.pfl
-			}
-		},
+export default {
+    data() {
+        return {
+            config: window.pfl
+        }
+    },
 
-		methods: {
-			getYear() {
-				return (new Date().getFullYear());
-			}
-		}
-	}
+    methods: {
+        getYear() {
+            return (new Date().getFullYear());
+        }
+    }
+}
 </script>

+ 771 - 735
resources/assets/components/partials/profile/ProfileSidebar.vue

@@ -1,107 +1,123 @@
 <template>
-	<div class="profile-sidebar-component">
-		<div>
-			<div class="d-block d-md-none">
-				<div class="media user-card user-select-none">
-					<div style="position: relative;">
-						<img :src="profile.avatar" class="avatar shadow cursor-pointer" draggable="false" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';">
-					</div>
-					<div class="media-body">
-						<p class="display-name" v-html="getDisplayName()"></p>
-						<p class="username" :class="{ remote: !profile.local }">
-							<a v-if="!profile.local" :href="profile.url" class="primary">&commat;{{ profile.acct }}</a>
-							<span v-else>&commat;{{ profile.acct }}</span>
-							<span v-if="profile.locked">
+    <div class="profile-sidebar-component">
+        <div>
+            <div class="d-block d-md-none">
+                <div class="media user-card user-select-none">
+                    <div style="position: relative;">
+                        <img :src="profile.avatar" class="avatar shadow cursor-pointer" draggable="false"
+                             onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';">
+                    </div>
+                    <div class="media-body">
+                        <p class="display-name" v-html="getDisplayName()"></p>
+                        <p class="username" :class="{ remote: !profile.local }">
+                            <a v-if="!profile.local" :href="profile.url" class="primary">&commat;{{ profile.acct }}</a>
+                            <span v-else>&commat;{{ profile.acct }}</span>
+                            <span v-if="profile.locked">
 								<i class="fal fa-lock ml-1 fa-sm text-lighter"></i>
 							</span>
-						</p>
-						<div class="stats">
-							<div class="stats-posts" @click="toggleTab('index')">
-								<div class="posts-count">{{ formatCount(profile.statuses_count) }}</div>
-								<div class="stats-label">
-									{{ $t('profile.posts') }}
-								</div>
-							</div>
-							<div class="stats-followers" @click="toggleTab('followers')">
-								<div class="followers-count">{{ formatCount(profile.followers_count) }}</div>
-								<div class="stats-label">
-									{{ $t('profile.followers') }}
-								</div>
-							</div>
-							<div class="stats-following" @click="toggleTab('following')">
-								<div class="following-count">{{ formatCount(profile.following_count) }}</div>
-								<div class="stats-label">
-									{{ $t('profile.following') }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
+                        </p>
+                        <div class="stats">
+                            <div class="stats-posts" @click="toggleTab('index')">
+                                <div class="posts-count">{{ formatCount(profile.statuses_count) }}</div>
+                                <div class="stats-label">
+                                    {{ $t('profile.posts') }}
+                                </div>
+                            </div>
+                            <div class="stats-followers" @click="toggleTab('followers')">
+                                <div class="followers-count">{{ formatCount(profile.followers_count) }}</div>
+                                <div class="stats-label">
+                                    {{ $t('profile.followers') }}
+                                </div>
+                            </div>
+                            <div class="stats-following" @click="toggleTab('following')">
+                                <div class="following-count">{{ formatCount(profile.following_count) }}</div>
+                                <div class="stats-label">
+                                    {{ $t('profile.following') }}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <div class="d-none d-md-flex justify-content-between align-items-center">
+                <button class="btn btn-link" @click="goBack()">
+                    <i class="far fa-chevron-left fa-lg text-lighter"></i>
+                </button>
+                <div>
+                    <img :src="getAvatar()" class="avatar img-fluid shadow border"
+                         onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';">
+                    <p v-if="profile.is_admin" class="text-right" style="margin-top: -30px;"><span class="admin-label">Admin</span>
+                    </p>
+                </div>
+                <!-- <button class="btn btn-link">
+                    <i class="far fa-lg fa-cog text-lighter"></i>
+                </button> -->
+
+                <b-dropdown
+                    variant="link"
+                    right
+                    no-caret>
+                    <template #button-content>
+                        <i class="far fa-lg fa-cog text-lighter"></i>
+                    </template>
+
+                    <b-dropdown-item v-if="profile.local" href="#" link-class="font-weight-bold"
+                                     @click.prevent="goToOldProfile()">View in old UI
+                    </b-dropdown-item>
+                    <b-dropdown-item href="#" link-class="font-weight-bold"
+                                     @click.prevent="copyTextToClipboard(profile.url)">Copy Link
+                    </b-dropdown-item>
+
+
+                    <b-dropdown-item v-if="profile.local" :href="'/users/' + profile.username + '.atom'"
+                                     link-class="font-weight-bold">Atom feed
+                    </b-dropdown-item>
+
+                    <div v-if="profile.id == user.id">
+                        <b-dropdown-divider></b-dropdown-divider>
+                        <b-dropdown-item href="/settings/home" link-class="font-weight-bold">
+                            <i class="far fa-cog mr-1"></i> Settings
+                        </b-dropdown-item>
+                    </div>
 
-			<div class="d-none d-md-flex justify-content-between align-items-center">
-				<button class="btn btn-link" @click="goBack()">
-					<i class="far fa-chevron-left fa-lg text-lighter"></i>
-				</button>
-				<div>
-					<img :src="getAvatar()" class="avatar img-fluid shadow border" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';">
-					<p v-if="profile.is_admin" class="text-right" style="margin-top: -30px;"><span class="admin-label">Admin</span></p>
-				</div>
-				<!-- <button class="btn btn-link">
-					<i class="far fa-lg fa-cog text-lighter"></i>
-				</button> -->
-
-				<b-dropdown
-					variant="link"
-					right
-					no-caret>
-					<template #button-content>
-						<i class="far fa-lg fa-cog text-lighter"></i>
-					</template>
-
-					<b-dropdown-item v-if="profile.local" href="#" link-class="font-weight-bold" @click.prevent="goToOldProfile()">View in old UI</b-dropdown-item>
-					<b-dropdown-item href="#" link-class="font-weight-bold" @click.prevent="copyTextToClipboard(profile.url)">Copy Link</b-dropdown-item>
-
-
-					<b-dropdown-item v-if="profile.local" :href="'/users/' + profile.username + '.atom'" link-class="font-weight-bold">Atom feed</b-dropdown-item>
-
-					<div v-if="profile.id == user.id">
-						<b-dropdown-divider></b-dropdown-divider>
-						<b-dropdown-item href="/settings/home" link-class="font-weight-bold">
-							<i class="far fa-cog mr-1"></i> Settings
-						</b-dropdown-item>
-					</div>
-
-					<div v-else>
-						<b-dropdown-item v-if="!profile.local" :href="profile.url" link-class="font-weight-bold">View Remote Profile</b-dropdown-item>
-						<b-dropdown-item :href="'/i/web/direct/thread/' + profile.id" link-class="font-weight-bold">Direct Message</b-dropdown-item>
-					</div>
-
-					<div v-if="profile.id !== user.id">
-						<b-dropdown-divider></b-dropdown-divider>
-
-						<b-dropdown-item link-class="font-weight-bold" @click="handleMute()">
-							{{ relationship.muting ? 'Unmute' : 'Mute' }}
-						</b-dropdown-item>
-
-						<b-dropdown-item link-class="font-weight-bold" @click="handleBlock()">
-							{{ relationship.blocking ? 'Unblock' : 'Block' }}
-						</b-dropdown-item>
-
-						<b-dropdown-item :href="'/i/report?type=user&id=' + profile.id" link-class="text-danger font-weight-bold">Report</b-dropdown-item>
-					</div>
-				</b-dropdown>
-			</div>
+                    <div v-else>
+                        <b-dropdown-item v-if="!profile.local" :href="profile.url" link-class="font-weight-bold">View
+                            Remote Profile
+                        </b-dropdown-item>
+                        <b-dropdown-item :href="'/i/web/direct/thread/' + profile.id" link-class="font-weight-bold">
+                            Direct Message
+                        </b-dropdown-item>
+                    </div>
+
+                    <div v-if="profile.id !== user.id">
+                        <b-dropdown-divider></b-dropdown-divider>
+
+                        <b-dropdown-item link-class="font-weight-bold" @click="handleMute()">
+                            {{ relationship.muting ? 'Unmute' : 'Mute' }}
+                        </b-dropdown-item>
 
-			<div class="d-none d-md-block text-center">
-				<p v-html="getDisplayName()" class="display-name"></p>
+                        <b-dropdown-item link-class="font-weight-bold" @click="handleBlock()">
+                            {{ relationship.blocking ? 'Unblock' : 'Block' }}
+                        </b-dropdown-item>
 
-				<p class="username" :class="{ remote: !profile.local }">
-					<a v-if="!profile.local" :href="profile.url" class="primary">&commat;{{ profile.acct }}</a>
-					<span v-else>&commat;{{ profile.acct }}</span>
-					<span v-if="profile.locked">
+                        <b-dropdown-item :href="'/i/report?type=user&id=' + profile.id"
+                                         link-class="text-danger font-weight-bold">Report
+                        </b-dropdown-item>
+                    </div>
+                </b-dropdown>
+            </div>
+
+            <div class="d-none d-md-block text-center">
+                <p v-html="getDisplayName()" class="display-name"></p>
+
+                <p class="username" :class="{ remote: !profile.local }">
+                    <a v-if="!profile.local" :href="profile.url" class="primary">&commat;{{ profile.acct }}</a>
+                    <span v-else>&commat;{{ profile.acct }}</span>
+                    <span v-if="profile.locked">
 						<i class="fal fa-lock ml-1 fa-sm text-lighter"></i>
 					</span>
+
 				</p>
 
 				<p v-if="user.id != profile.id && (relationship.followed_by || relationship.muting || relationship.blocking)" class="mt-n3 text-center">
@@ -148,7 +164,7 @@
                        {{ $t("profile.myPortifolio") }}
                         <span class="badge badge-success ml-1">NEW</span>
                     </a>
-				</div>
+                </div>
 
                 <div v-else-if="profile.hasOwnProperty('moved') && profile.moved.id" style="flex-grow: 1;">
                     <div class="card shadow-none rounded-lg mb-3 bg-danger">
@@ -158,687 +174,707 @@
                                 Account has moved to:
                             </div>
                             <p class="mb-0 lead ft-std text-white text-break">
-                                <router-link :to="`/i/web/profile/${profile.moved.id}`" class="btn btn-outline-light btn-block rounded-pill font-weight-bold">&commat;{{truncate(profile.moved.acct)}}</router-link>
+                                <router-link :to="`/i/web/profile/${profile.moved.id}`"
+                                             class="btn btn-outline-light btn-block rounded-pill font-weight-bold">
+                                    &commat;{{ truncate(profile.moved.acct) }}
+                                </router-link>
                             </p>
                         </div>
                     </div>
                 </div>
-				<div v-else-if="profile.locked" style="flex-grow: 1;">
-					<template v-if="!relationship.following && !relationship.requested">
-						<button
-							class="btn btn-primary font-weight-bold btn-block follow-btn"
-							@click="follow"
-							:disabled="relationship.blocking">
-							Request Follow
-						</button>
-						<p v-if="relationship.blocking" class="mt-n4 text-lighter" style="font-size: 11px">You need to unblock this account before you can request to follow.</p>
-					</template>
-
-					<div v-else-if="relationship.requested">
-						<button class="btn btn-primary font-weight-bold btn-block follow-btn" disabled>
-							{{ $t('profile.followRequested') }}
-						</button>
-
-						<p class="small font-weight-bold text-center mt-n4">
-							<a href="#" @click.prevent="cancelFollowRequest()">Cancel Follow Request</a>
-						</p>
-					</div>
-
-					<button
-						v-else-if="relationship.following"
-						class="btn btn-primary font-weight-bold btn-block unfollow-btn"
-						@click="unfollow">
-						{{ $t('profile.unfollow') }}
-					</button>
-				</div>
-
-				<div v-else style="flex-grow: 1;">
-					<template v-if="!relationship.following">
-						<button
-							class="btn btn-primary font-weight-bold btn-block follow-btn"
-							@click="follow"
-							:disabled="relationship.blocking">
-							{{ $t('profile.follow') }}
-						</button>
-						<p v-if="relationship.blocking" class="mt-n4 text-lighter" style="font-size: 11px">You need to unblock this account before you can follow.</p>
-					</template>
-
-					<button
-						v-else
-						class="btn btn-primary font-weight-bold btn-block unfollow-btn"
-						@click="unfollow">
-						{{ $t('profile.unfollow') }}
-					</button>
-				</div>
-
-				<div class="d-block d-md-none ml-3">
-					<b-dropdown
-						variant="link"
-						right
-						no-caret>
-						<template #button-content>
-							<i class="far fa-lg fa-cog text-lighter"></i>
-						</template>
-
-						<b-dropdown-item v-if="profile.local" href="#" link-class="font-weight-bold" @click.prevent="goToOldProfile()">View in old UI</b-dropdown-item>
-						<b-dropdown-item href="#" link-class="font-weight-bold" @click.prevent="copyTextToClipboard(profile.url)">Copy Link</b-dropdown-item>
+                <div v-else-if="profile.locked" style="flex-grow: 1;">
+                    <template v-if="!relationship.following && !relationship.requested">
+                        <button
+                            class="btn btn-primary font-weight-bold btn-block follow-btn"
+                            @click="follow"
+                            :disabled="relationship.blocking">
+                            Request Follow
+                        </button>
+                        <p v-if="relationship.blocking" class="mt-n4 text-lighter" style="font-size: 11px">You need to
+                            unblock this account before you can request to follow.</p>
+                    </template>
+
+                    <div v-else-if="relationship.requested">
+                        <button class="btn btn-primary font-weight-bold btn-block follow-btn" disabled>
+                            {{ $t('profile.followRequested') }}
+                        </button>
+
+                        <p class="small font-weight-bold text-center mt-n4">
+                            <a href="#" @click.prevent="cancelFollowRequest()">Cancel Follow Request</a>
+                        </p>
+                    </div>
 
+                    <button
+                        v-else-if="relationship.following"
+                        class="btn btn-primary font-weight-bold btn-block unfollow-btn"
+                        @click="unfollow">
+                        {{ $t('profile.unfollow') }}
+                    </button>
+                </div>
 
-						<b-dropdown-item v-if="profile.local" :href="'/users/' + profile.username + '.atom'" link-class="font-weight-bold">Atom feed</b-dropdown-item>
+                <div v-else style="flex-grow: 1;">
+                    <template v-if="!relationship.following">
+                        <button
+                            class="btn btn-primary font-weight-bold btn-block follow-btn"
+                            @click="follow"
+                            :disabled="relationship.blocking">
+                            {{ $t('profile.follow') }}
+                        </button>
+                        <p v-if="relationship.blocking" class="mt-n4 text-lighter" style="font-size: 11px">You need to
+                            unblock this account before you can follow.</p>
+                    </template>
+
+                    <button
+                        v-else
+                        class="btn btn-primary font-weight-bold btn-block unfollow-btn"
+                        @click="unfollow">
+                        {{ $t('profile.unfollow') }}
+                    </button>
+                </div>
 
-						<div v-if="profile.id == user.id">
-							<b-dropdown-divider></b-dropdown-divider>
-							<b-dropdown-item href="/settings/home" link-class="font-weight-bold">
-								<i class="far fa-cog mr-1"></i> Settings
-							</b-dropdown-item>
-						</div>
+                <div class="d-block d-md-none ml-3">
+                    <b-dropdown
+                        variant="link"
+                        right
+                        no-caret>
+                        <template #button-content>
+                            <i class="far fa-lg fa-cog text-lighter"></i>
+                        </template>
+
+                        <b-dropdown-item v-if="profile.local" href="#" link-class="font-weight-bold"
+                                         @click.prevent="goToOldProfile()">View in old UI
+                        </b-dropdown-item>
+                        <b-dropdown-item href="#" link-class="font-weight-bold"
+                                         @click.prevent="copyTextToClipboard(profile.url)">Copy Link
+                        </b-dropdown-item>
+
+
+                        <b-dropdown-item v-if="profile.local" :href="'/users/' + profile.username + '.atom'"
+                                         link-class="font-weight-bold">Atom feed
+                        </b-dropdown-item>
+
+                        <div v-if="profile.id == user.id">
+                            <b-dropdown-divider></b-dropdown-divider>
+                            <b-dropdown-item href="/settings/home" link-class="font-weight-bold">
+                                <i class="far fa-cog mr-1"></i> Settings
+                            </b-dropdown-item>
+                        </div>
 
-						<div v-else>
-							<b-dropdown-item v-if="!profile.local" :href="profile.url" link-class="font-weight-bold">View Remote Profile</b-dropdown-item>
+                        <div v-else>
+                            <b-dropdown-item v-if="!profile.local" :href="profile.url" link-class="font-weight-bold">
+                                View Remote Profile
+                            </b-dropdown-item>
 
-							<b-dropdown-item :href="'/i/web/direct/thread/' + profile.id" link-class="font-weight-bold">Direct Message</b-dropdown-item>
-						</div>
+                            <b-dropdown-item :href="'/i/web/direct/thread/' + profile.id" link-class="font-weight-bold">
+                                Direct Message
+                            </b-dropdown-item>
+                        </div>
 
-						<div v-if="profile.id !== user.id">
-							<b-dropdown-divider></b-dropdown-divider>
+                        <div v-if="profile.id !== user.id">
+                            <b-dropdown-divider></b-dropdown-divider>
 
-							<b-dropdown-item link-class="font-weight-bold" @click="handleMute()">
-								{{ relationship.muting ? 'Unmute' : 'Mute' }}
-							</b-dropdown-item>
+                            <b-dropdown-item link-class="font-weight-bold" @click="handleMute()">
+                                {{ relationship.muting ? 'Unmute' : 'Mute' }}
+                            </b-dropdown-item>
 
-							<b-dropdown-item link-class="font-weight-bold" @click="handleBlock()">
-								{{ relationship.blocking ? 'Unblock' : 'Block' }}
-							</b-dropdown-item>
+                            <b-dropdown-item link-class="font-weight-bold" @click="handleBlock()">
+                                {{ relationship.blocking ? 'Unblock' : 'Block' }}
+                            </b-dropdown-item>
 
-							<b-dropdown-item :href="'/i/report?type=user&id=' + profile.id" link-class="text-danger font-weight-bold">Report</b-dropdown-item>
-						</div>
-					</b-dropdown>
-				</div>
-			</div>
+                            <b-dropdown-item :href="'/i/report?type=user&id=' + profile.id"
+                                             link-class="text-danger font-weight-bold">Report
+                            </b-dropdown-item>
+                        </div>
+                    </b-dropdown>
+                </div>
+            </div>
 
-			<div v-if="profile.note && renderedBio && renderedBio.length" class="bio-wrapper card shadow-none">
-				<div class="card-body">
-					<div class="bio-body">
-						<div v-html="renderedBio"></div>
-					</div>
-				</div>
-			</div>
+            <div v-if="profile.note && renderedBio && renderedBio.length" class="bio-wrapper card shadow-none">
+                <div class="card-body">
+                    <div class="bio-body">
+                        <div v-html="renderedBio"></div>
+                    </div>
+                </div>
+            </div>
 
-			<div class="d-none d-md-block card card-body shadow-none py-2">
-				<p v-if="profile.website" class="small">
+            <div class="d-none d-md-block card card-body shadow-none py-2">
+                <p v-if="profile.website" class="small">
 					<span class="text-lighter mr-2">
 						<i class="far fa-link"></i>
 					</span>
 
-					<span>
+                    <span>
 						<a :href="profile.website" class="font-weight-bold">{{ profile.website }}</a>
 					</span>
-				</p>
+                </p>
 
-				<p class="mb-0 small">
+                <p class="mb-0 small">
 					<span class="text-lighter mr-2">
 						<i class="far fa-clock"></i>
 					</span>
 
-					<span v-if="profile.local">
+                    <span v-if="profile.local">
 						{{ $t('profile.joined') }} {{ getJoinedDate() }}
 					</span>
-					<span v-else>
+                    <span v-else>
 						{{ $t('profile.joined') }} {{ getJoinedDate() }}
 
 						<span class="float-right primary">
-							<i class="far fa-info-circle" v-b-tooltip.hover title="This user is from a remote server and may have created their account before this date"></i>
+							<i class="far fa-info-circle" v-b-tooltip.hover
+                               title="This user is from a remote server and may have created their account before this date"></i>
 						</span>
 					</span>
-				</p>
-			</div>
-
-			<div class="d-none d-md-flex sidebar-sitelinks">
-				<a href="/site/about">{{ $t('navmenu.about') }}</a>
-				<router-link to="/i/web/help">{{ $t('navmenu.help') }}</router-link>
-				<router-link to="/i/web/language">{{ $t('navmenu.language') }}</router-link>
-				<a href="/site/terms">{{ $t('navmenu.privacy') }}</a>
-				<a href="/site/terms">{{ $t('navmenu.terms') }}</a>
-			</div>
-
-			<div class="d-none d-md-block sidebar-attribution">
-				<a href="https://pixelfed.org" class="font-weight-bold">Powered by Pixelfed</a>
-			</div>
-		</div>
-
-		<b-modal
-			ref="fullBio"
-			centered
-			hide-footer
-			ok-only
-			ok-title="Close"
-			ok-variant="light"
-			:scrollable="true"
-			body-class="p-md-5"
-			title="Bio"
-			>
-			<div v-html="profile.note"></div>
-		</b-modal>
-	</div>
+                </p>
+            </div>
+
+            <div class="d-none d-md-flex flex-wrap sidebar-sitelinks">
+                <a href="/site/about">{{ $t('navmenu.about') }}</a>
+                <router-link to="/i/web/help">{{ $t('navmenu.help') }}</router-link>
+                <router-link to="/i/web/language">{{ $t('navmenu.language') }}</router-link>
+                <a href="/site/terms">{{ $t('navmenu.privacy') }}</a>
+                <a href="/site/terms">{{ $t('navmenu.terms') }}</a>
+                <a v-if="showLegalNoticeLink" href="/site/legal-notice">{{ $t('navmenu.legalNotice') }}</a>
+            </div>
+
+            <div class="d-none d-md-block sidebar-attribution">
+                <a href="https://pixelfed.org" class="font-weight-bold">Powered by Pixelfed</a>
+            </div>
+        </div>
+
+        <b-modal
+            ref="fullBio"
+            centered
+            hide-footer
+            ok-only
+            ok-title="Close"
+            ok-variant="light"
+            :scrollable="true"
+            body-class="p-md-5"
+            title="Bio"
+        >
+            <div v-html="profile.note"></div>
+        </b-modal>
+    </div>
 </template>
 
 <script type="text/javascript">
-	import { mapGetters } from 'vuex'
-
-	export default {
-		props: {
-			profile: {
-				type: Object
-			},
-
-			relationship: {
-				type: Object,
-				default: (function() {
-					return {
-						following: false,
-						followed_by: false
-					};
-				})
-			},
-
-			user: {
-				type: Object
-			}
-		},
-
-		computed: {
-			...mapGetters([
-				'getCustomEmoji'
-			])
-		},
-
-		data() {
-			return {
-				'renderedBio': ''
-			};
-		},
-
-		mounted() {
-			this.$nextTick(() => {
-				this.setBio();
-			});
-		},
-
-		methods: {
-			getDisplayName() {
-				let self = this;
-				let profile = this.profile;
-				let dn = profile.display_name;
-				if(!dn) {
-					return profile.username;
-				}
-				if(dn.includes(':')) {
-					// let re = /:(::|[^:\n])+:/g;
-					let re = /(<a?)?:\w+:(\d{18}>)?/g;
-					let un = dn.replaceAll(re, function(em) {
-						let shortcode = em.slice(1, em.length - 1);
-						let emoji = self.getCustomEmoji.filter(e => {
-							return e.shortcode == shortcode;
-						});
-						return emoji.length ? `<img draggable="false" class="emojione custom-emoji" alt="${emoji[0].shortcode}" title="${emoji[0].shortcode}" src="${emoji[0].url}" data-original="${emoji[0].url}" data-static="${emoji[0].static_url}" width="16" height="16" onerror="this.onerror=null;this.src='/storage/emoji/missing.png';" />`: em;
-					});
-					return un;
-				} else {
-					return dn;
-				}
-			},
-
-            truncate(str) {
-                if(!str) {
+import {mapGetters} from 'vuex'
+
+export default {
+    props: {
+        profile: {
+            type: Object
+        },
+
+        relationship: {
+            type: Object,
+            default: (function () {
+                return {
+                    following: false,
+                    followed_by: false
+                };
+            })
+        },
+
+        user: {
+            type: Object
+        }
+    },
+
+    computed: {
+        ...mapGetters([
+            'getCustomEmoji'
+        ])
+    },
+
+    data() {
+        return {
+            'renderedBio': '',
+            'showLegalNoticeLink': window.App.config.show_legal_notice_link
+        };
+    },
+
+    mounted() {
+        this.$nextTick(() => {
+            this.setBio();
+        });
+    },
+
+    methods: {
+        getDisplayName() {
+            let self = this;
+            let profile = this.profile;
+            let dn = profile.display_name;
+            if (!dn) {
+                return profile.username;
+            }
+            if (dn.includes(':')) {
+                // let re = /:(::|[^:\n])+:/g;
+                let re = /(<a?)?:\w+:(\d{18}>)?/g;
+                let un = dn.replaceAll(re, function (em) {
+                    let shortcode = em.slice(1, em.length - 1);
+                    let emoji = self.getCustomEmoji.filter(e => {
+                        return e.shortcode == shortcode;
+                    });
+                    return emoji.length ? `<img draggable="false" class="emojione custom-emoji" alt="${emoji[0].shortcode}" title="${emoji[0].shortcode}" src="${emoji[0].url}" data-original="${emoji[0].url}" data-static="${emoji[0].static_url}" width="16" height="16" onerror="this.onerror=null;this.src='/storage/emoji/missing.png';" />` : em;
+                });
+                return un;
+            } else {
+                return dn;
+            }
+        },
+
+        truncate(str) {
+            if (!str) {
+                return;
+            }
+            if (str.length > 15) {
+                return str.slice(0, 15) + '...';
+            }
+            return str;
+        },
+
+        formatCount(val) {
+            return App.util.format.count(val);
+        },
+
+        goBack() {
+            this.$emit('back');
+        },
+
+        showFullBio() {
+            this.$refs.fullBio.show();
+        },
+
+        toggleTab(tab) {
+            event.currentTarget.blur();
+            if (['followers', 'following'].includes(tab)) {
+                this.$router.push('/i/web/profile/' + this.profile.id + '/' + tab);
+                return;
+            } else {
+                this.$emit('toggletab', tab);
+            }
+        },
+
+        getJoinedDate() {
+            let d = new Date(this.profile.created_at);
+            let month = new Intl.DateTimeFormat("en-US", {month: "long"}).format(d);
+            let year = d.getFullYear();
+            return `${month} ${year}`;
+        },
+
+        follow() {
+            event.currentTarget.blur();
+            this.$emit('follow');
+        },
+
+        unfollow() {
+            event.currentTarget.blur();
+            this.$emit('unfollow');
+        },
+
+        setBio() {
+            if (!this.profile.note.length) {
+                return;
+            }
+            if (this.profile.local) {
+                let content = this.profile.hasOwnProperty('note_text') ?
+                    this.profile.note_text :
+                    this.profile.note.replace(/(<([^>]+)>)/gi, "");
+                this.renderedBio = window.pftxt.autoLink(content, {
+                    usernameUrlBase: '/i/web/profile/@',
+                    hashtagUrlBase: '/i/web/hashtag/'
+                })
+            } else {
+                if (this.profile.note === '<p></p>') {
+                    this.renderedBio = null;
                     return;
                 }
-                if(str.length > 15) {
-                    return str.slice(0, 15) + '...';
+                let content = this.profile.note;
+                let el = document.createElement('div');
+                el.innerHTML = content;
+                el.querySelectorAll('a[class*="hashtag"]')
+                    .forEach(elr => {
+                        let tag = elr.innerText;
+                        if (tag.substr(0, 1) == '#') {
+                            tag = tag.substr(1);
+                        }
+                        elr.removeAttribute('target');
+                        elr.setAttribute('href', '/i/web/hashtag/' + tag);
+                    })
+                el.querySelectorAll('a:not(.hashtag)[class*="mention"], a:not(.hashtag)[class*="list-slug"]')
+                    .forEach(elr => {
+                        let name = elr.innerText;
+                        if (name.substr(0, 1) == '@') {
+                            name = name.substr(1);
+                        }
+                        if (this.profile.local == false && !name.includes('@')) {
+                            let domain = document.createElement('a');
+                            domain.href = this.profile.url;
+                            name = name + '@' + domain.hostname;
+                        }
+                        elr.removeAttribute('target');
+                        elr.setAttribute('href', '/i/web/username/' + name);
+                    })
+                this.renderedBio = el.outerHTML;
+            }
+        },
+
+        getAvatar() {
+            if (this.profile.id == this.user.id) {
+                return window._sharedData.user.avatar;
+            }
+
+            return this.profile.avatar;
+        },
+
+        copyTextToClipboard(val) {
+            App.util.clipboard(val);
+        },
+
+        goToOldProfile() {
+            if (this.profile.local) {
+                location.href = this.profile.url + '?fs=1';
+            } else {
+                location.href = '/i/web/profile/_/' + this.profile.id;
+            }
+        },
+
+        handleMute() {
+            let msg = this.relationship.muting ? 'unmuted' : 'muted';
+            let url = this.relationship.muting == true ? '/i/unmute' : '/i/mute';
+            axios.post(url, {
+                type: 'user',
+                item: this.profile.id
+            }).then(res => {
+                this.$emit('updateRelationship', res.data);
+                swal('Success', 'You have successfully ' + msg + ' ' + this.profile.acct, 'success');
+            }).catch(err => {
+                if (err.response.status === 422) {
+                    swal({
+                        title: 'Error',
+                        text: err.response?.data?.error,
+                        icon: "error",
+                        buttons: {
+                            review: {
+                                text: "Review muted accounts",
+                                value: "review",
+                                className: "btn-primary"
+                            },
+                            cancel: true,
+                        }
+                    })
+                        .then((val) => {
+                            if (val && val == 'review') {
+                                location.href = '/settings/privacy/muted-users';
+                                return;
+                            }
+                        });
+                } else {
+                    swal('Error', 'Something went wrong. Please try again later.', 'error');
                 }
-                return str;
-            },
-
-			formatCount(val) {
-				return App.util.format.count(val);
-			},
-
-			goBack() {
-				this.$emit('back');
-			},
-
-			showFullBio() {
-				this.$refs.fullBio.show();
-			},
-
-			toggleTab(tab) {
-				event.currentTarget.blur();
-                if(['followers', 'following'].includes(tab)) {
-                    this.$router.push('/i/web/profile/' + this.profile.id + '/' + tab);
-                    return;
+            });
+        },
+
+        handleBlock() {
+            let msg = this.relationship.blocking ? 'unblock' : 'block';
+            let url = this.relationship.blocking == true ? '/i/unblock' : '/i/block';
+            axios.post(url, {
+                type: 'user',
+                item: this.profile.id
+            }).then(res => {
+                this.$emit('updateRelationship', res.data);
+                swal('Success', 'You have successfully ' + msg + 'ed ' + this.profile.acct, 'success');
+            }).catch(err => {
+                if (err.response.status === 422) {
+                    swal({
+                        title: 'Error',
+                        text: err.response?.data?.error,
+                        icon: "error",
+                        buttons: {
+                            review: {
+                                text: "Review blocked accounts",
+                                value: "review",
+                                className: "btn-primary"
+                            },
+                            cancel: true,
+                        }
+                    })
+                        .then((val) => {
+                            if (val && val == 'review') {
+                                location.href = '/settings/privacy/blocked-users';
+                                return;
+                            }
+                        });
                 } else {
-				    this.$emit('toggletab', tab);
+                    swal('Error', 'Something went wrong. Please try again later.', 'error');
                 }
-			},
+            });
+        },
+
+        cancelFollowRequest() {
+            if (!window.confirm('Are you sure you want to cancel your follow request?')) {
+                return;
+            }
+            event.currentTarget.blur();
+            this.$emit('unfollow');
+        }
+    }
 
-			getJoinedDate() {
-				return new Date(this.profile.created_at).toLocaleDateString(this.$i18n.locale, {
-                    year: 'numeric',
-                    month: 'long',
-                });
-			},
-
-			follow() {
-				event.currentTarget.blur();
-				this.$emit('follow');
-			},
-
-			unfollow() {
-				event.currentTarget.blur();
-				this.$emit('unfollow');
-			},
-
-			setBio() {
-				if(!this.profile.note.length) {
-					return;
-				}
-				if(this.profile.local) {
-					let content = this.profile.hasOwnProperty('note_text') ?
-						this.profile.note_text :
-						this.profile.note.replace(/(<([^>]+)>)/gi, "");
-					this.renderedBio = window.pftxt.autoLink(content, {
-						usernameUrlBase: '/i/web/profile/@',
-						hashtagUrlBase: '/i/web/hashtag/'
-					})
-				} else {
-					if(this.profile.note === '<p></p>') {
-						this.renderedBio = null;
-						return;
-					}
-					let content = this.profile.note;
-					let el = document.createElement('div');
-					el.innerHTML = content;
-					el.querySelectorAll('a[class*="hashtag"]')
-					.forEach(elr => {
-						let tag = elr.innerText;
-						if(tag.substr(0, 1) == '#') {
-							tag = tag.substr(1);
-						}
-						elr.removeAttribute('target');
-						elr.setAttribute('href', '/i/web/hashtag/' + tag);
-					})
-					el.querySelectorAll('a:not(.hashtag)[class*="mention"], a:not(.hashtag)[class*="list-slug"]')
-					.forEach(elr => {
-						let name = elr.innerText;
-						if(name.substr(0, 1) == '@') {
-							name = name.substr(1);
-						}
-						if(this.profile.local == false && !name.includes('@')) {
-							let domain = document.createElement('a');
-							domain.href = this.profile.url;
-							name = name + '@' + domain.hostname;
-						}
-						elr.removeAttribute('target');
-						elr.setAttribute('href', '/i/web/username/' + name);
-					})
-					this.renderedBio = el.outerHTML;
-				}
-			},
-
-			getAvatar() {
-				if(this.profile.id == this.user.id) {
-					return window._sharedData.user.avatar;
-				}
-
-				return this.profile.avatar;
-			},
-
-			copyTextToClipboard(val) {
-				App.util.clipboard(val);
-			},
-
-			goToOldProfile() {
-				if(this.profile.local) {
-					location.href = this.profile.url + '?fs=1';
-				} else {
-					location.href = '/i/web/profile/_/' + this.profile.id;
-				}
-			},
-
-			handleMute() {
-				let msg = this.relationship.muting ? 'unmuted' : 'muted';
-				let url = this.relationship.muting == true ? '/i/unmute' : '/i/mute';
-				axios.post(url, {
-					type: 'user',
-					item: this.profile.id
-				}).then(res => {
-					this.$emit('updateRelationship', res.data);
-					swal('Success', 'You have successfully '+ msg +' ' + this.profile.acct, 'success');
-				}).catch(err => {
-					if(err.response.status === 422) {
-						swal({
-							title: 'Error',
-							text: err.response?.data?.error,
-							icon: "error",
-							buttons: {
-								review: {
-									text: "Review muted accounts",
-									value: "review",
-									className: "btn-primary"
-								},
-								cancel: true,
-							}
-						})
-						.then((val) => {
-							if(val && val == 'review') {
-								location.href = '/settings/privacy/muted-users';
-								return;
-							}
-						});
-					} else {
-						swal('Error', 'Something went wrong. Please try again later.', 'error');
-					}
-				});
-			},
-
-			handleBlock() {
-				let msg = this.relationship.blocking ? 'unblock' : 'block';
-				let url = this.relationship.blocking == true ? '/i/unblock' : '/i/block';
-				axios.post(url, {
-					type: 'user',
-					item: this.profile.id
-				}).then(res => {
-					this.$emit('updateRelationship', res.data);
-					swal('Success', 'You have successfully '+ msg +'ed ' + this.profile.acct, 'success');
-				}).catch(err => {
-					if(err.response.status === 422) {
-						swal({
-							title: 'Error',
-							text: err.response?.data?.error,
-							icon: "error",
-							buttons: {
-								review: {
-									text: "Review blocked accounts",
-									value: "review",
-									className: "btn-primary"
-								},
-								cancel: true,
-							}
-						})
-						.then((val) => {
-							if(val && val == 'review') {
-								location.href = '/settings/privacy/blocked-users';
-								return;
-							}
-						});
-					} else {
-						swal('Error', 'Something went wrong. Please try again later.', 'error');
-					}
-				});
-			},
-
-			cancelFollowRequest() {
-				if(!window.confirm('Are you sure you want to cancel your follow request?')) {
-					return;
-				}
-				event.currentTarget.blur();
-				this.$emit('unfollow');
-			}
-		}
-	}
 </script>
 
 <style lang="scss">
-	.profile-sidebar-component {
-		margin-bottom: 1rem;
-
-		.avatar {
-			width: 140px;
-			margin-bottom: 1rem;
-			border-radius: 15px;
-		}
-
-		.display-name {
-			font-size: 20px;
-			margin-bottom: 0;
-			word-break: break-word;
-			font-size: 15px;
-			font-weight: 800 !important;
-			user-select: all;
-			line-height: 0.8;
-			font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
-		}
-
-		.username {
-			color: var(--primary);
-			font-size: 14px;
-			font-weight: 600;
-			font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
-
-			&.remote {
-				font-size: 11px;
-			}
-		}
-
-		.stats {
-			margin-bottom: 1rem;
-
-			.stat-item {
-				max-width: 33%;
-				flex: 0 0 33%;
-				text-align: center;
-				margin: 0;
-				padding: 0;
-				text-decoration: none;
-
-				strong {
-					display: block;
-					color: var(--body-color);
-					font-size: 18px;
-					line-height: 0.9;
-				}
-
-				span {
-					display: block;
-					font-size: 12px;
-					color: #B8C2CC;
-				}
-			}
-		}
-
-		.follow-btn {
-			@media (min-width: 768px) {
-				margin-bottom: 2rem;
-			}
-
-			&.btn-primary {
-				background-color: var(--primary);
-			}
-
-			&.btn-light {
-				border-color: var(--input-border);
-			}
-		}
-
-		.unfollow-btn {
-			@media (min-width: 768px) {
-				margin-bottom: 2rem;
-			}
-
-			background-color: rgba(59, 130, 246, 0.7);
-		}
-
-		.bio-wrapper {
-			margin-bottom: 1rem;
-
-			.bio-body {
-				display: block;
-				position: relative;
-				font-size: 12px !important;
-				white-space: pre-wrap;
-
-				.username {
-					font-size: 12px !important;
-				}
-
-				&.long {
-					max-height: 80px;
-					overflow: hidden;
-
-					&:after {
-						content: '';
-						width: 100%;
-						height: 100%;
-						position: absolute;
-						top: 0;
-						left: 0;
-						background: linear-gradient(180deg, transparent 0, rgba(255, 255, 255, .9) 60%, #fff 90%);
-						z-index: 2;
-					}
-				}
-
-				p {
-					margin-bottom: 0 !important;
-				}
-			}
-
-			.bio-more {
-				position: relative;
-				z-index: 3;
-			}
-		}
-
-		.admin-label {
-			padding: 1px 5px;
-			font-size: 12px;
-			color: #B91C1C;
-			background: #FEE2E2;
-			border: 1px solid #FCA5A5;
-			font-weight: 600;
-			text-transform: capitalize;
-			display: inline-block;
-			border-radius: 8px;
-		}
-
-		.sidebar-sitelinks {
-			margin-top: 1rem;
-			justify-content: space-between;
-			padding: 0;
-
-			a {
-				font-size: 12px;
-				color: #B8C2CC;
-			}
-
-			.active {
-				color: #212529;
-				font-weight: 600;
-			}
-		}
-
-		.sidebar-attribution {
-			margin-top: 0.5rem;
-			font-size: 12px;
-			color: #B8C2CC !important;
-
-			a {
-				color: #B8C2CC !important;
-			}
-		}
-
-		.user-card {
-			align-items: center;
-
-			.avatar {
-				width: 80px;
-				height: 80px;
-				border-radius: 15px;
-				margin-right: 0.8rem;
-				border: 1px solid #E5E7EB;
-
-				@media (min-width: 390px) {
-					width: 100px;
-					height: 100px;
-				}
-			}
-
-			.avatar-update-btn {
-				position: absolute;
-				right: 12px;
-				bottom: 0;
-				width: 20px;
-				height: 20px;
-				background: rgba(255,255,255,0.9);
-				border: 1px solid #dee2e6 !important;
-				padding: 0;
-				border-radius: 50rem;
-
-				&-icon {
-					font-family: 'Font Awesome 5 Free';
-					font-weight: 400;
-					-webkit-font-smoothing: antialiased;
-					display: inline-block;
-					font-style: normal;
-					font-variant: normal;
-					text-rendering: auto;
-					line-height: 1;
-
-					&:before {
-						content: "\F013";
-					}
-				}
-			}
-
-			.username {
-				font-weight: 600;
-				font-size: 13px;
-				margin: 4px 0;
-				word-break: break-word;
-				line-height: 12px;
-				user-select: all;
-
-				@media (min-width: 390px) {
-					margin: 8px 0;
-					font-size: 16px;
-				}
-			}
-
-			.display-name {
-				color: var(--body-color);
-				line-height: 0.8;
-				font-size: 20px;
-				font-weight: 800 !important;
-				word-break: break-word;
-				user-select: all;
-				font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
-				margin-bottom: 0;
-
-				@media (min-width: 390px) {
-					font-size: 24px;
-				}
-			}
-
-			.stats {
-				display: flex;
-				justify-content: space-between;
-				flex-direction: row;
-				margin-top: 0;
-				margin-bottom: 0;
-				font-size: 16px;
-				user-select: none;
-
-				.posts-count,
-				.following-count,
-				.followers-count {
-					display: flex;
-					font-weight: 800;
-				}
-
-				.stats-label {
-					color: #94a3b8;
-					font-size: 11px;
-					margin-top: -5px;
-				}
-			}
-		}
-	}
+.profile-sidebar-component {
+    margin-bottom: 1rem;
+
+    .avatar {
+        width: 140px;
+        margin-bottom: 1rem;
+        border-radius: 15px;
+    }
+
+    .display-name {
+        font-size: 20px;
+        margin-bottom: 0;
+        word-break: break-word;
+        font-size: 15px;
+        font-weight: 800 !important;
+        user-select: all;
+        line-height: 0.8;
+        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+    }
+
+    .username {
+        color: var(--primary);
+        font-size: 14px;
+        font-weight: 600;
+        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+
+        &.remote {
+            font-size: 11px;
+        }
+    }
+
+    .stats {
+        margin-bottom: 1rem;
+
+        .stat-item {
+            max-width: 33%;
+            flex: 0 0 33%;
+            text-align: center;
+            margin: 0;
+            padding: 0;
+            text-decoration: none;
+
+            strong {
+                display: block;
+                color: var(--body-color);
+                font-size: 18px;
+                line-height: 0.9;
+            }
+
+            span {
+                display: block;
+                font-size: 12px;
+                color: #B8C2CC;
+            }
+        }
+    }
+
+    .follow-btn {
+        @media (min-width: 768px) {
+            margin-bottom: 2rem;
+        }
+
+        &.btn-primary {
+            background-color: var(--primary);
+        }
+
+        &.btn-light {
+            border-color: var(--input-border);
+        }
+    }
+
+    .unfollow-btn {
+        @media (min-width: 768px) {
+            margin-bottom: 2rem;
+        }
+
+        background-color: rgba(59, 130, 246, 0.7);
+    }
+
+    .bio-wrapper {
+        margin-bottom: 1rem;
+
+        .bio-body {
+            display: block;
+            position: relative;
+            font-size: 12px !important;
+            white-space: pre-wrap;
+
+            .username {
+                font-size: 12px !important;
+            }
+
+            &.long {
+                max-height: 80px;
+                overflow: hidden;
+
+                &:after {
+                    content: '';
+                    width: 100%;
+                    height: 100%;
+                    position: absolute;
+                    top: 0;
+                    left: 0;
+                    background: linear-gradient(180deg, transparent 0, rgba(255, 255, 255, .9) 60%, #fff 90%);
+                    z-index: 2;
+                }
+            }
+
+            p {
+                margin-bottom: 0 !important;
+            }
+        }
+
+        .bio-more {
+            position: relative;
+            z-index: 3;
+        }
+    }
+
+    .admin-label {
+        padding: 1px 5px;
+        font-size: 12px;
+        color: #B91C1C;
+        background: #FEE2E2;
+        border: 1px solid #FCA5A5;
+        font-weight: 600;
+        text-transform: capitalize;
+        display: inline-block;
+        border-radius: 8px;
+    }
+
+    .sidebar-sitelinks {
+        margin-top: 1rem;
+        justify-content: space-between;
+        padding: 0;
+
+        a {
+            font-size: 12px;
+            color: #B8C2CC;
+        }
+
+        .active {
+            color: #212529;
+            font-weight: 600;
+        }
+    }
+
+    .sidebar-attribution {
+        margin-top: 0.5rem;
+        font-size: 12px;
+        color: #B8C2CC !important;
+
+        a {
+            color: #B8C2CC !important;
+        }
+    }
+
+    .user-card {
+        align-items: center;
+
+        .avatar {
+            width: 80px;
+            height: 80px;
+            border-radius: 15px;
+            margin-right: 0.8rem;
+            border: 1px solid #E5E7EB;
+
+            @media (min-width: 390px) {
+                width: 100px;
+                height: 100px;
+            }
+        }
+
+        .avatar-update-btn {
+            position: absolute;
+            right: 12px;
+            bottom: 0;
+            width: 20px;
+            height: 20px;
+            background: rgba(255, 255, 255, 0.9);
+            border: 1px solid #dee2e6 !important;
+            padding: 0;
+            border-radius: 50rem;
+
+            &-icon {
+                font-family: 'Font Awesome 5 Free';
+                font-weight: 400;
+                -webkit-font-smoothing: antialiased;
+                display: inline-block;
+                font-style: normal;
+                font-variant: normal;
+                text-rendering: auto;
+                line-height: 1;
+
+                &:before {
+                    content: "\F013";
+                }
+            }
+        }
+
+        .username {
+            font-weight: 600;
+            font-size: 13px;
+            margin: 4px 0;
+            word-break: break-word;
+            line-height: 12px;
+            user-select: all;
+
+            @media (min-width: 390px) {
+                margin: 8px 0;
+                font-size: 16px;
+            }
+        }
+
+        .display-name {
+            color: var(--body-color);
+            line-height: 0.8;
+            font-size: 20px;
+            font-weight: 800 !important;
+            word-break: break-word;
+            user-select: all;
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+            margin-bottom: 0;
+
+            @media (min-width: 390px) {
+                font-size: 24px;
+            }
+        }
+
+        .stats {
+            display: flex;
+            justify-content: space-between;
+            flex-direction: row;
+            margin-top: 0;
+            margin-bottom: 0;
+            font-size: 16px;
+            user-select: none;
+
+            .posts-count,
+            .following-count,
+            .followers-count {
+                display: flex;
+                font-weight: 800;
+            }
+
+            .stats-label {
+                color: #94a3b8;
+                font-size: 11px;
+                margin-top: -5px;
+            }
+        }
+    }
+}
 </style>

+ 638 - 631
resources/assets/components/partials/sidebar.vue

@@ -1,62 +1,65 @@
 <template>
-	<div class="sidebar-component sticky-top d-none d-md-block">
-		<!-- <input type="file" class="d-none" ref="avatarUpdateRef" @change="handleAvatarUpdate()"> -->
-		<!-- <div class="card shadow-sm mb-3 cursor-pointer" style="border-radius: 15px;" @click="gotoMyProfile()"> -->
-		<div class="card shadow-sm mb-3" style="border-radius: 15px;">
-			<div class="card-body p-2">
-				<div class="media user-card user-select-none">
-					<div style="position: relative;">
-						<img :src="user.avatar" class="avatar shadow cursor-pointer" draggable="false" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';" @click="gotoMyProfile()">
-						<button class="btn btn-light btn-sm avatar-update-btn" @click="updateAvatar()">
-							<span class="avatar-update-btn-icon"></span>
-						</button>
-					</div>
-					<div class="media-body">
-						<p class="display-name" v-html="getDisplayName()"></p>
-						<p class="username primary">&commat;{{ user.username }}</p>
-						<p class="stats">
+    <div class="sidebar-component sticky-top d-none d-md-block">
+        <!-- <input type="file" class="d-none" ref="avatarUpdateRef" @change="handleAvatarUpdate()"> -->
+        <!-- <div class="card shadow-sm mb-3 cursor-pointer" style="border-radius: 15px;" @click="gotoMyProfile()"> -->
+        <div class="card shadow-sm mb-3" style="border-radius: 15px;">
+            <div class="card-body p-2">
+                <div class="media user-card user-select-none">
+                    <div style="position: relative;">
+                        <img :src="user.avatar" class="avatar shadow cursor-pointer" draggable="false"
+                             onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';"
+                             @click="gotoMyProfile()">
+                        <button class="btn btn-light btn-sm avatar-update-btn" @click="updateAvatar()">
+                            <span class="avatar-update-btn-icon"></span>
+                        </button>
+                    </div>
+                    <div class="media-body">
+                        <p class="display-name" v-html="getDisplayName()"></p>
+                        <p class="username primary">&commat;{{ user.username }}</p>
+                        <p class="stats">
 							<span class="stats-following">
 								<span class="following-count">{{ formatCount(user.following_count) }}</span> Following
 							</span>
-							<span class="stats-followers">
+                            <span class="stats-followers">
 								<span class="followers-count">{{ formatCount(user.followers_count) }}</span> Followers
 							</span>
-						</p>
-					</div>
-				</div>
-			</div>
-		</div>
-
-		<div class="btn-group btn-group-lg btn-block mb-4">
-			<!-- <button type="button" class="btn btn-outline-primary btn-block font-weight-bold" style="border-top-left-radius: 18px;border-bottom-left-radius:18px;font-size:18px;font-weight:300!important" @click="createNewPost()">
-				<i class="fal fa-arrow-circle-up mr-1"></i> {{ $t('navmenu.compose') }} Post
-			</button> -->
-			<router-link to="/i/web/compose" class="btn btn-primary btn-block font-weight-bold">
-				<i class="fal fa-arrow-circle-up mr-1"></i> {{ $t('navmenu.compose') }} Post
-			</router-link>
-			<button type="button" class="btn btn-outline-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-expanded="false">
-				<span class="sr-only">Toggle Dropdown</span>
-			</button>
-			<div class="dropdown-menu dropdown-menu-right">
-				<a class="dropdown-item font-weight-bold" href="/i/collections/create">Create Collection</a>
-				<a v-if="hasStories" class="dropdown-item font-weight-bold" href="/i/stories/new">Create Story</a>
-				<div class="dropdown-divider"></div>
-				<a class="dropdown-item font-weight-bold" href="/settings/home">Account Settings</a>
-			</div>
-		</div>
-
-		<!-- <router-link to="/i/web/compose" class="btn btn-primary btn-lg btn-block mb-4 shadow-sm font-weight-bold">
-			<i class="far fa-plus-square mr-1"></i> {{ $t('navmenu.compose') }}
-		</router-link> -->
-
-		<div class="sidebar-sticky shadow-sm">
-			<ul class="nav flex-column">
-				<li class="nav-item">
-					<div class="d-flex justify-content-between align-items-center">
-						<!-- <router-link class="nav-link text-center" to="/i/web">
-							<div class="icon text-lighter"><i class="far fa-home fa-lg"></i></div>
-							<div class="small">{{ $t('navmenu.homeFeed') }}</div>
-						</router-link> -->
+                        </p>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="btn-group btn-group-lg btn-block mb-4">
+            <!-- <button type="button" class="btn btn-outline-primary btn-block font-weight-bold" style="border-top-left-radius: 18px;border-bottom-left-radius:18px;font-size:18px;font-weight:300!important" @click="createNewPost()">
+                <i class="fal fa-arrow-circle-up mr-1"></i> {{ $t('navmenu.compose') }} Post
+            </button> -->
+            <router-link to="/i/web/compose" class="btn btn-primary btn-block font-weight-bold">
+                <i class="fal fa-arrow-circle-up mr-1"></i> {{ $t('navmenu.compose') }} Post
+            </router-link>
+            <button type="button" class="btn btn-outline-primary dropdown-toggle dropdown-toggle-split"
+                    data-toggle="dropdown" aria-expanded="false">
+                <span class="sr-only">Toggle Dropdown</span>
+            </button>
+            <div class="dropdown-menu dropdown-menu-right">
+                <a class="dropdown-item font-weight-bold" href="/i/collections/create">Create Collection</a>
+                <a v-if="hasStories" class="dropdown-item font-weight-bold" href="/i/stories/new">Create Story</a>
+                <div class="dropdown-divider"></div>
+                <a class="dropdown-item font-weight-bold" href="/settings/home">Account Settings</a>
+            </div>
+        </div>
+
+        <!-- <router-link to="/i/web/compose" class="btn btn-primary btn-lg btn-block mb-4 shadow-sm font-weight-bold">
+            <i class="far fa-plus-square mr-1"></i> {{ $t('navmenu.compose') }}
+        </router-link> -->
+
+        <div class="sidebar-sticky shadow-sm">
+            <ul class="nav flex-column">
+                <li class="nav-item">
+                    <div class="d-flex justify-content-between align-items-center">
+                        <!-- <router-link class="nav-link text-center" to="/i/web">
+                            <div class="icon text-lighter"><i class="far fa-home fa-lg"></i></div>
+                            <div class="small">{{ $t('navmenu.homeFeed') }}</div>
+                        </router-link> -->
                         <a
                             class="nav-link text-center"
                             href="/i/web"
@@ -66,10 +69,10 @@
                             <div class="small">{{ $t('navmenu.homeFeed') }}</div>
                         </a>
 
-						<!-- <router-link v-if="hasLocalTimeline" class="nav-link text-center" :to="{ name: 'timeline', params: { scope: 'local' } }">
-							<div class="icon text-lighter"><i class="fas fa-stream fa-lg"></i></div>
-							<div class="small">{{ $t('navmenu.localFeed') }}</div>
-						</router-link> -->
+                        <!-- <router-link v-if="hasLocalTimeline" class="nav-link text-center" :to="{ name: 'timeline', params: { scope: 'local' } }">
+                            <div class="icon text-lighter"><i class="fas fa-stream fa-lg"></i></div>
+                            <div class="small">{{ $t('navmenu.localFeed') }}</div>
+                        </router-link> -->
                         <a
                             v-if="hasLocalTimeline"
                             class="nav-link text-center"
@@ -80,10 +83,10 @@
                             <div class="small">{{ $t('navmenu.localFeed') }}</div>
                         </a>
 
-						<!-- <router-link v-if="hasNetworkTimeline" class="nav-link text-center" :to="{ name: 'timeline', params: { scope: 'global' } }">
-							<div class="icon text-lighter"><i class="far fa-globe fa-lg"></i></div>
-							<div class="small">{{ $t('navmenu.globalFeed') }}</div>
-						</router-link> -->
+                        <!-- <router-link v-if="hasNetworkTimeline" class="nav-link text-center" :to="{ name: 'timeline', params: { scope: 'global' } }">
+                            <div class="icon text-lighter"><i class="far fa-globe fa-lg"></i></div>
+                            <div class="small">{{ $t('navmenu.globalFeed') }}</div>
+                        </router-link> -->
                         <a
                             v-if="hasNetworkTimeline"
                             class="nav-link text-center"
@@ -93,34 +96,34 @@
                             <div class="icon text-lighter"><i class="far fa-globe fa-lg"></i></div>
                             <div class="small">{{ $t('navmenu.globalFeed') }}</div>
                         </a>
-					</div>
-					<hr class="mb-0" style="margin-top: -5px;opacity: 0.4;" />
-				</li>
+                    </div>
+                    <hr class="mb-0" style="margin-top: -5px;opacity: 0.4;"/>
+                </li>
 
-				<!-- <li class="nav-item">
-				</li>
+                <!-- <li class="nav-item">
+                </li>
 
-				<li class="nav-item">
+                <li class="nav-item">
 
-				</li> -->
+                </li> -->
 
 
-				<!-- <li v-for="(link, index) in links" class="nav-item">
-					<router-link class="nav-link" :to="link.path">
-						<span v-if="link.icon" class="icon text-lighter"><i :class="[ link.icon ]"></i></span>
-						{{ link.name }}
-					</router-link>
-				</li> -->
+                <!-- <li v-for="(link, index) in links" class="nav-item">
+                    <router-link class="nav-link" :to="link.path">
+                        <span v-if="link.icon" class="icon text-lighter"><i :class="[ link.icon ]"></i></span>
+                        {{ link.name }}
+                    </router-link>
+                </li> -->
 
-				<li class="nav-item">
-					<router-link class="nav-link" to="/i/web/discover">
-						<span class="icon text-lighter"><i class="far fa-compass"></i></span>
-						{{ $t('navmenu.discover') }}
-					</router-link>
-				</li>
+                <li class="nav-item">
+                    <router-link class="nav-link" to="/i/web/discover">
+                        <span class="icon text-lighter"><i class="far fa-compass"></i></span>
+                        {{ $t('navmenu.discover') }}
+                    </router-link>
+                </li>
 
-				<li class="nav-item">
-					<router-link class="nav-link d-flex justify-content-between align-items-center" to="/i/web/direct">
+                <li class="nav-item">
+                    <router-link class="nav-link d-flex justify-content-between align-items-center" to="/i/web/direct">
 						<span>
 							<span class="icon text-lighter">
 								<i class="far fa-envelope"></i>
@@ -128,30 +131,32 @@
 							{{ $t('navmenu.directMessages') }}
 						</span>
 
-						<!-- <span class="badge badge-danger font-weight-light rounded-pill px-2" style="transform:scale(0.86)">99+</span> -->
-					</router-link>
-				</li>
+                        <!-- <span class="badge badge-danger font-weight-light rounded-pill px-2" style="transform:scale(0.86)">99+</span> -->
+                    </router-link>
+                </li>
 
-				<li v-if="hasGroups" class="nav-item">
-					<router-link class="nav-link" to="/groups/feed">
-						<span class="icon text-lighter"><i class="far fa-layer-group"></i></span>
-						{{ $t('navmenu.groups') }}
-					</router-link>
-				</li>
+                <li v-if="hasGroups" class="nav-item">
+                    <router-link class="nav-link" to="/groups/feed">
+                        <span class="icon text-lighter"><i class="far fa-layer-group"></i></span>
+                        {{ $t('navmenu.groups') }}
+                    </router-link>
+                </li>
 
-				<li v-if="hasLiveStreams" class="nav-item">
-					<router-link class="nav-link d-flex justify-content-between align-items-center" to="/i/web/livestreams">
+                <li v-if="hasLiveStreams" class="nav-item">
+                    <router-link class="nav-link d-flex justify-content-between align-items-center"
+                                 to="/i/web/livestreams">
 						<span>
 							<span class="icon text-lighter">
 								<i class="far fa-record-vinyl"></i>
 							</span>
 							Livestreams
 						</span>
-					</router-link>
-				</li>
+                    </router-link>
+                </li>
 
-				<li class="nav-item">
-					<router-link class="nav-link d-flex justify-content-between align-items-center" to="/i/web/notifications">
+                <li class="nav-item">
+                    <router-link class="nav-link d-flex justify-content-between align-items-center"
+                                 to="/i/web/notifications">
 						<span>
 							<span class="icon text-lighter">
 								<i class="far fa-bell"></i>
@@ -159,563 +164,565 @@
 							{{ $t('navmenu.notifications') }}
 						</span>
 
-						<!-- <span class="badge badge-danger font-weight-light rounded-pill px-2" style="transform:scale(0.86)">99+</span> -->
-					</router-link>
-				</li>
+                        <!-- <span class="badge badge-danger font-weight-light rounded-pill px-2" style="transform:scale(0.86)">99+</span> -->
+                    </router-link>
+                </li>
 
-				<li class="nav-item">
-					<hr class="mt-n1" style="opacity: 0.4;margin-bottom: 0;" />
+                <li class="nav-item">
+                    <hr class="mt-n1" style="opacity: 0.4;margin-bottom: 0;"/>
 
-					<router-link class="nav-link" :to="'/i/web/profile/' + user.id">
+                    <router-link class="nav-link" :to="'/i/web/profile/' + user.id">
 						<span class="icon text-lighter">
 							<i class="far fa-user"></i>
 						</span>
-						{{ $t('navmenu.profile') }}
-					</router-link>
-
-					<!-- <router-link class="nav-link" to="/i/web/settings">
-						<span class="icon text-lighter">
-							<i class="far fa-cog"></i>
-						</span>
-						{{ $t('navmenu.settings') }}
-					</router-link> -->
-				</li>
-				<!-- <li class="nav-item">
-					<router-link class="nav-link" to="/i/web/drive">
-						<span class="icon text-lighter">
-							<i class="far fa-cloud-upload"></i>
-						</span>
-						{{ $t('navmenu.drive') }}
-					</router-link>
-				</li> -->
-				<!-- <li class="nav-item">
-					<router-link class="nav-link" to="/i/web/settings">
-						<span class="icon text-lighter">
-							<i class="fas fa-cog"></i>
-						</span>
-						{{ $t('navmenu.settings') }}
-					</router-link>
-				</li>
-				<li class="nav-item">
-					<a class="nav-link" href="/i/web/help">
-						<span class="icon text-lighter">
-							<i class="fas fa-info-circle"></i>
-						</span>
-						Help
-					</a>
-				</li> -->
-				<li v-if="user.is_admin" class="nav-item">
-					<hr class="mt-n1" style="opacity: 0.4;margin-bottom: 0;" />
-					<a class="nav-link" href="/i/admin/dashboard">
+                        {{ $t('navmenu.profile') }}
+                    </router-link>
+
+                    <!-- <router-link class="nav-link" to="/i/web/settings">
+                        <span class="icon text-lighter">
+                            <i class="far fa-cog"></i>
+                        </span>
+                        {{ $t('navmenu.settings') }}
+                    </router-link> -->
+                </li>
+                <!-- <li class="nav-item">
+                    <router-link class="nav-link" to="/i/web/drive">
+                        <span class="icon text-lighter">
+                            <i class="far fa-cloud-upload"></i>
+                        </span>
+                        {{ $t('navmenu.drive') }}
+                    </router-link>
+                </li> -->
+                <!-- <li class="nav-item">
+                    <router-link class="nav-link" to="/i/web/settings">
+                        <span class="icon text-lighter">
+                            <i class="fas fa-cog"></i>
+                        </span>
+                        {{ $t('navmenu.settings') }}
+                    </router-link>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" href="/i/web/help">
+                        <span class="icon text-lighter">
+                            <i class="fas fa-info-circle"></i>
+                        </span>
+                        Help
+                    </a>
+                </li> -->
+                <li v-if="user.is_admin" class="nav-item">
+                    <hr class="mt-n1" style="opacity: 0.4;margin-bottom: 0;"/>
+                    <a class="nav-link" href="/i/admin/dashboard">
 						<span class="icon text-lighter">
 							<i class="far fa-tools"></i>
 						</span>
-						{{ $t('navmenu.admin') }}
-					</a>
-				</li>
+                        {{ $t('navmenu.admin') }}
+                    </a>
+                </li>
 
-				<li class="nav-item">
-					<hr class="mt-n1" style="opacity: 0.4;margin-bottom: 0;" />
-					<a class="nav-link" href="/?force_old_ui=1">
+                <li class="nav-item">
+                    <hr class="mt-n1" style="opacity: 0.4;margin-bottom: 0;"/>
+                    <a class="nav-link" href="/?force_old_ui=1">
 						<span class="icon text-lighter">
 							<i class="fas fa-chevron-left"></i>
 						</span>
-						{{ $t('navmenu.backToPreviousDesign') }}
-					</a>
-				</li>
-				<!-- <li class="nav-item">
-					<router-link class="nav-link" to="/i/web/?a=feed">
-						<span class="fas fa-stream pr-2 text-lighter"></span>
-						Feed
-					</router-link>
-				</li>
-				<li class="nav-item">
-					<router-link class="nav-link" to="/i/web/discover">
-						<span class="fas fa-compass pr-2 text-lighter"></span>
-						Discover
-					</router-link>
-				</li>
-				<li class="nav-item">
-					<router-link class="nav-link" to="/i/web/stories">
-						<span class="fas fa-history pr-2 text-lighter"></span>
-						Stories
-					</router-link>
-				</li> -->
-			</ul>
-		</div>
-
-		<!-- <div class="sidebar-sitelinks">
-			<a href="/site/about">{{ $t('navmenu.about') }}</a>
-			<a href="/site/language">{{ $t('navmenu.language') }}</a>
-			<a href="/site/terms">{{ $t('navmenu.privacy') }}</a>
-			<a href="/site/terms">{{ $t('navmenu.terms') }}</a>
-		</div> -->
-
-		<div class="sidebar-attribution pr-3 d-flex justify-content-between align-items-center">
-			<router-link to="/i/web/language">
-				<i class="fal fa-language fa-2x" alt="Select a language"></i>
-			</router-link>
-			<a href="/site/help" class="font-weight-bold">{{ $t('navmenu.help') }}</a>
-			<a href="/site/privacy" class="font-weight-bold">{{ $t('navmenu.privacy') }}</a>
-			<a href="/site/terms" class="font-weight-bold">{{ $t('navmenu.terms') }}</a>
-			<a href="https://pixelfed.org" class="font-weight-bold powered-by">Powered by Pixelfed</a>
-		</div>
-
-		<!-- <b-modal
-			ref="avatarUpdateModal"
-			centered
-			hide-footer
-			header-class="py-2"
-			body-class="p-0"
-			title-class="w-100 text-center pl-4 font-weight-bold"
-			title-tag="p"
-			title="Upload Avatar"
-		>
-		<div class="d-flex align-items-center justify-content-center">
-			<div
-				v-if="avatarUpdateIndex === 0"
-				class="py-5 user-select-none cursor-pointer"
-				@click="avatarUpdateStep(0)">
-				<p class="text-center primary">
-					<i class="fal fa-cloud-upload fa-3x"></i>
-				</p>
-				<p class="text-center lead">Drag photo here or click here</p>
-				<p class="text-center small text-muted mb-0">Must be a <strong>png</strong> or <strong>jpg</strong> image up to 2MB</p>
-			</div>
-
-			<div v-else-if="avatarUpdateIndex === 1" class="w-100 p-5">
-
-				<div class="d-md-flex justify-content-between align-items-center">
-					<div class="text-center mb-4">
-						<p class="small font-weight-bold" style="opacity:0.7;">Current</p>
-						<img :src="user.avatar" class="shadow" style="width: 150px;height: 150px;object-fit: cover;border-radius: 18px;opacity: 0.7;">
-					</div>
-
-					<div class="text-center mb-4">
-						<p class="font-weight-bold">New</p>
-						<img :src="avatarUpdateFile" class="shadow" style="width: 220px;height: 220px;object-fit: cover;border-radius: 18px;">
-					</div>
-				</div>
-
-				<hr>
-
-				<div class="d-flex justify-content-between">
-					<button class="btn btn-light font-weight-bold btn-block mr-3" @click="avatarUpdateClose()">Cancel</button>
-					<button class="btn btn-primary primary font-weight-bold btn-block mt-0">Upload</button>
-				</div>
-			</div>
-		</div>
-		</b-modal> -->
-
-		<!-- <b-modal
-			ref="createPostModal"
-			centered
-			hide-footer
-			header-class="py-2"
-			body-class="p-0 w-100 h-100"
-			title-class="w-100 text-center pl-4 font-weight-bold"
-			title-tag="p"
-			title="Create New Post"
-			>
-			<compose-simple />
-		</b-modal> -->
-
-		<update-avatar ref="avatarUpdate" :user="user" />
-	</div>
+                        {{ $t('navmenu.backToPreviousDesign') }}
+                    </a>
+                </li>
+                <!-- <li class="nav-item">
+                    <router-link class="nav-link" to="/i/web/?a=feed">
+                        <span class="fas fa-stream pr-2 text-lighter"></span>
+                        Feed
+                    </router-link>
+                </li>
+                <li class="nav-item">
+                    <router-link class="nav-link" to="/i/web/discover">
+                        <span class="fas fa-compass pr-2 text-lighter"></span>
+                        Discover
+                    </router-link>
+                </li>
+                <li class="nav-item">
+                    <router-link class="nav-link" to="/i/web/stories">
+                        <span class="fas fa-history pr-2 text-lighter"></span>
+                        Stories
+                    </router-link>
+                </li> -->
+            </ul>
+        </div>
+
+        <!-- <div class="sidebar-sitelinks">
+            <a href="/site/about">{{ $t('navmenu.about') }}</a>
+            <a href="/site/language">{{ $t('navmenu.language') }}</a>
+            <a href="/site/terms">{{ $t('navmenu.privacy') }}</a>
+            <a href="/site/terms">{{ $t('navmenu.terms') }}</a>
+        </div> -->
+
+        <div class="sidebar-attribution pr-3 d-flex flex-wrap justify-content-between align-items-center">
+            <router-link to="/i/web/language">
+                <i class="fal fa-language fa-2x" alt="Select a language"></i>
+            </router-link>
+            <a href="/site/help" class="font-weight-bold">{{ $t('navmenu.help') }}</a>
+            <a href="/site/privacy" class="font-weight-bold">{{ $t('navmenu.privacy') }}</a>
+            <a href="/site/terms" class="font-weight-bold">{{ $t('navmenu.terms') }}</a>
+            <a v-if="showLegalNoticeLink" href="/site/legal-notice" class="font-weight-bold">{{ $t('navmenu.legalNotice') }}</a>
+            <a href="https://pixelfed.org" class="font-weight-bold powered-by">Powered by Pixelfed</a>
+        </div>
+
+        <!-- <b-modal
+            ref="avatarUpdateModal"
+            centered
+            hide-footer
+            header-class="py-2"
+            body-class="p-0"
+            title-class="w-100 text-center pl-4 font-weight-bold"
+            title-tag="p"
+            title="Upload Avatar"
+        >
+        <div class="d-flex align-items-center justify-content-center">
+            <div
+                v-if="avatarUpdateIndex === 0"
+                class="py-5 user-select-none cursor-pointer"
+                @click="avatarUpdateStep(0)">
+                <p class="text-center primary">
+                    <i class="fal fa-cloud-upload fa-3x"></i>
+                </p>
+                <p class="text-center lead">Drag photo here or click here</p>
+                <p class="text-center small text-muted mb-0">Must be a <strong>png</strong> or <strong>jpg</strong> image up to 2MB</p>
+            </div>
+
+            <div v-else-if="avatarUpdateIndex === 1" class="w-100 p-5">
+
+                <div class="d-md-flex justify-content-between align-items-center">
+                    <div class="text-center mb-4">
+                        <p class="small font-weight-bold" style="opacity:0.7;">Current</p>
+                        <img :src="user.avatar" class="shadow" style="width: 150px;height: 150px;object-fit: cover;border-radius: 18px;opacity: 0.7;">
+                    </div>
+
+                    <div class="text-center mb-4">
+                        <p class="font-weight-bold">New</p>
+                        <img :src="avatarUpdateFile" class="shadow" style="width: 220px;height: 220px;object-fit: cover;border-radius: 18px;">
+                    </div>
+                </div>
+
+                <hr>
+
+                <div class="d-flex justify-content-between">
+                    <button class="btn btn-light font-weight-bold btn-block mr-3" @click="avatarUpdateClose()">Cancel</button>
+                    <button class="btn btn-primary primary font-weight-bold btn-block mt-0">Upload</button>
+                </div>
+            </div>
+        </div>
+        </b-modal> -->
+
+        <!-- <b-modal
+            ref="createPostModal"
+            centered
+            hide-footer
+            header-class="py-2"
+            body-class="p-0 w-100 h-100"
+            title-class="w-100 text-center pl-4 font-weight-bold"
+            title-tag="p"
+            title="Create New Post"
+            >
+            <compose-simple />
+        </b-modal> -->
+
+        <update-avatar ref="avatarUpdate" :user="user"/>
+    </div>
 </template>
 
 <script type="text/javascript">
-	import { mapGetters } from 'vuex'
-	// import ComposeSimple from './../sections/ComposeSimple.vue';
-	import UpdateAvatar from './modal/UpdateAvatar.vue';
-
-	export default {
-		props: {
-			user: {
-				type: Object,
-				default: (function() {
-					return {
-						avatar: '/storage/avatars/default.jpg',
-						username: false,
-						display_name: '',
-						following_count: 0,
-						followers_count: 0
-					};
-				})
-			},
-
-			links: {
-				type: Array,
-				default: function() {
-					return [
-						// {
-						// 	name: "Home",
-						// 	path: "/i/web",
-						// 	icon: "fas fa-home"
-						// },
-						// {
-						// 	name: "Local",
-						// 	path: "/i/web/timeline/local",
-						// 	icon: "fas fa-stream"
-						// },
-						// {
-						// 	name: "Global",
-						// 	path: "/i/web/timeline/global",
-						// 	icon: "far fa-globe"
-						// },
-						// {
-						// 	name: "Audiences",
-						// 	path: "/i/web/discover",
-						// 	icon: "far fa-circle-notch"
-						// },
-						{
-							name: "Discover",
-							path: "/i/web/discover",
-							icon: "fas fa-compass"
-						},
-						// {
-						// 	name: "Events",
-						// 	path: "/i/events",
-						// 	icon: "far fa-calendar-alt"
-						// },
-						{
-							name: "Groups",
-							path: "/i/web/groups",
-							icon: "far fa-user-friends"
-						},
-						// {
-						// 	name: "Live",
-						// 	path: "/i/web/?t=live",
-						// 	icon: "far fa-play"
-						// },
-						// {
-						// 	name: "Marketplace",
-						// 	path: "/i/web/marketplace",
-						// 	icon: "far fa-shopping-cart"
-						// },
-						// {
-						// 	name: "Stories",
-						// 	path: "/i/web/?t=stories",
-						// 	icon: "fas fa-history"
-						// },
-						{
-							name: "Videos",
-							path: "/i/web/videos",
-							icon: "far fa-video"
-						}
-					];
-				}
-			}
-		},
-
-		components: {
-			// ComposeSimple,
-			UpdateAvatar
-		},
-
-		computed: {
-			...mapGetters([
-				'getCustomEmoji'
-			])
-		},
-
-		data() {
-			return {
-				loaded: false,
-				hasLocalTimeline: true,
-				hasNetworkTimeline: false,
-				hasLiveStreams: false,
-                hasStories: false,
-                hasGroups: false,
-			}
-		},
-
-		mounted() {
-			if(window.App.config.features.hasOwnProperty('timelines')) {
-				this.hasLocalTimeline = App.config.features.timelines.local;
-                this.hasNetworkTimeline = App.config.features.timelines.network;
-				this.hasGroups = App.config.features.groups;
-				//this.hasLiveStreams = App.config.ab.hls == true;
-			}
-            if(window.App.config.features.hasOwnProperty('stories')) {
-                this.hasStories = App.config.features.stories;
+import {mapGetters} from 'vuex'
+// import ComposeSimple from './../sections/ComposeSimple.vue';
+import UpdateAvatar from './modal/UpdateAvatar.vue';
+
+export default {
+    props: {
+        user: {
+            type: Object,
+            default: (function () {
+                return {
+                    avatar: '/storage/avatars/default.jpg',
+                    username: false,
+                    display_name: '',
+                    following_count: 0,
+                    followers_count: 0
+                };
+            })
+        },
+
+        links: {
+            type: Array,
+            default: function () {
+                return [
+                    // {
+                    // 	name: "Home",
+                    // 	path: "/i/web",
+                    // 	icon: "fas fa-home"
+                    // },
+                    // {
+                    // 	name: "Local",
+                    // 	path: "/i/web/timeline/local",
+                    // 	icon: "fas fa-stream"
+                    // },
+                    // {
+                    // 	name: "Global",
+                    // 	path: "/i/web/timeline/global",
+                    // 	icon: "far fa-globe"
+                    // },
+                    // {
+                    // 	name: "Audiences",
+                    // 	path: "/i/web/discover",
+                    // 	icon: "far fa-circle-notch"
+                    // },
+                    {
+                        name: "Discover",
+                        path: "/i/web/discover",
+                        icon: "fas fa-compass"
+                    },
+                    // {
+                    // 	name: "Events",
+                    // 	path: "/i/events",
+                    // 	icon: "far fa-calendar-alt"
+                    // },
+                    {
+                        name: "Groups",
+                        path: "/i/web/groups",
+                        icon: "far fa-user-friends"
+                    },
+                    // {
+                    // 	name: "Live",
+                    // 	path: "/i/web/?t=live",
+                    // 	icon: "far fa-play"
+                    // },
+                    // {
+                    // 	name: "Marketplace",
+                    // 	path: "/i/web/marketplace",
+                    // 	icon: "far fa-shopping-cart"
+                    // },
+                    // {
+                    // 	name: "Stories",
+                    // 	path: "/i/web/?t=stories",
+                    // 	icon: "fas fa-history"
+                    // },
+                    {
+                        name: "Videos",
+                        path: "/i/web/videos",
+                        icon: "far fa-video"
+                    }
+                ];
+            }
+        }
+    },
+
+    components: {
+        // ComposeSimple,
+        UpdateAvatar
+    },
+
+    computed: {
+        ...mapGetters([
+            'getCustomEmoji'
+        ])
+    },
+
+    data() {
+        return {
+            loaded: false,
+            hasLocalTimeline: true,
+            hasNetworkTimeline: false,
+            hasLiveStreams: false,
+            hasStories: false,
+            hasGroups: false,
+            showLegalNoticeLink: window.App.config.show_legal_notice_link,
+        }
+    },
+
+    mounted() {
+        if (window.App.config.features.hasOwnProperty('timelines')) {
+            this.hasLocalTimeline = App.config.features.timelines.local;
+            this.hasNetworkTimeline = App.config.features.timelines.network;
+            this.hasGroups = App.config.features.groups;
+            //this.hasLiveStreams = App.config.ab.hls == true;
+        }
+        if (window.App.config.features.hasOwnProperty('stories')) {
+            this.hasStories = App.config.features.stories;
+        }
+    },
+
+    methods: {
+        getDisplayName() {
+            let self = this;
+            let profile = this.user;
+            let dn = profile.display_name;
+            if (!dn) {
+                return profile.username;
+            }
+            if (dn.includes(':')) {
+                let re = /(<a?)?:\w+:(\d{18}>)?/g;
+                let un = dn.replaceAll(re, function (em) {
+                    let shortcode = em.slice(1, em.length - 1);
+                    let emoji = self.getCustomEmoji.filter(e => {
+                        return e.shortcode == shortcode;
+                    });
+                    return emoji.length ? `<img draggable="false" class="emojione custom-emoji" alt="${emoji[0].shortcode}" title="${emoji[0].shortcode}" src="${emoji[0].url}" data-original="${emoji[0].url}" data-static="${emoji[0].static_url}" width="16" height="16" onerror="this.onerror=null;this.src='/storage/emoji/missing.png';" />` : em;
+                });
+                return un;
+            } else {
+                return dn;
             }
-		},
-
-		methods: {
-			getDisplayName() {
-				let self = this;
-				let profile = this.user;
-				let dn = profile.display_name;
-				if(!dn) {
-					return profile.username;
-				}
-				if(dn.includes(':')) {
-					let re = /(<a?)?:\w+:(\d{18}>)?/g;
-					let un = dn.replaceAll(re, function(em) {
-						let shortcode = em.slice(1, em.length - 1);
-						let emoji = self.getCustomEmoji.filter(e => {
-							return e.shortcode == shortcode;
-						});
-						return emoji.length ? `<img draggable="false" class="emojione custom-emoji" alt="${emoji[0].shortcode}" title="${emoji[0].shortcode}" src="${emoji[0].url}" data-original="${emoji[0].url}" data-static="${emoji[0].static_url}" width="16" height="16" onerror="this.onerror=null;this.src='/storage/emoji/missing.png';" />`: em;
-					});
-					return un;
-				} else {
-					return dn;
-				}
-			},
-
-			gotoMyProfile() {
-				let user = this.user;
-				this.$router.push({
-					name: 'profile',
-					path: `/i/web/profile/${user.id}`,
-					params: {
-						id: user.id,
-						cachedProfile: user,
-						cachedUser: user
-					}
-				})
-			},
-
-			formatCount(count = 0, locale = 'en-GB', notation = 'compact') {
-				return new Intl.NumberFormat(locale, { notation: notation , compactDisplay: "short" }).format(count);
-			},
-
-			updateAvatar() {
-				event.currentTarget.blur();
-				// swal('update avatar', 'test', 'success');
-				this.$refs.avatarUpdate.open();
-			},
-
-			createNewPost() {
-				this.$refs.createPostModal.show();
-			},
-
-            goToFeed(feed) {
-                const curPath = this.$route.path;
-                switch(feed) {
-                    case 'home':
-                        if(curPath == '/i/web') {
-                            this.$emit('refresh');
-                        } else {
-                            this.$router.push('/i/web');
-                        }
+        },
+
+        gotoMyProfile() {
+            let user = this.user;
+            this.$router.push({
+                name: 'profile',
+                path: `/i/web/profile/${user.id}`,
+                params: {
+                    id: user.id,
+                    cachedProfile: user,
+                    cachedUser: user
+                }
+            })
+        },
+
+        formatCount(count = 0, locale = 'en-GB', notation = 'compact') {
+            return new Intl.NumberFormat(locale, {notation: notation, compactDisplay: "short"}).format(count);
+        },
+
+        updateAvatar() {
+            event.currentTarget.blur();
+            // swal('update avatar', 'test', 'success');
+            this.$refs.avatarUpdate.open();
+        },
+
+        createNewPost() {
+            this.$refs.createPostModal.show();
+        },
+
+        goToFeed(feed) {
+            const curPath = this.$route.path;
+            switch (feed) {
+                case 'home':
+                    if (curPath == '/i/web') {
+                        this.$emit('refresh');
+                    } else {
+                        this.$router.push('/i/web');
+                    }
                     break;
 
-                    case 'local':
-                        if(curPath == '/i/web/timeline/local') {
-                            this.$emit('refresh');
-                        } else {
-                            this.$router.push({ name: 'timeline', params: { scope: 'local' }});
-                        }
+                case 'local':
+                    if (curPath == '/i/web/timeline/local') {
+                        this.$emit('refresh');
+                    } else {
+                        this.$router.push({name: 'timeline', params: {scope: 'local'}});
+                    }
                     break;
 
-                    case 'global':
-                        if(curPath == '/i/web/timeline/global') {
-                            this.$emit('refresh');
-                        } else {
-                            this.$router.push({ name: 'timeline', params: { scope: 'global' }});
-                        }
+                case 'global':
+                    if (curPath == '/i/web/timeline/global') {
+                        this.$emit('refresh');
+                    } else {
+                        this.$router.push({name: 'timeline', params: {scope: 'global'}});
+                    }
                     break;
-                }
             }
-		}
-	}
+        }
+    }
+}
 </script>
 
 <style lang="scss">
-	.sidebar-component {
-		.sidebar-sticky {
-			background-color: var(--card-bg);
-			border-radius: 15px;
-		}
-
-		&.sticky-top {
-			top: 90px;
-		}
-
-		.nav {
-			overflow: auto;
-		}
-
-		.nav-item {
-			.nav-link {
-				font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
-				font-weight: 500;
-				color: rgba(156,163,175, 1);
-				padding-left: 14px;
-				margin-bottom: 5px;
-
-				&:hover {
-					background-color: var(--light-hover-bg);
-				}
-
-				.icon {
-					display: inline-block;
-					width: 40px;
-					text-align: center;
-				}
-
-			}
-
-			.router-link-exact-active {
-				color: var(--primary);
-				font-weight: 700;
-				padding-left: 14px;
-
-				&:not(.text-center) {
-					padding-left: 10px;
-					border-left: 4px solid var(--primary);
-				}
-
-				.icon {
-					color: var(--primary) !important;
-				}
-			}
-
-			&:first-child {
-				.nav-link {
-					.small {
-						font-weight: 700;
-					}
-
-					&:first-child {
-						border-top-left-radius: 15px;
-					}
-
-					&:last-child {
-						border-top-right-radius: 15px;
-					}
-				}
-			}
-
-			&:is(:last-child) {
-				.nav-link {
-					margin-bottom: 0;
-					border-bottom-left-radius: 15px;
-					border-bottom-right-radius: 15px;
-				}
-			}
-		}
-
-		.sidebar-heading {
-			font-size: .75rem;
-			text-transform: uppercase;
-		}
-
-		.user-card {
-			align-items: center;
-
-			.avatar {
-				width: 75px;
-				height: 75px;
-				border-radius: 15px;
-				margin-right: 0.8rem;
-				border: 1px solid var(--border-color);
-			}
-
-			.avatar-update-btn {
-				position: absolute;
-				right: 12px;
-				bottom: 0;
-				width: 20px;
-				height: 20px;
-				background: rgba(255,255,255,0.9);
-				border: 1px solid #dee2e6 !important;
-				padding: 0;
-				border-radius: 50rem;
-
-				&-icon {
-					font-family: 'Font Awesome 5 Free';
-					font-weight: 400;
-					-webkit-font-smoothing: antialiased;
-					display: inline-block;
-					font-style: normal;
-					font-variant: normal;
-					text-rendering: auto;
-					line-height: 1;
-
-					&:before {
-						content: "\F013";
-					}
-				}
-			}
-
-			.username {
-				font-weight: 600;
-				font-size: 13px;
-				margin-bottom: 0;
-			}
-
-			.display-name {
-				color: var(--body-color);
-				line-height: 0.8;
-				font-size: 14px;
-				font-weight: 800 !important;
-				user-select: all;
-				font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
-				margin-bottom: 0;
-                word-break: break-all;
-			}
-
-			.stats {
-				margin-top: 0;
-				margin-bottom: 0;
-				font-size: 12px;
-				user-select: none;
-
-				.stats-following {
-					margin-right: 0.8rem;
-				}
-
-				.following-count,
-				.followers-count {
-					font-weight: 800;
-				}
-			}
-		}
-
-		.btn-primary {
-			background-color: var(--primary);
-
-			&.router-link-exact-active {
-				opacity: 0.5;
-				pointer-events: none;
-				cursor: unset;
-			}
-		}
-
-		.sidebar-sitelinks {
-			margin-top: 1rem;
-			display: flex;
-			justify-content: space-between;
-			padding: 0 2rem;
-
-			a {
-				font-size: 12px;
-				color: #B8C2CC;
-			}
-
-			.active {
-				color: #212529;
-				font-weight: 600;
-			}
-		}
-
-		.sidebar-attribution {
-			margin-top: 0.5rem;
-			font-size: 10px;
-			color: #B8C2CC;
-			padding-left: 2rem;
-
-			a {
-				color: #B8C2CC !important;
-
-				&.powered-by {
-					opacity: 0.5;
-				}
-			}
-		}
-	}
+.sidebar-component {
+    .sidebar-sticky {
+        background-color: var(--card-bg);
+        border-radius: 15px;
+    }
+
+    &.sticky-top {
+        top: 90px;
+    }
+
+    .nav {
+        overflow: auto;
+    }
+
+    .nav-item {
+        .nav-link {
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+            font-weight: 500;
+            color: rgba(156, 163, 175, 1);
+            padding-left: 14px;
+            margin-bottom: 5px;
+
+            &:hover {
+                background-color: var(--light-hover-bg);
+            }
+
+            .icon {
+                display: inline-block;
+                width: 40px;
+                text-align: center;
+            }
+
+        }
+
+        .router-link-exact-active {
+            color: var(--primary);
+            font-weight: 700;
+            padding-left: 14px;
+
+            &:not(.text-center) {
+                padding-left: 10px;
+                border-left: 4px solid var(--primary);
+            }
+
+            .icon {
+                color: var(--primary) !important;
+            }
+        }
+
+        &:first-child {
+            .nav-link {
+                .small {
+                    font-weight: 700;
+                }
+
+                &:first-child {
+                    border-top-left-radius: 15px;
+                }
+
+                &:last-child {
+                    border-top-right-radius: 15px;
+                }
+            }
+        }
+
+        &:is(:last-child) {
+            .nav-link {
+                margin-bottom: 0;
+                border-bottom-left-radius: 15px;
+                border-bottom-right-radius: 15px;
+            }
+        }
+    }
+
+    .sidebar-heading {
+        font-size: .75rem;
+        text-transform: uppercase;
+    }
+
+    .user-card {
+        align-items: center;
+
+        .avatar {
+            width: 75px;
+            height: 75px;
+            border-radius: 15px;
+            margin-right: 0.8rem;
+            border: 1px solid var(--border-color);
+        }
+
+        .avatar-update-btn {
+            position: absolute;
+            right: 12px;
+            bottom: 0;
+            width: 20px;
+            height: 20px;
+            background: rgba(255, 255, 255, 0.9);
+            border: 1px solid #dee2e6 !important;
+            padding: 0;
+            border-radius: 50rem;
+
+            &-icon {
+                font-family: 'Font Awesome 5 Free';
+                font-weight: 400;
+                -webkit-font-smoothing: antialiased;
+                display: inline-block;
+                font-style: normal;
+                font-variant: normal;
+                text-rendering: auto;
+                line-height: 1;
+
+                &:before {
+                    content: "\F013";
+                }
+            }
+        }
+
+        .username {
+            font-weight: 600;
+            font-size: 13px;
+            margin-bottom: 0;
+        }
+
+        .display-name {
+            color: var(--body-color);
+            line-height: 0.8;
+            font-size: 14px;
+            font-weight: 800 !important;
+            user-select: all;
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+            margin-bottom: 0;
+            word-break: break-all;
+        }
+
+        .stats {
+            margin-top: 0;
+            margin-bottom: 0;
+            font-size: 12px;
+            user-select: none;
+
+            .stats-following {
+                margin-right: 0.8rem;
+            }
+
+            .following-count,
+            .followers-count {
+                font-weight: 800;
+            }
+        }
+    }
+
+    .btn-primary {
+        background-color: var(--primary);
+
+        &.router-link-exact-active {
+            opacity: 0.5;
+            pointer-events: none;
+            cursor: unset;
+        }
+    }
+
+    .sidebar-sitelinks {
+        margin-top: 1rem;
+        display: flex;
+        justify-content: space-between;
+        padding: 0 2rem;
+
+        a {
+            font-size: 12px;
+            color: #B8C2CC;
+        }
+
+        .active {
+            color: #212529;
+            font-weight: 600;
+        }
+    }
+
+    .sidebar-attribution {
+        margin-top: 0.5rem;
+        font-size: 10px;
+        color: #B8C2CC;
+        padding-left: 2rem;
+
+        a {
+            color: #B8C2CC !important;
+
+            &.powered-by {
+                opacity: 0.5;
+            }
+        }
+    }
+}
 </style>

+ 8 - 7
resources/lang/de/web.php

@@ -62,12 +62,13 @@ return [
 		'compose' => 'Neu erstellen:',
 		'logout' => 'Ausloggen',
 
-		// Nav footer
-		'about' => 'Über uns',
-		'help' => 'Hilfe',
-		'language' => 'Sprache',
-		'privacy' => 'Privatsphäre',
-		'terms' => 'AGB',
+        // Nav footer
+        'about' => 'Über uns',
+        'help' => 'Hilfe',
+        'language' => 'Sprache',
+        'privacy' => 'Privatsphäre',
+        'terms' => 'AGB',
+        'legalNotice' => 'Impressum',
 
 		// Temporary links
 		'backToPreviousDesign' => 'Zurück zum vorherigen Design'
@@ -195,7 +196,7 @@ return [
 	'hashtags' => [
 		'emptyFeed' => 'Wir können keine Beiträge mit diesem Hashtag finden'
 	],
-	
+
 	'report' => [
 		'report' => 'Melden',
 		'selectReason' => 'Wähle einen Grund',

+ 1 - 0
resources/lang/en/web.php

@@ -71,6 +71,7 @@ return [
 		'language' => 'Language',
 		'privacy' => 'Privacy',
 		'terms' => 'Terms',
+        'legalNotice' => 'Legal Notice',
 
 		// Temporary links
 		'backToPreviousDesign' => 'Go back to previous design'

+ 1 - 1
resources/views/admin/pages/edit.blade.php

@@ -16,7 +16,7 @@
 </div>
 <div class="container-fluid mt-4">
     <input type="hidden" id="slug" name="slug" value="{{$page->slug}}">
-    <input class="form-control form-control-lg" id="title" name="title" placeholder="Title">
+    <input class="form-control form-control-lg" id="title" name="title" placeholder="Title" value="{{$page->title}}">
     <p class="small text-muted">
       Page URL: <span class="page-url font-weight-bold">{{$page->url()}}</span>
       {{-- <span class="pl-1"><a href="#" class="font-weight-bold">Edit</a></span> --}}