Page MenuHomePhorge

No OneTemporary

Size
112 KB
Referenced Files
None
Subscribers
None
diff --git a/changelog.d/misc-markup.fix b/changelog.d/misc-markup.fix
new file mode 100644
index 0000000000..7af934a29a
--- /dev/null
+++ b/changelog.d/misc-markup.fix
@@ -0,0 +1 @@
+Fix small markup inconsistencies
diff --git a/changelog.d/user-link.add b/changelog.d/user-link.add
new file mode 100644
index 0000000000..ca65aa5fac
--- /dev/null
+++ b/changelog.d/user-link.add
@@ -0,0 +1 @@
+Make UserLink wrappable
diff --git a/src/components/announcements_page/announcements_page.vue b/src/components/announcements_page/announcements_page.vue
index 25f830ffbb..44e2cf46a7 100644
--- a/src/components/announcements_page/announcements_page.vue
+++ b/src/components/announcements_page/announcements_page.vue
@@ -1,78 +1,78 @@
<template>
<div class="panel panel-default announcements-page">
<div class="panel-heading">
- <span>
+ <h1 class="title">
{{ $t('announcements.page_header') }}
- </span>
+ </h1>
</div>
<div class="panel-body">
<section
v-if="canPostAnnouncement"
>
<div class="post-form">
<div class="heading">
<h4>{{ $t('announcements.post_form_header') }}</h4>
</div>
<div class="body">
<announcement-editor
:announcement="newAnnouncement"
:disabled="posting"
/>
</div>
<div class="footer">
<button
class="btn button-default post-button"
:disabled="posting"
@click.prevent="postAnnouncement"
>
{{ $t('announcements.post_action') }}
</button>
<div
v-if="error"
class="alert error"
>
{{ $t('announcements.post_error', { error }) }}
<button
class="button-unstyled"
@click="clearError"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
:title="$t('announcements.close_error')"
/>
</button>
</div>
</div>
</div>
</section>
<section
v-for="announcement in announcements"
:key="announcement.id"
>
<announcement
:announcement="announcement"
/>
</section>
</div>
</div>
</template>
<script src="./announcements_page.js"></script>
<style lang="scss">
.announcements-page {
.post-form {
padding: var(--status-margin);
.heading,
.body {
margin-bottom: var(--status-margin);
}
.post-button {
min-width: 10em;
}
}
}
</style>
diff --git a/src/components/bookmark_folder_edit/bookmark_folder_edit.vue b/src/components/bookmark_folder_edit/bookmark_folder_edit.vue
index b6a768d414..709df402a1 100644
--- a/src/components/bookmark_folder_edit/bookmark_folder_edit.vue
+++ b/src/components/bookmark_folder_edit/bookmark_folder_edit.vue
@@ -1,198 +1,198 @@
<template>
<div class="panel-default panel BookmarkFolderEdit">
<div
ref="header"
class="panel-heading folder-edit-heading"
>
<button
class="button-unstyled go-back-button"
@click="$router.back"
>
<FAIcon
size="lg"
icon="chevron-left"
/>
</button>
- <div class="title">
+ <h1 class="title">
<i18n-t
v-if="id"
keypath="bookmark_folders.editing_folder"
>
<template #folderName>
{{ name }}
</template>
</i18n-t>
<i18n-t
v-else
keypath="bookmark_folders.creating_folder"
/>
- </div>
+ </h1>
</div>
<div class="panel-body">
<div class="input-wrap">
<label for="folder-edit-title">{{ $t('bookmark_folders.emoji') }}</label>
<button
class="input input-emoji"
:title="$t('bookmark_folder.emoji_pick')"
@click="showEmojiPicker"
>
<img
v-if="emojiUrlDraft"
class="iconEmoji iconEmoji-image"
:src="emojiUrlDraft"
:alt="emojiDraft"
:title="emojiDraft"
>
<span
v-else-if="emojiDraft"
class="iconEmoji"
>
<span>
{{ emojiDraft }}
</span>
</span>
</button>
<EmojiPicker
ref="picker"
class="emoji-picker-panel"
@emoji="selectEmoji"
@show="onShowPicker"
@close="onClosePicker"
/>
</div>
<div class="input-wrap">
<label for="folder-edit-title">{{ $t('bookmark_folders.name') }}</label>
<input
id="folder-edit-title"
ref="name"
v-model="nameDraft"
class="input"
>
</div>
</div>
<div class="panel-footer">
<span class="spacer" />
<button
v-if="!id"
class="btn button-default footer-button"
@click="createFolder"
>
{{ $t('bookmark_folders.create') }}
</button>
<button
v-else-if="!reallyDelete"
class="btn button-default footer-button"
@click="reallyDelete = true"
>
{{ $t('bookmark_folders.delete') }}
</button>
<template v-else>
{{ $t('bookmark_folders.really_delete') }}
<button
class="btn button-default footer-button"
@click="deleteFolder"
>
{{ $t('general.yes') }}
</button>
<button
class="btn button-default footer-button"
@click="reallyDelete = false"
>
{{ $t('general.no') }}
</button>
</template>
<div
v-if="id && !reallyDelete"
>
<button
class="btn button-default follow-button"
@click="updateFolder"
>
{{ $t('bookmark_folders.update_folder') }}
</button>
</div>
</div>
</div>
</template>
<script src="./bookmark_folder_edit.js"></script>
<style lang="scss">
.BookmarkFolderEdit {
--panel-body-padding: 0.5em;
overflow: hidden;
display: flex;
flex-direction: column;
.folder-edit-heading {
grid-template-columns: auto minmax(50%, 1fr);
}
.panel-body {
display: flex;
gap: 0.5em;
}
.emoji-picker-panel {
position: absolute;
z-index: 20;
margin-top: 2px;
&.hide {
display: none;
}
}
.input-emoji {
height: 2.5em;
width: 2.5em;
padding: 0;
.iconEmoji {
display: inline-block;
text-align: center;
object-fit: contain;
vertical-align: middle;
height: 2.5em;
width: 2.5em;
> span {
font-size: 1.5rem;
line-height: 2.5rem;
}
}
img.iconEmoji {
padding: 0.25em;
box-sizing: border-box;
}
}
.input-wrap {
display: flex;
flex-direction: column;
gap: 0.5em;
}
.go-back-button {
text-align: center;
line-height: 1;
height: 100%;
align-self: start;
width: var(--__panel-heading-height-inner);
}
.btn {
margin: 0 0.5em;
}
.panel-footer {
grid-template-columns: minmax(10%, 1fr);
.footer-button {
min-width: 9em;
}
}
}
</style>
diff --git a/src/components/bookmark_folders/bookmark_folders.vue b/src/components/bookmark_folders/bookmark_folders.vue
index d92e95df05..fdd461064b 100644
--- a/src/components/bookmark_folders/bookmark_folders.vue
+++ b/src/components/bookmark_folders/bookmark_folders.vue
@@ -1,37 +1,37 @@
<template>
<div class="Bookmark-folders panel panel-default">
<div class="panel-heading">
- <div class="title">
+ <h1 class="title">
{{ $t('nav.bookmark_folders') }}
- </div>
+ </h1>
<router-link
:to="{ name: 'bookmark-folder-new' }"
class="button-default btn new-folder-button"
>
{{ $t("bookmark_folders.new") }}
</router-link>
</div>
<div class="panel-body">
<BookmarkFolderCard
:all-bookmarks="true"
class="list-item"
/>
<BookmarkFolderCard
v-for="folder in bookmarkFolders.slice().reverse()"
:key="folder"
:folder="folder"
class="list-item"
/>
</div>
</div>
</template>
<script src="./bookmark_folders.js"></script>
<style lang="scss">
.Bookmark-folders {
.new-folder-button {
padding: 0 0.5em;
}
}
</style>
diff --git a/src/components/chat_list/chat_list.vue b/src/components/chat_list/chat_list.vue
index b33ea67ec2..24bbc9f4a4 100644
--- a/src/components/chat_list/chat_list.vue
+++ b/src/components/chat_list/chat_list.vue
@@ -1,61 +1,61 @@
<template>
<div v-if="isNew">
<ChatNew @cancel="cancelNewChat" />
</div>
<div
v-else
class="chat-list panel panel-default"
>
<div class="panel-heading -sticky">
- <span class="title">
+ <h1 class="title">
{{ $t("chats.chats") }}
- </span>
+ </h1>
<button
class="button-default"
@click="newChat"
>
{{ $t("chats.new") }}
</button>
</div>
<div class="panel-body">
<div
v-if="sortedChatList.length > 0"
class="timeline"
>
<List :items="sortedChatList">
<template #item="{item}">
<ChatListItem
:key="item.id"
:compact="false"
:chat="item"
/>
</template>
</List>
</div>
<div
v-else
class="emtpy-chat-list-alert"
>
<span>{{ $t('chats.empty_chat_list_placeholder') }}</span>
</div>
</div>
</div>
</template>
<script src="./chat_list.js"></script>
<style lang="scss">
.chat-list {
min-height: 25em;
margin-bottom: 0;
}
.emtpy-chat-list-alert {
padding: 3em;
font-size: 1.2em;
display: flex;
justify-content: center;
color: var(--textFaint);
}
</style>
diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue
index 526de5c307..1c290b9004 100644
--- a/src/components/conversation/conversation.vue
+++ b/src/components/conversation/conversation.vue
@@ -1,332 +1,334 @@
<template>
<div
v-if="!hideStatus"
:style="hiddenStyle"
class="Conversation"
:class="{ '-expanded' : isExpanded, 'panel' : isExpanded }"
>
<div
v-if="isExpanded"
class="panel-heading conversation-heading -sticky"
>
- <span class="title"> {{ $t('timeline.conversation') }} </span>
+ <h1 class="title">
+ {{ $t('timeline.conversation') }}
+ </h1>
<button
v-if="collapsable"
class="button-unstyled -link"
@click.prevent="toggleExpanded"
>
{{ $t('timeline.collapse') }}
</button>
<QuickFilterSettings
v-if="!collapsable"
:conversation="true"
class="rightside-button"
/>
<QuickViewSettings
v-if="!collapsable"
:conversation="true"
class="rightside-button"
/>
</div>
<div
v-if="isPage && !status"
class="conversation-body"
:class="{ 'panel-body': isExpanded }"
>
<p v-if="!loadStatusError">
<FAIcon
spin
icon="circle-notch"
/>
{{ $t('status.loading') }}
</p>
<p v-else>
{{ $t('status.load_error', { error: loadStatusError }) }}
</p>
</div>
<div
v-else
class="conversation-body"
:class="{ 'panel-body': isExpanded }"
>
<div
v-if="isTreeView"
class="thread-body"
>
<div
v-if="shouldShowAllConversationButton"
class="conversation-dive-to-top-level-box"
>
<i18n-t
keypath="status.show_all_conversation_with_icon"
tag="button"
class="button-unstyled -link"
scope="global"
@click.prevent="diveToTopLevel"
>
<template #icon>
<FAIcon
icon="angle-double-left"
/>
</template>
<template #text>
<span>
{{ $tc('status.show_all_conversation', otherTopLevelCount, { numStatus: otherTopLevelCount }) }}
</span>
</template>
</i18n-t>
</div>
<div
v-if="shouldShowAncestors"
class="thread-ancestors"
>
<article
v-for="status in ancestorsOf(diveRoot)"
:key="status.id"
class="thread-ancestor"
:class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1, '-faded': shouldFadeAncestors}"
>
<status
ref="statusComponent"
:inline-expanded="collapsable && isExpanded"
:statusoid="status"
:expandable="!isExpanded"
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:focused="focused(status.id)"
:in-conversation="isExpanded"
:highlight="getHighlight()"
:replies="getReplies(status.id)"
:in-profile="inProfile"
:profile-user-id="profileUserId"
class="conversation-status status-fadein panel-body"
:simple-tree="treeViewIsSimple"
:toggle-thread-display="toggleThreadDisplay"
:thread-display-status="threadDisplayStatus"
:show-thread-recursively="showThreadRecursively"
:total-reply-count="totalReplyCount"
:total-reply-depth="totalReplyDepth"
:show-other-replies-as-button="showOtherRepliesButtonInsideStatus"
:dive="() => diveIntoStatus(status.id)"
:controlled-showing-tall="statusContentProperties[status.id].showingTall"
:controlled-expanding-subject="statusContentProperties[status.id].expandingSubject"
:controlled-showing-long-subject="statusContentProperties[status.id].showingLongSubject"
:controlled-replying="statusContentProperties[status.id].replying"
:controlled-media-playing="statusContentProperties[status.id].mediaPlaying"
:controlled-toggle-showing-tall="() => toggleStatusContentProperty(status.id, 'showingTall')"
:controlled-toggle-expanding-subject="() => toggleStatusContentProperty(status.id, 'expandingSubject')"
:controlled-toggle-showing-long-subject="() => toggleStatusContentProperty(status.id, 'showingLongSubject')"
:controlled-toggle-replying="() => toggleStatusContentProperty(status.id, 'replying')"
:controlled-set-media-playing="(newVal) => toggleStatusContentProperty(status.id, 'mediaPlaying', newVal)"
@goto="setHighlight"
@toggleExpanded="toggleExpanded"
/>
<div
v-if="showOtherRepliesButtonBelowStatus && getReplies(status.id).length > 1"
class="thread-ancestor-dive-box"
>
<div
class="thread-ancestor-dive-box-inner"
>
<i18n-t
tag="button"
scope="global"
keypath="status.ancestor_follow_with_icon"
class="button-unstyled -link thread-tree-show-replies-button"
@click.prevent="diveIntoStatus(status.id)"
>
<template #icon>
<FAIcon
icon="angle-double-right"
/>
</template>
<template #text>
<span>
{{ $tc('status.ancestor_follow', getReplies(status.id).length - 1, { numReplies: getReplies(status.id).length - 1 }) }}
</span>
</template>
</i18n-t>
</div>
</div>
</article>
</div>
<thread-tree
v-for="status in showingTopLevel"
:key="status.id"
ref="statusComponent"
:depth="0"
:status="status"
:in-profile="inProfile"
:conversation="conversation"
:collapsable="collapsable"
:is-expanded="isExpanded"
:pinned-status-ids-object="pinnedStatusIdsObject"
:profile-user-id="profileUserId"
:focused="focused"
:get-replies="getReplies"
:highlight="maybeHighlight"
:set-highlight="setHighlight"
:toggle-expanded="toggleExpanded"
:simple="treeViewIsSimple"
:toggle-thread-display="toggleThreadDisplay"
:thread-display-status="threadDisplayStatus"
:show-thread-recursively="showThreadRecursively"
:total-reply-count="totalReplyCount"
:total-reply-depth="totalReplyDepth"
:status-content-properties="statusContentProperties"
:set-status-content-property="setStatusContentProperty"
:toggle-status-content-property="toggleStatusContentProperty"
:dive="canDive ? diveIntoStatus : undefined"
/>
</div>
<div
v-if="isLinearView"
class="thread-body"
>
<article>
<status
v-for="status in conversation"
:key="status.id"
ref="statusComponent"
:inline-expanded="collapsable && isExpanded"
:statusoid="status"
:expandable="!isExpanded"
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:focused="focused(status.id)"
:in-conversation="isExpanded"
:highlight="getHighlight()"
:replies="getReplies(status.id)"
:in-profile="inProfile"
:profile-user-id="profileUserId"
class="conversation-status status-fadein panel-body"
:toggle-thread-display="toggleThreadDisplay"
:thread-display-status="threadDisplayStatus"
:show-thread-recursively="showThreadRecursively"
:total-reply-count="totalReplyCount"
:total-reply-depth="totalReplyDepth"
:status-content-properties="statusContentProperties"
:set-status-content-property="setStatusContentProperty"
:toggle-status-content-property="toggleStatusContentProperty"
@goto="setHighlight"
@toggleExpanded="toggleExpanded"
/>
</article>
</div>
</div>
</div>
<div
v-else
class="Conversation -hidden"
:style="hiddenStyle"
/>
</template>
<script src="./conversation.js"></script>
<style lang="scss">
.Conversation {
z-index: 1;
&.-hidden {
background: var(--__panel-background);
backdrop-filter: var(--__panel-backdrop-filter);
}
.conversation-dive-to-top-level-box {
padding: var(--status-margin);
border-bottom: 1px solid var(--border);
border-radius: 0;
/* Make the button stretch along the whole row */
display: flex;
align-items: stretch;
flex-direction: column;
}
.thread-ancestors {
margin-left: var(--status-margin);
border-left: 2px solid var(--border);
}
.thread-ancestor.-faded .RichContent {
/* stylelint-disable declaration-no-important */
--text: var(--textFaint) !important;
--link: var(--linkFaint) !important;
--funtextGreentext: var(--funtextGreentextFaint) !important;
--funtextCyantext: var(--funtextCyantextFaint) !important;
/* stylelint-enable declaration-no-important */
}
.thread-ancestor-dive-box {
padding-left: var(--status-margin);
border-bottom: 1px solid var(--border);
border-radius: 0;
/* Make the button stretch along the whole row */
&,
&-inner {
display: flex;
align-items: stretch;
flex-direction: column;
}
}
.thread-ancestor-dive-box-inner {
padding: var(--status-margin);
}
.conversation-status {
border-bottom: 1px solid var(--border);
border-radius: 0;
}
.thread-ancestor-has-other-replies .conversation-status,
&:last-child:not(.-expanded) .conversation-status,
&.-expanded .conversation-status:last-child,
.thread-ancestor:last-child .conversation-status,
.thread-ancestor:last-child .thread-ancestor-dive-box,
&.-expanded .thread-tree .conversation-status {
border-bottom: none;
}
.thread-ancestors + .thread-tree > .conversation-status {
border-top: 1px solid var(--border);
}
/* expanded conversation in timeline */
&.status-fadein.-expanded .thread-body {
border-left: 4px solid var(--cRed);
border-radius: var(--roundness);
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom: 1px solid var(--border);
}
&.-expanded.status-fadein {
--___margin: calc(var(--status-margin) / 2);
background: var(--background);
margin: var(--___margin);
&::before {
z-index: -1;
content: "";
display: block;
position: absolute;
top: calc(var(--___margin) * -1);
bottom: calc(var(--___margin) * -1);
left: calc(var(--___margin) * -1);
right: calc(var(--___margin) * -1);
background: var(--background);
backdrop-filter: var(--__panel-backdrop-filter);
}
}
}
</style>
diff --git a/src/components/dialog_modal/dialog_modal.vue b/src/components/dialog_modal/dialog_modal.vue
index 3bceff229b..93b8ac0fab 100644
--- a/src/components/dialog_modal/dialog_modal.vue
+++ b/src/components/dialog_modal/dialog_modal.vue
@@ -1,82 +1,82 @@
<template>
<span
:class="{ 'dark-overlay': darkOverlay }"
@click.self.stop="onCancel()"
>
<div
class="dialog-modal panel panel-default"
@click.stop=""
>
<div class="panel-heading dialog-modal-heading">
- <div class="title">
+ <h1 class="title">
<slot name="header" />
- </div>
+ </h1>
</div>
<div class="panel-body dialog-modal-content">
<slot name="default" />
</div>
<div class="dialog-modal-footer user-interactions panel-footer">
<slot name="footer" />
</div>
</div>
</span>
</template>
<script src="./dialog_modal.js"></script>
<style lang="scss">
// TODO: unify with other modals.
.dark-overlay {
&::before {
bottom: 0;
content: " ";
display: block;
cursor: default;
left: 0;
position: fixed;
right: 0;
top: 0;
background: rgb(27 31 35 / 50%);
z-index: 2000;
}
}
.dialog-modal.panel {
top: 0;
left: 50%;
max-height: 80vh;
max-width: 90vw;
margin: 15vh auto;
position: fixed;
transform: translateX(-50%);
z-index: 2001;
cursor: default;
display: block;
.dialog-modal-heading {
.title {
text-align: center;
}
}
.dialog-modal-content {
margin: 0;
padding: 1rem;
white-space: normal;
}
.dialog-modal-footer {
margin: 0;
padding: 0.5em;
border-top: 1px solid var(--border);
display: flex;
justify-content: flex-end;
button {
width: auto;
margin-left: 0.5rem;
}
}
}
</style>
diff --git a/src/components/edit_status_modal/edit_status_modal.vue b/src/components/edit_status_modal/edit_status_modal.vue
index db62972d6a..5001bd46c1 100644
--- a/src/components/edit_status_modal/edit_status_modal.vue
+++ b/src/components/edit_status_modal/edit_status_modal.vue
@@ -1,49 +1,51 @@
<template>
<Modal
v-if="isFormVisible"
class="edit-form-modal-view"
@backdropClicked="closeModal"
>
<div class="edit-form-modal-panel panel">
<div class="panel-heading">
- {{ $t('post_status.edit_status') }}
+ <h1 class="title">
+ {{ $t('post_status.edit_status') }}
+ </h1>
</div>
<PostStatusForm
class="panel-body"
v-bind="params"
:post-handler="doEditStatus"
:disable-polls="true"
:disable-visibility-selector="true"
@posted="closeModal"
/>
</div>
</Modal>
</template>
<script src="./edit_status_modal.js"></script>
<style lang="scss">
.modal-view.edit-form-modal-view {
align-items: flex-start;
}
.edit-form-modal-panel {
flex-shrink: 0;
margin-top: 25%;
margin-bottom: 2em;
width: 100%;
max-width: 700px;
@media (orientation: landscape) {
margin-top: 8%;
}
.form-bottom-left {
max-width: 6.5em;
.emoji-icon {
justify-content: right;
}
}
}
</style>
diff --git a/src/components/features_panel/features_panel.vue b/src/components/features_panel/features_panel.vue
index 4cdf56d075..cde8d6e420 100644
--- a/src/components/features_panel/features_panel.vue
+++ b/src/components/features_panel/features_panel.vue
@@ -1,41 +1,41 @@
<template>
<div class="features-panel">
<div class="panel panel-default base01-background">
<div class="panel-heading timeline-heading base02-background base04">
- <div class="title">
+ <h1 class="title">
{{ $t('features_panel.title') }}
- </div>
+ </h1>
</div>
<div class="panel-body features-panel">
<ul>
<li v-if="shout">
{{ $t('features_panel.shout') }}
</li>
<li v-if="pleromaChatMessages">
{{ $t('features_panel.pleroma_chat_messages') }}
</li>
<li v-if="gopher">
{{ $t('features_panel.gopher') }}
</li>
<li v-if="whoToFollow">
{{ $t('features_panel.who_to_follow') }}
</li>
<li v-if="mediaProxy">
{{ $t('features_panel.media_proxy') }}
</li>
<li>{{ $t('features_panel.scope_options') }}</li>
<li>{{ $t('features_panel.text_limit') }} = {{ textlimit }}</li>
<li>{{ $t('features_panel.upload_limit') }} = {{ uploadlimit.num }} {{ $t('upload.file_size_units.' + uploadlimit.unit) }}</li>
</ul>
</div>
</div>
</div>
</template>
<script src="./features_panel.js"></script>
<style lang="scss">
.features-panel li {
line-height: 24px;
}
</style>
diff --git a/src/components/follow_requests/follow_requests.vue b/src/components/follow_requests/follow_requests.vue
index 41f19db8f9..b678364cc7 100644
--- a/src/components/follow_requests/follow_requests.vue
+++ b/src/components/follow_requests/follow_requests.vue
@@ -1,19 +1,19 @@
<template>
<div class="settings panel panel-default">
<div class="panel-heading">
- <div class="title">
+ <h1 class="title">
{{ $t('nav.friend_requests') }}
- </div>
+ </h1>
</div>
<div class="panel-body">
<FollowRequestCard
v-for="request in requests"
:key="request.id"
:user="request"
class="list-item"
/>
</div>
</div>
</template>
<script src="./follow_requests.js"></script>
diff --git a/src/components/interactions/interactions.vue b/src/components/interactions/interactions.vue
index a2c56af4e9..1e2efe402e 100644
--- a/src/components/interactions/interactions.vue
+++ b/src/components/interactions/interactions.vue
@@ -1,53 +1,53 @@
<template>
<div class="panel panel-default">
<div class="panel-heading">
- <div class="title">
+ <h1 class="title">
{{ $t("nav.interactions") }}
- </div>
+ </h1>
</div>
<tab-switcher
ref="tabSwitcher"
:on-switch="onModeSwitch"
>
<span
key="statuses"
:label="$t('nav.mentions')"
/>
<span
key="statuses"
:label="$t('interactions.statuses')"
/>
<span
key="likes+repeats"
:label="$t('interactions.favs_repeats')"
/>
<span
key="follows"
:label="$t('interactions.follows')"
/>
<span
key="reactions"
:label="$t('interactions.emoji_reactions')"
/>
<span
v-if="canSeeReports"
key="reports"
:label="$t('interactions.reports')"
/>
<span
v-if="!allowFollowingMove"
key="moves"
:label="$t('interactions.moves')"
/>
</tab-switcher>
<Notifications
ref="notifications"
:no-heading="true"
:no-extra="true"
:minimal-mode="true"
:filter-mode="filterMode"
/>
</div>
</template>
<script src="./interactions.js"></script>
diff --git a/src/components/lists/lists.vue b/src/components/lists/lists.vue
index b8bab0a047..05df5b72f6 100644
--- a/src/components/lists/lists.vue
+++ b/src/components/lists/lists.vue
@@ -1,33 +1,35 @@
<template>
<div class="Lists panel panel-default">
<div class="panel-heading">
<div class="title">
- {{ $t('lists.lists') }}
+ <h1 class="title">
+ {{ $t('lists.lists') }}
+ </h1>
</div>
<router-link
:to="{ name: 'lists-new' }"
class="button-default btn new-list-button"
>
{{ $t("lists.new") }}
</router-link>
</div>
<div class="panel-body">
<ListsCard
v-for="list in lists.slice().reverse()"
:key="list"
:list="list"
class="list-item"
/>
</div>
</div>
</template>
<script src="./lists.js"></script>
<style lang="scss">
.Lists {
.new-list-button {
padding: 0 0.5em;
}
}
</style>
diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue
index adc2dd5b42..3c152b2e46 100644
--- a/src/components/login_form/login_form.vue
+++ b/src/components/login_form/login_form.vue
@@ -1,148 +1,148 @@
<template>
<div class="login panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
- {{ $t('login.login') }}
+ <h1 class="title">{{ $t('login.login') }}</h1>
</div>
<div class="panel-body">
<form
class="login-form"
@submit.prevent="submit"
>
<template v-if="isPasswordAuth">
<div class="form-group">
<label for="username">{{ $t('login.username') }}</label>
<input
id="username"
v-model="user.username"
:disabled="loggingIn"
class="input form-control"
:placeholder="$t('login.placeholder')"
>
</div>
<div class="form-group">
<label for="password">{{ $t('login.password') }}</label>
<input
id="password"
ref="passwordInput"
v-model="user.password"
:disabled="loggingIn"
class="input form-control"
type="password"
>
</div>
<div class="form-group">
<router-link :to="{name: 'password-reset'}">
{{ $t('password_reset.forgot_password') }}
</router-link>
</div>
</template>
<div
v-if="isTokenAuth"
class="form-group"
>
<p>{{ $t('login.description') }}</p>
</div>
<div class="form-group">
<div class="login-bottom">
<div>
<router-link
v-if="registrationOpen"
:to="{name: 'registration'}"
class="register"
>
{{ $t('login.register') }}
</router-link>
</div>
<button
:disabled="loggingIn"
type="submit"
class="btn button-default"
>
{{ $t('login.login') }}
</button>
</div>
</div>
</form>
</div>
<div
v-if="error"
class="form-group"
>
<div class="alert error">
{{ error }}
<button
class="button-unstyled"
@click="clearError"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div>
</div>
</div>
</template>
<script src="./login_form.js"></script>
<style lang="scss">
.login-form {
display: flex;
flex-direction: column;
padding: 0.6em;
.btn {
min-height: 2em;
width: 10em;
}
.register {
flex: 1 1;
}
.login-bottom {
margin-top: 1em;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.form-group {
display: flex;
flex-direction: column;
padding: 0.3em 0.5em 0.6em;
line-height: 24px;
}
.form-bottom {
display: flex;
padding: 0.5em;
height: 32px;
button {
width: 10em;
}
p {
margin: 0.35em;
padding: 0.35em;
display: flex;
}
}
.error {
text-align: center;
animation-name: shakeError;
animation-duration: 0.4s;
animation-timing-function: ease-in-out;
}
}
</style>
diff --git a/src/components/mfa_form/recovery_form.vue b/src/components/mfa_form/recovery_form.vue
index 27184fb4eb..f8c3e6a048 100644
--- a/src/components/mfa_form/recovery_form.vue
+++ b/src/components/mfa_form/recovery_form.vue
@@ -1,72 +1,74 @@
<template>
<div class="login panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
- {{ $t('login.heading.recovery') }}
+ <h1 class="title">
+ {{ $t('login.heading.recovery') }}
+ </h1>
</div>
<div class="panel-body">
<form
class="login-form"
@submit.prevent="submit"
>
<div class="form-group">
<label for="code">{{ $t('login.recovery_code') }}</label>
<input
id="code"
v-model="code"
class="input form-control"
>
</div>
<div class="form-group">
<div class="login-bottom">
<div>
<button
class="button-unstyled -link"
type="button"
@click.prevent="requireTOTP"
>
{{ $t('login.enter_two_factor_code') }}
</button>
<br>
<button
class="button-unstyled -link"
type="button"
@click.prevent="abortMFA"
>
{{ $t('general.cancel') }}
</button>
</div>
<button
type="submit"
class="btn button-default"
>
{{ $t('general.verify') }}
</button>
</div>
</div>
</form>
</div>
<div
v-if="error"
class="form-group"
>
<div class="alert error">
{{ error }}
<button
class="button-unstyled"
@click="clearError"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div>
</div>
</div>
</template>
<script src="./recovery_form.js"></script>
diff --git a/src/components/mfa_form/totp_form.vue b/src/components/mfa_form/totp_form.vue
index 3ec617e9a1..26fc1e8044 100644
--- a/src/components/mfa_form/totp_form.vue
+++ b/src/components/mfa_form/totp_form.vue
@@ -1,75 +1,77 @@
<template>
<div class="login panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
- {{ $t('login.heading.totp') }}
+ <h1 class="title">
+ {{ $t('login.heading.totp') }}
+ </h1>
</div>
<div class="panel-body">
<form
class="login-form"
@submit.prevent="submit"
>
<div class="form-group">
<label for="code">
{{ $t('login.authentication_code') }}
</label>
<input
id="code"
v-model="code"
class="input form-control"
>
</div>
<div class="form-group">
<div class="login-bottom">
<div>
<button
class="button-unstyled -link"
type="button"
@click.prevent="requireRecovery"
>
{{ $t('login.enter_recovery_code') }}
</button>
<br>
<button
class="button-unstyled -link"
type="button"
@click.prevent="abortMFA"
>
{{ $t('general.cancel') }}
</button>
</div>
<button
type="submit"
class="btn button-default"
>
{{ $t('general.verify') }}
</button>
</div>
</div>
</form>
</div>
<div
v-if="error"
class="form-group"
>
<div class="alert error">
{{ error }}
<button
class="button-unstyled"
@click="clearError"
>
<FAIcon
size="lg"
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div>
</div>
</div>
</template>
<script src="./totp_form.js"></script>
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index 76a90d3e52..b737155e51 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -1,256 +1,256 @@
<template>
<div
class="MobileNav"
>
<nav
id="nav"
class="mobile-nav"
@click="scrollToTop()"
>
<div class="item">
<button
class="button-unstyled mobile-nav-button"
:title="$t('nav.mobile_sidebar')"
:aria-expanaded="$refs.sideDrawer && !$refs.sideDrawer.closed"
@click.stop.prevent="toggleMobileSidebar()"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="bars"
/>
<div
v-if="(unreadChatCount && !chatsPinned) || unreadAnnouncementCount"
class="badge -dot -notification"
/>
</button>
<NavigationPins class="pins" />
</div> <div class="item right">
<button
v-if="currentUser"
class="button-unstyled mobile-nav-button"
:title="unseenNotificationsCount ? $t('nav.mobile_notifications_unread_active') : $t('nav.mobile_notifications')"
@click.stop.prevent="openMobileNotifications()"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="bell"
/>
<div
v-if="unseenNotificationsCount"
class="badge -dot -notification"
/>
</button>
</div>
</nav>
<aside
v-if="currentUser"
class="mobile-notifications-drawer mobile-drawer"
:class="{ '-closed': !notificationsOpen }"
@touchstart.stop="notificationsTouchStart"
@touchmove.stop="notificationsTouchMove"
>
<div class="panel-heading mobile-notifications-header">
- <span class="title">
+ <h1 class="title">
{{ $t('notifications.notifications') }}
<span
v-if="unseenCountBadgeText"
class="badge -notification unseen-count"
>{{ unseenCountBadgeText }}</span>
- </span>
+ </h1>
<span class="spacer" />
<button
v-if="notificationsAtTop"
class="button-unstyled mobile-nav-button"
:title="$t('general.scroll_to_top')"
@click.stop.prevent="scrollMobileNotificationsToTop"
>
<FALayers class="fa-scale-110 fa-old-padding-layer">
<FAIcon icon="arrow-up" />
<FAIcon
icon="minus"
transform="up-7"
/>
</FALayers>
</button>
<button
v-if="!closingDrawerMarksAsSeen"
class="button-unstyled mobile-nav-button"
:title="$t('nav.mobile_notifications_mark_as_seen')"
@click.stop.prevent="markNotificationsAsSeen()"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="check-double"
/>
</button>
<button
class="button-unstyled mobile-nav-button"
:title="$t('nav.mobile_notifications_close')"
@click.stop.prevent="closeMobileNotifications(true)"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div>
<div
id="mobile-notifications"
ref="mobileNotifications"
class="mobile-notifications"
@scroll="onScroll"
/>
</aside>
<SideDrawer
ref="sideDrawer"
:logout="logout"
/>
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmLogout"
:title="$t('login.logout_confirm_title')"
:confirm-text="$t('login.logout_confirm_accept_button')"
:cancel-text="$t('login.logout_confirm_cancel_button')"
@accepted="doLogout"
@cancelled="hideConfirmLogout"
>
{{ $t('login.logout_confirm') }}
</confirm-modal>
</teleport>
</div>
</template>
<script src="./mobile_nav.js"></script>
<style lang="scss">
.MobileNav {
z-index: var(--ZI_navbar);
.mobile-nav {
display: grid;
line-height: var(--navbar-height);
grid-template-rows: var(--navbar-height);
grid-template-columns: 2fr auto;
width: 100%;
box-sizing: border-box;
a {
color: var(--link);
}
}
.mobile-inner-nav {
width: 100%;
display: flex;
align-items: center;
}
.mobile-nav-button {
display: inline-block;
text-align: center;
padding: 0 1em;
position: relative;
cursor: pointer;
}
.site-name {
padding: 0 0.3em;
display: inline-block;
}
.item {
/* moslty just to get rid of extra whitespaces */
display: flex;
}
.mobile-notifications-drawer {
width: 100%;
height: 100vh;
overflow-x: hidden;
position: fixed;
top: 0;
left: 0;
box-shadow: var(--shadow);
transition-property: transform;
transition-duration: 0.25s;
transform: translateX(0);
z-index: var(--ZI_navbar);
-webkit-overflow-scrolling: touch;
background: var(--background);
&.-closed {
transform: translateX(100%);
box-shadow: none;
}
}
.mobile-notifications-header {
display: flex;
align-items: center;
justify-content: space-between;
z-index: calc(var(--ZI_navbar) + 100);
width: 100%;
height: 3.5em;
line-height: 3.5em;
position: absolute;
box-shadow: var(--shadow);
.spacer {
flex: 1;
}
.title {
font-size: 1.3em;
margin-left: 0.6em;
}
}
.pins {
flex: 1;
.pinned-item {
flex-grow: 1;
}
}
.mobile-notifications {
margin-top: 3.5em;
width: 100vw;
height: calc(100vh - var(--navbar-height));
overflow-x: hidden;
overflow-y: scroll;
.notifications {
padding: 0;
border-radius: 0;
box-shadow: none;
.panel {
border-radius: 0;
margin: 0;
box-shadow: none;
}
.panel::after {
border-radius: 0;
}
.panel .panel-heading {
border-radius: 0;
box-shadow: none;
}
}
}
.confirm-modal.dark-overlay {
&::before {
z-index: 3000;
}
.dialog-modal.panel {
z-index: 3001;
}
}
}
</style>
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 87e7b68d7b..387c3a8475 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -1,112 +1,112 @@
<template>
<teleport
:disabled="minimalMode || disableTeleport"
:to="teleportTarget"
>
<component
:is="noHeading ? 'div' : 'aside'"
ref="root"
:class="{ minimal: minimalMode }"
class="Notifications"
>
<div :class="mainClass">
<div
v-if="!noHeading"
class="notifications-heading panel-heading -sticky"
>
- <div class="title">
+ <h1 class="title">
{{ $t('notifications.notifications') }}
<span
v-if="unseenCountBadgeText"
class="badge -notification unseen-count"
>{{ unseenCountBadgeText }}</span>
- </div>
+ </h1>
<div
v-if="showScrollTop"
class="rightside-button"
>
<button
class="button-unstyled scroll-to-top-button"
type="button"
:title="$t('general.scroll_to_top')"
@click="scrollToTop"
>
<FALayers class="fa-scale-110 fa-old-padding-layer">
<FAIcon icon="arrow-up" />
<FAIcon
icon="minus"
transform="up-7"
/>
</FALayers>
</button>
</div>
<button
v-if="unseenCount"
class="button-default read-button"
type="button"
@click.prevent="markAsSeen"
>
{{ $t('notifications.read') }}
</button>
<NotificationFilters class="rightside-button" />
</div>
<div
class="panel-body"
role="feed"
>
<div
v-if="showExtraNotifications"
role="listitem"
class="notification"
>
<extra-notifications />
</div>
<div
v-for="notification in notificationsToDisplay"
:key="notification.id"
role="listitem"
class="notification"
:class="{unseen: !minimalMode && shouldShowUnseen(notification)}"
@click="e => notificationClicked(notification)"
>
<div class="notification-overlay" />
<notification
:notification="notification"
@interacted="e => notificationInteracted(notification)"
/>
</div>
</div>
<div class="panel-footer">
<div
v-if="bottomedOut"
class="new-status-notification text-center faint"
>
{{ $t('notifications.no_more_notifications') }}
</div>
<button
v-else-if="!loading"
class="button-unstyled -link text-center"
@click.prevent="fetchOlderNotifications()"
>
<div class="new-status-notification text-center">
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }}
</div>
</button>
<div
v-else
class="new-status-notification text-center"
>
<FAIcon
icon="circle-notch"
spin
size="lg"
/>
</div>
</div>
</div>
</component>
</teleport>
</template>
<script src="./notifications.js"></script>
<style lang="scss" src="./notifications.scss"></style>
diff --git a/src/components/password_reset/password_reset.vue b/src/components/password_reset/password_reset.vue
index 037b859e83..5392f487b5 100644
--- a/src/components/password_reset/password_reset.vue
+++ b/src/components/password_reset/password_reset.vue
@@ -1,127 +1,129 @@
<template>
<div class="settings panel panel-default">
<div class="panel-heading">
- {{ $t('password_reset.password_reset') }}
+ <h1 class="title">
+ {{ $t('password_reset.password_reset') }}
+ </h1>
</div>
<div class="panel-body">
<form
class="password-reset-form"
@submit.prevent="submit"
>
<div class="container">
<div v-if="!mailerEnabled">
<p v-if="passwordResetRequested">
{{ $t('password_reset.password_reset_required_but_mailer_is_disabled') }}
</p>
<p v-else>
{{ $t('password_reset.password_reset_disabled') }}
</p>
</div>
<div v-else-if="success || throttled">
<p v-if="success">
{{ $t('password_reset.check_email') }}
</p>
<div class="form-group text-center">
<router-link :to="{name: 'root'}">
{{ $t('password_reset.return_home') }}
</router-link>
</div>
</div>
<div v-else>
<p
v-if="passwordResetRequested"
class="alert password-reset-required error"
>
{{ $t('password_reset.password_reset_required') }}
</p>
<p>
{{ $t('password_reset.instruction') }}
</p>
<div class="form-group">
<input
ref="email"
v-model="user.email"
:disabled="isPending"
:placeholder="$t('password_reset.placeholder')"
class="input form-control"
type="input"
>
</div>
<div class="form-group">
<button
:disabled="isPending"
type="submit"
class="btn button-default btn-block"
>
{{ $t('settings.save') }}
</button>
</div>
</div>
<p
v-if="error"
class="alert error notice-dismissible"
>
<span>{{ error }}</span>
<a
class="fa-scale-110 fa-old-padding dismiss"
@click.prevent="dismissError()"
>
<FAIcon icon="times" />
</a>
</p>
</div>
</form>
</div>
</div>
</template>
<script src="./password_reset.js"></script>
<style lang="scss">
.password-reset-form {
display: flex;
flex-direction: column;
align-items: center;
margin: 0.6em;
.container {
display: flex;
flex: 1 0;
flex-direction: column;
margin-top: 0.6em;
max-width: 18rem;
> * {
min-width: 0;
}
}
.form-group {
display: flex;
flex-direction: column;
margin-bottom: 1em;
padding: 0.3em 0;
line-height: 1.85em;
}
.error {
text-align: center;
animation-name: shakeError;
animation-duration: 0.4s;
animation-timing-function: ease-in-out;
}
.alert {
padding: 0.5em;
margin: 0.3em 0 1em;
}
.notice-dismissible {
padding-right: 2rem;
}
.dismiss {
cursor: pointer;
}
}
</style>
diff --git a/src/components/post_status_modal/post_status_modal.vue b/src/components/post_status_modal/post_status_modal.vue
index bc2cad4a10..2bdf41d555 100644
--- a/src/components/post_status_modal/post_status_modal.vue
+++ b/src/components/post_status_modal/post_status_modal.vue
@@ -1,39 +1,41 @@
<template>
<Modal
v-if="isLoggedIn && !resettingForm"
:is-open="modalActivated"
class="post-form-modal-view"
@backdropClicked="closeModal"
>
<div class="post-form-modal-panel panel">
<div class="panel-heading">
- {{ $t('post_status.new_status') }}
+ <h1 class="title">
+ {{ $t('post_status.new_status') }}
+ </h1>
</div>
<PostStatusForm
class="panel-body"
v-bind="params"
@posted="resetAndClose"
/>
</div>
</Modal>
</template>
<script src="./post_status_modal.js"></script>
<style lang="scss">
.modal-view.post-form-modal-view {
align-items: flex-start;
}
.post-form-modal-panel {
flex-shrink: 0;
margin-top: 25%;
margin-bottom: 2em;
width: 100%;
max-width: 700px;
@media (orientation: landscape) {
margin-top: 8%;
}
}
</style>
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index a2008d871f..cb0209ec73 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -1,420 +1,422 @@
<template>
<div class="settings panel panel-default">
<div class="panel-heading">
- {{ $t('registration.registration') }}
+ <h1 class="title">
+ {{ $t('registration.registration') }}
+ </h1>
</div>
<div
v-if="!hasSignUpNotice"
class="panel-body"
>
<form
class="registration-form"
@submit.prevent="submit(user)"
>
<div class="container">
<div class="text-fields">
<div
class="form-group"
:class="{ 'form-group--error': v$.user.username.$error }"
>
<label
class="form--label"
for="sign-up-username"
>{{ $t('login.username') }}</label>
<input
id="sign-up-username"
v-model.trim="v$.user.username.$model"
:disabled="isPending"
class="input form-control"
:aria-required="true"
:placeholder="$t('registration.username_placeholder')"
>
</div>
<div
v-if="v$.user.username.$dirty"
class="form-error"
>
<ul>
<li v-if="!v$.user.username.required">
<span>{{ $t('registration.validations.username_required') }}</span>
</li>
</ul>
</div>
<div
class="form-group"
:class="{ 'form-group--error': v$.user.fullname.$error }"
>
<label
class="form--label"
for="sign-up-fullname"
>{{ $t('registration.fullname') }}</label>
<input
id="sign-up-fullname"
v-model.trim="v$.user.fullname.$model"
:disabled="isPending"
class="input form-control"
:aria-required="true"
:placeholder="$t('registration.fullname_placeholder')"
>
</div>
<div
v-if="v$.user.fullname.$dirty"
class="form-error"
>
<ul>
<li v-if="!v$.user.fullname.required">
<span>{{ $t('registration.validations.fullname_required') }}</span>
</li>
</ul>
</div>
<div
class="form-group"
:class="{ 'form-group--error': v$.user.email.$error }"
>
<label
class="form--label"
for="email"
>{{ accountActivationRequired ? $t('registration.email') : $t('registration.email_optional') }}</label>
<input
id="email"
v-model="v$.user.email.$model"
:disabled="isPending"
class="input form-control"
type="email"
:aria-required="accountActivationRequired"
>
</div>
<div
v-if="v$.user.email.$dirty"
class="form-error"
>
<ul>
<li v-if="!v$.user.email.required">
<span>{{ $t('registration.validations.email_required') }}</span>
</li>
</ul>
</div>
<div class="form-group">
<label
class="form--label"
for="bio"
>{{ $t('registration.bio_optional') }}</label>
<textarea
id="bio"
v-model="user.bio"
:disabled="isPending"
class="input form-control"
:placeholder="bioPlaceholder"
/>
</div>
<div
class="form-group"
:class="{ 'form-group--error': v$.user.password.$error }"
>
<label
class="form--label"
for="sign-up-password"
>{{ $t('login.password') }}</label>
<input
id="sign-up-password"
v-model="user.password"
:disabled="isPending"
class="input form-control"
type="password"
:aria-required="true"
>
</div>
<div
v-if="v$.user.password.$dirty"
class="form-error"
>
<ul>
<li v-if="!v$.user.password.required">
<span>{{ $t('registration.validations.password_required') }}</span>
</li>
</ul>
</div>
<div
class="form-group"
:class="{ 'form-group--error': v$.user.confirm.$error }"
>
<label
class="form--label"
for="sign-up-password-confirmation"
>{{ $t('registration.password_confirm') }}</label>
<input
id="sign-up-password-confirmation"
v-model="user.confirm"
:disabled="isPending"
class="input form-control"
type="password"
:aria-required="true"
>
</div>
<div
v-if="v$.user.confirm.$dirty"
class="form-error"
>
<ul>
<li v-if="v$.user.confirm.required.$invalid">
<span>{{ $t('registration.validations.password_confirmation_required') }}</span>
</li>
<li v-if="v$.user.confirm.sameAs.$invalid">
<span>{{ $t('registration.validations.password_confirmation_match') }}</span>
</li>
</ul>
</div>
<div
class="form-group"
:class="{ 'form-group--error': v$.user.birthday.$error }"
>
<label
class="form--label"
for="sign-up-birthday"
>
{{ birthdayRequired ? $t('registration.birthday') : $t('registration.birthday_optional') }}
</label>
<input
id="sign-up-birthday"
v-model="user.birthday"
:disabled="isPending"
class="input form-control"
type="date"
:max="birthdayRequired ? birthdayMinAttr : undefined"
:aria-required="birthdayRequired"
>
</div>
<div
v-if="v$.user.birthday.$dirty"
class="form-error"
>
<ul>
<li v-if="v$.user.birthday.required.$invalid">
<span>{{ $t('registration.validations.birthday_required') }}</span>
</li>
<li v-if="v$.user.birthday.maxValue.$invalid">
<span>{{ $tc('registration.validations.birthday_min_age', { date: birthdayMinFormatted }) }}</span>
</li>
</ul>
</div>
<div
class="form-group"
:class="{ 'form-group--error': v$.user.language.$error }"
>
<interface-language-switcher
for="email-language"
:prompt-text="$t('registration.email_language')"
:language="v$.user.language.$model"
:set-language="val => v$.user.language.$model = val"
@click.stop.prevent
/>
</div>
<div
v-if="accountApprovalRequired"
class="form-group"
>
<label
class="form--label"
for="reason"
>{{ $t('registration.reason') }}</label>
<textarea
id="reason"
v-model="user.reason"
:disabled="isPending"
class="input form-control"
:placeholder="reasonPlaceholder"
/>
</div>
<div
v-if="captcha.type != 'none'"
id="captcha-group"
class="form-group"
>
<label
class="form--label"
for="captcha-label"
>{{ $t('registration.captcha') }}</label>
<template v-if="['kocaptcha', 'native'].includes(captcha.type)">
<img
:src="captcha.url"
@click="setCaptcha"
>
<sub>{{ $t('registration.new_captcha') }}</sub>
<input
id="captcha-answer"
v-model="captcha.solution"
:disabled="isPending"
class="input form-control"
type="text"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
>
</template>
</div>
<div
v-if="token"
class="form-group"
>
<label for="token">{{ $t('registration.token') }}</label>
<input
id="token"
v-model="token"
disabled="true"
class="input form-control"
type="text"
>
</div>
<div class="form-group">
<button
:disabled="isPending"
type="submit"
class="btn button-default"
>
{{ $t('registration.register') }}
</button>
</div>
</div>
<!-- eslint-disable vue/no-v-html -->
<div
class="terms-of-service"
v-html="termsOfService"
/>
<!-- eslint-enable vue/no-v-html -->
</div>
<div
v-if="serverValidationErrors.length"
class="form-group"
>
<div class="alert error">
<span
v-for="error in serverValidationErrors"
:key="error"
>{{ error }}</span>
</div>
</div>
</form>
</div>
<div v-else>
<p class="registration-notice">
{{ signUpNotice.message }}
</p>
</div>
</div>
</template>
<script src="./registration.js"></script>
<style lang="scss">
.registration-form {
display: flex;
flex-direction: column;
margin: 0.6em;
.container {
display: flex;
flex-direction: row;
> * {
min-width: 0;
}
}
.terms-of-service {
flex: 0 1 50%;
margin: 0.8em;
}
.text-fields {
margin-top: 0.6em;
flex: 1 0;
display: flex;
flex-direction: column;
}
textarea {
min-height: 100px;
resize: vertical;
}
.form-group {
display: flex;
flex-direction: column;
padding: 0.3em 0;
line-height: 2;
margin-bottom: 1em;
}
.form-group--error {
animation-name: shakeError;
animation-duration: 0.6s;
animation-timing-function: ease-in-out;
}
.form-group--error .form--label {
color: var(--cRed);
}
.form-error {
margin-top: -0.7em;
text-align: left;
span {
font-size: 0.85em;
}
}
.form-error ul {
list-style: none;
padding: 0 0 0 5px;
margin-top: 0;
li::before {
content: "• ";
}
}
form textarea {
line-height: 16px;
resize: vertical;
}
.captcha {
max-width: 350px;
margin-bottom: 0.4em;
}
.btn {
margin-top: 0.6em;
height: 2em;
}
.error {
text-align: center;
}
}
.registration-notice {
margin: 0.6em;
}
@media all and (max-width: 800px) {
.registration-form .container {
flex-direction: column-reverse;
}
}
</style>
diff --git a/src/components/remote_user_resolver/remote_user_resolver.vue b/src/components/remote_user_resolver/remote_user_resolver.vue
index 07aac169f9..cbd4d19c46 100644
--- a/src/components/remote_user_resolver/remote_user_resolver.vue
+++ b/src/components/remote_user_resolver/remote_user_resolver.vue
@@ -1,17 +1,19 @@
<template>
<div class="panel panel-default">
<div class="panel-heading">
- {{ $t('remote_user_resolver.remote_user_resolver') }}
+ <h1 class="title">
+ {{ $t('remote_user_resolver.remote_user_resolver') }}
+ </h1>
</div>
<div class="panel-body">
<p>
{{ $t('remote_user_resolver.searching_for') }} @{{ $route.params.username }}@{{ $route.params.hostname }}
</p>
<p v-if="error">
{{ $t('remote_user_resolver.error') }}
</p>
</div>
</div>
</template>
<script src="./remote_user_resolver.js"></script>
diff --git a/src/components/search/search.vue b/src/components/search/search.vue
index bd384ad3fc..00e700cfb7 100644
--- a/src/components/search/search.vue
+++ b/src/components/search/search.vue
@@ -1,225 +1,225 @@
<template>
<div class="Search panel panel-default">
<div class="panel-heading">
- <div class="title">
+ <h1 class="title">
{{ $t('nav.search') }}
- </div>
+ </h1>
</div>
<div class="panel-body search-input-container">
<input
ref="searchInput"
v-model="searchTerm"
class="input search-input"
:placeholder="$t('nav.search')"
@keyup.enter="newQuery(searchTerm)"
>
<button
class="btn button-default search-button"
type="submit"
@click="newQuery(searchTerm)"
>
<FAIcon icon="search" />
</button>
</div>
<div
v-if="loading && statusesOffset == 0"
class="panel-body text-center loading-icon"
>
<FAIcon
icon="circle-notch"
spin
size="lg"
/>
</div>
<div v-else-if="loaded">
<div class="search-nav-heading">
<tab-switcher
ref="tabSwitcher"
:on-switch="onResultTabSwitch"
:active-tab="currenResultTab"
>
<span
key="statuses"
:label="$t('user_card.statuses') + resultCount('visibleStatuses')"
/>
<span
key="people"
:label="$t('search.people') + resultCount('users')"
/>
<span
key="hashtags"
:label="$t('search.hashtags') + resultCount('hashtags')"
/>
</tab-switcher>
</div>
</div>
<div class="panel-body">
<div v-if="currenResultTab === 'statuses'">
<Status
v-for="status in visibleStatuses"
:key="status.id"
:collapsable="false"
:expandable="false"
:compact="false"
class="search-result"
:statusoid="status"
:no-heading="false"
/>
<button
v-if="!loading && loaded && lastStatusFetchCount > 0"
class="more-statuses-button button-unstyled -link"
@click.prevent="search(searchTerm, 'statuses')"
>
<div class="new-status-notification text-center">
{{ $t('search.load_more') }}
</div>
</button>
<div
v-else-if="loading && statusesOffset > 0"
class="text-center loading-icon"
>
<FAIcon
icon="circle-notch"
spin
size="lg"
/>
</div>
<div
v-if="(visibleStatuses.length === 0 || lastStatusFetchCount === 0) && !loading && loaded"
class="search-result-heading"
>
<h4>
{{ visibleStatuses.length === 0 ? $t('search.no_results') : $t('search.no_more_results') }}
</h4>
</div>
</div>
<div v-else-if="currenResultTab === 'people'">
<div
v-if="users.length === 0 && !loading && loaded"
class="search-result-heading"
>
<h4>{{ $t('search.no_results') }}</h4>
</div>
<FollowCard
v-for="user in users"
:key="user.id"
:user="user"
class="list-item search-result"
/>
</div>
<div v-else-if="currenResultTab === 'hashtags'">
<div
v-if="hashtags.length === 0 && !loading && loaded"
class="search-result-heading"
>
<h4>{{ $t('search.no_results') }}</h4>
</div>
<div
v-for="hashtag in hashtags"
:key="hashtag.url"
class="status trend search-result"
>
<div class="hashtag">
<router-link :to="{ name: 'tag-timeline', params: { tag: hashtag.name } }">
#{{ hashtag.name }}
</router-link>
<div v-if="lastHistoryRecord(hashtag)">
<span v-if="lastHistoryRecord(hashtag).accounts == 1">
{{ $t('search.person_talking', { count: lastHistoryRecord(hashtag).accounts }) }}
</span>
<span v-else>
{{ $t('search.people_talking', { count: lastHistoryRecord(hashtag).accounts }) }}
</span>
</div>
</div>
<div
v-if="lastHistoryRecord(hashtag)"
class="count"
>
{{ lastHistoryRecord(hashtag).uses }}
</div>
</div>
</div>
</div>
<div class="search-result-footer text-center panel-footer faint" />
</div>
</template>
<script src="./search.js"></script>
<style lang="scss">
.search-result-heading {
color: var(--faint);
padding: 0.75rem;
text-align: center;
}
@media all and (max-width: 800px) {
.search-nav-heading {
.tab-switcher .tabs .tab-wrapper {
display: block;
justify-content: center;
flex: 1 1 auto;
text-align: center;
}
}
}
.search-result {
box-sizing: border-box;
border-bottom: 1px solid;
border-color: var(--border);
}
.search-input-container {
padding: 0.8rem;
display: flex;
justify-content: center;
.search-input {
width: 100%;
line-height: 1.125rem;
font-size: 1rem;
padding: 0.5rem;
box-sizing: border-box;
}
.search-button {
margin-left: 0.5em;
}
}
.loading-icon {
padding: 1em;
}
.trend {
display: flex;
align-items: center;
.hashtag {
flex: 1 1 auto;
color: var(--text);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.count {
flex: 0 0 auto;
width: 2rem;
font-size: 1.5rem;
line-height: 2.25rem;
font-weight: 500;
text-align: center;
color: var(--text);
}
}
.more-statuses-button {
height: 3.5em;
line-height: 3.5em;
width: 100%;
}
</style>
diff --git a/src/components/settings_modal/settings_modal.vue b/src/components/settings_modal/settings_modal.vue
index 90dbbde0a0..b9f7c3557e 100644
--- a/src/components/settings_modal/settings_modal.vue
+++ b/src/components/settings_modal/settings_modal.vue
@@ -1,167 +1,167 @@
<template>
<Modal
:is-open="modalActivated"
class="settings-modal"
:class="{ peek: modalPeeked }"
:no-background="modalPeeked"
>
<div class="settings-modal-panel panel">
<div class="panel-heading">
- <span class="title">
+ <h1 class="title">
{{ modalMode === 'user' ? $t('settings.settings') : $t('admin_dash.window_title') }}
- </span>
+ </h1>
<transition name="fade">
<div
v-if="currentSaveStateNotice"
class="alert"
:class="{ success: !currentSaveStateNotice.error, error: currentSaveStateNotice.error}"
@click.prevent
>
{{ currentSaveStateNotice.error ? $t('settings.saving_err') : $t('settings.saving_ok') }}
</div>
</transition>
<button
class="btn button-default"
:title="$t('general.peek')"
@click="peekModal"
>
<FAIcon
:icon="['far', 'window-minimize']"
fixed-width
/>
</button>
<button
class="btn button-default"
:title="$t('general.close')"
@click="closeModal"
>
<FAIcon
icon="times"
fixed-width
/>
</button>
</div>
<div class="panel-body">
<SettingsModalUserContent v-if="modalMode === 'user' && modalOpenedOnceUser" />
<SettingsModalAdminContent v-if="modalMode === 'admin' && modalOpenedOnceAdmin" />
</div>
<div class="panel-footer settings-footer -flexible-height">
<Popover
v-if="modalMode === 'user'"
class="export"
trigger="click"
placement="top"
:offset="{ y: 5, x: 5 }"
:bound-to="{ x: 'container' }"
remove-padding
>
<template #trigger>
<button
class="btn button-default"
:title="$t('general.close')"
>
<span>{{ $t("settings.file_export_import.backup_restore") }}</span>
{{ ' ' }}
<FAIcon
icon="chevron-down"
/>
</button>
</template>
<template #content="{close}">
<div class="dropdown-menu">
<button
class="menu-item dropdown-item dropdown-item-icon"
@click.prevent="backup"
@click="close"
>
<FAIcon
icon="file-download"
fixed-width
/><span>{{ $t("settings.file_export_import.backup_settings") }}</span>
</button>
<button
class="menu-item dropdown-item dropdown-item-icon"
@click.prevent="backupWithTheme"
@click="close"
>
<FAIcon
icon="file-download"
fixed-width
/><span>{{ $t("settings.file_export_import.backup_settings_theme") }}</span>
</button>
<button
class="menu-item dropdown-item dropdown-item-icon"
@click.prevent="restore"
@click="close"
>
<FAIcon
icon="file-upload"
fixed-width
/><span>{{ $t("settings.file_export_import.restore_settings") }}</span>
</button>
</div>
</template>
</Popover>
<Checkbox
:model-value="!!expertLevel"
@update:modelValue="expertLevel = Number($event)"
>
{{ $t("settings.expert_mode") }}
</Checkbox>
<span v-if="modalMode === 'admin'">
<i18n-t keypath="admin_dash.wip_notice">
<template #adminFeLink>
<a
href="/pleroma/admin/#/login-pleroma"
target="_blank"
>
{{ $t("admin_dash.old_ui_link") }}
</a>
</template>
</i18n-t>
</span>
<span
id="unscrolled-content"
class="extra-content"
/>
<span
v-if="modalMode === 'admin'"
class="admin-buttons"
>
<button
class="button-default btn"
:disabled="!adminDraftAny"
@click="resetAdminDraft"
>
{{ $t("admin_dash.reset_all") }}
</button>
{{ ' ' }}
<button
class="button-default btn"
:disabled="!adminDraftAny"
@click="pushAdminDraft"
>
{{ $t("admin_dash.commit_all") }}
</button>
</span>
</div>
</div>
<teleport to="#modal">
<ConfirmModal
v-if="$store.state.interface.temporaryChangesTimeoutId"
:title="$t('settings.confirm_new_setting')"
:cancel-text="$t('settings.revert')"
:confirm-text="$t('settings.confirm')"
@cancelled="$store.state.interface.temporaryChangesRevert"
@accepted="$store.state.interface.temporaryChangesConfirm"
>
{{ $t('settings.confirm_new_question') }}
</ConfirmModal>
</teleport>
</Modal>
</template>
<script src="./settings_modal.js"></script>
<style src="./settings_modal.scss" lang="scss"></style>
diff --git a/src/components/settings_modal/tabs/theme_tab/theme_preview.vue b/src/components/settings_modal/tabs/theme_tab/theme_preview.vue
index dbaecee459..4446c18b96 100644
--- a/src/components/settings_modal/tabs/theme_tab/theme_preview.vue
+++ b/src/components/settings_modal/tabs/theme_tab/theme_preview.vue
@@ -1,250 +1,250 @@
<template>
<div class="theme-preview-container">
<div class="underlay underlay-preview" />
<div class="panel dummy">
<div class="panel-heading">
- <div class="title">
+ <h1 class="title">
{{ $t('settings.style.preview.header') }}
<span class="badge -notification">
99
</span>
- </div>
+ </h1>
<span class="faint">
{{ $t('settings.style.preview.header_faint') }}
</span>
<span class="alert error">
{{ $t('settings.style.preview.error') }}
</span>
<button class="btn button-default">
{{ $t('settings.style.preview.button') }}
</button>
</div>
<div class="panel-body theme-preview-content">
<div class="post">
<div class="avatar still-image">
( ͡° ͜ʖ ͡°)
</div>
<div class="content">
<h4>
{{ $t('settings.style.preview.content') }}
</h4>
<i18n-t
scope="global"
keypath="settings.style.preview.text"
>
<code style="font-family: var(--postCodeFont);">
{{ $t('settings.style.preview.mono') }}
</code>
<a style="color: var(--link);">
{{ $t('settings.style.preview.link') }}
</a>
</i18n-t>
<div class="icons">
<FAIcon
fixed-width
style="color: var(--cBlue);"
class="fa-scale-110 fa-old-padding"
icon="reply"
/>
<FAIcon
fixed-width
style="color: var(--cGreen);"
class="fa-scale-110 fa-old-padding"
icon="retweet"
/>
<FAIcon
fixed-width
style="color: var(--cOrange);"
class="fa-scale-110 fa-old-padding"
icon="star"
/>
<FAIcon
fixed-width
style="color: var(--cRed);"
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</div>
</div>
</div>
<div class="after-post">
<div class="avatar-alt">
:^)
</div>
<div class="content">
<i18n-t
keypath="settings.style.preview.fine_print"
tag="span"
class="faint"
scope="global"
>
<a style="color: var(--linkFaint);">
{{ $t('settings.style.preview.faint_link') }}
</a>
</i18n-t>
</div>
</div>
<div class="separator" />
<span class="alert error">
{{ $t('settings.style.preview.error') }}
</span>
<input
:value="$t('settings.style.preview.input')"
type="text"
class="input"
>
<div class="actions">
<Checkbox>
{{ $t('settings.style.preview.checkbox') }}
</Checkbox>
<button class="btn button-default">
{{ $t('settings.style.preview.button') }}
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import Checkbox from 'src/components/checkbox/checkbox.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faTimes,
faStar,
faRetweet,
faReply
} from '@fortawesome/free-solid-svg-icons'
library.add(
faTimes,
faStar,
faRetweet,
faReply
)
export default {
components: {
Checkbox
}
}
</script>
<style lang="scss">
.theme-preview-container {
position: relative;
border-top: 1px dashed;
border-bottom: 1px dashed;
border-color: var(--border);
margin: 1em 0;
padding: 1em;
background-color: var(--wallpaper);
background-image: var(--body-background-image);
background-size: cover;
background-position: 50% 50%;
.theme-preview-content {
padding: 20px;
}
.dummy {
.post {
font-family: var(--postFont);
display: flex;
.content {
flex: 1;
h4 {
margin-bottom: 0.25em;
}
.icons {
margin-top: 0.5em;
display: flex;
i {
margin-right: 1em;
}
}
}
}
.after-post {
margin-top: 1em;
display: flex;
align-items: center;
}
.avatar,
.avatar-alt {
background:
linear-gradient(
135deg,
#b8e1fc 0%,
#a9d2f3 10%,
#90bae4 25%,
#90bcea 37%,
#90bff0 50%,
#6ba8e5 51%,
#a2daf5 83%,
#bdf3fd 100%
);
color: black;
font-family: sans-serif;
text-align: center;
margin-right: 1em;
}
.avatar-alt {
flex: 0 auto;
margin-left: 28px;
font-size: 12px;
min-width: 20px;
min-height: 20px;
line-height: 20px;
}
.avatar {
flex: 0 auto;
width: 48px;
height: 48px;
font-size: 14px;
line-height: 48px;
}
.actions {
display: flex;
align-items: baseline;
.checkbox {
margin-right: 1em;
flex: 1;
}
}
.separator {
margin: 1em;
border-bottom: 1px solid;
border-color: var(--border);
}
.btn {
min-width: 3em;
}
}
.underlay-preview {
position: absolute;
top: 0;
bottom: 0;
left: 10px;
right: 10px;
}
}
</style>
diff --git a/src/components/shout_panel/shout_panel.vue b/src/components/shout_panel/shout_panel.vue
index 9113211eb9..67927df88b 100644
--- a/src/components/shout_panel/shout_panel.vue
+++ b/src/components/shout_panel/shout_panel.vue
@@ -1,152 +1,152 @@
<template>
<div
v-if="!collapsed || !floating"
class="shout-panel"
>
<div class="panel panel-default">
<div
class="panel-heading"
:class="{ 'shout-heading': floating }"
@click.stop.prevent="togglePanel"
>
- <div class="title">
+ <h1 class="title">
{{ $t('shoutbox.title') }}
<FAIcon
v-if="floating"
icon="times"
class="close-icon"
/>
- </div>
+ </h1>
</div>
<div class="panel-body shout-window">
<div
v-for="message in messages"
:key="message.id"
class="shout-message"
>
<span class="shout-avatar">
<img :src="message.author.avatar">
</span>
<div class="shout-content">
<router-link
class="shout-name"
:to="userProfileLink(message.author)"
>
{{ message.author.username }}
</router-link>
<br>
<span class="shout-text">
{{ message.text }}
</span>
</div>
</div>
</div>
<div class="panel-body shout-input">
<textarea
v-model="currentMessage"
class="shout-input-textarea input"
rows="1"
@keyup.enter="submit(currentMessage)"
/>
</div>
</div>
</div>
<div
v-else
class="shout-panel"
>
<div class="panel panel-default">
<div
class="panel-heading -stub timeline-heading shout-heading"
@click.stop.prevent="togglePanel"
>
<div class="title">
<FAIcon
class="icon"
icon="bullhorn"
/>
{{ $t('shoutbox.title') }}
</div>
</div>
</div>
</div>
</template>
<script src="./shout_panel.js"></script>
<style lang="scss">
.floating-shout {
position: fixed;
bottom: 0.5em;
z-index: var(--ZI_popovers);
max-width: 25em;
&.-left {
left: 0.5em;
}
&:not(.-left) {
right: 0.5em;
}
}
.shout-panel {
.shout-heading {
cursor: pointer;
.icon {
color: var(--text);
margin-right: 0.5em;
}
.title {
display: flex;
justify-content: space-between;
align-items: center;
}
}
.shout-window {
overflow-y: auto;
overflow-x: hidden;
max-height: 20em;
}
.shout-window-container {
height: 100%;
}
.shout-message {
display: flex;
padding: 0.2em 0.5em;
}
.shout-avatar {
img {
height: 24px;
width: 24px;
border-radius: var(--roundness);
margin-right: 0.5em;
margin-top: 0.25em;
}
}
.shout-input {
display: flex;
textarea {
flex: 1;
margin: 0.6em;
min-height: 3.5em;
resize: none;
}
}
.shout-panel {
.title {
display: flex;
justify-content: space-between;
}
}
}
</style>
diff --git a/src/components/status_history_modal/status_history_modal.vue b/src/components/status_history_modal/status_history_modal.vue
index 79642e9c87..d89f495995 100644
--- a/src/components/status_history_modal/status_history_modal.vue
+++ b/src/components/status_history_modal/status_history_modal.vue
@@ -1,47 +1,49 @@
<template>
<Modal
v-if="modalActivated"
class="status-history-modal-view"
@backdropClicked="closeModal"
>
<div class="status-history-modal-panel panel">
<div class="panel-heading">
- {{ $t('status.status_history') }} ({{ historyCount }})
+ <h1 class="title">
+ {{ $t('status.status_history') }} ({{ historyCount }})
+ </h1>
</div>
<div class="panel-body">
<div
v-if="historyCount > 0"
class="history-body"
>
<status
v-for="status in history"
:key="status.id"
:statusoid="status"
:is-preview="true"
class="conversation-status status-fadein panel-body"
/>
</div>
</div>
</div>
</Modal>
</template>
<script src="./status_history_modal.js"></script>
<style lang="scss">
.modal-view.status-history-modal-view {
align-items: flex-start;
}
.status-history-modal-panel {
flex-shrink: 0;
margin-top: 25%;
margin-bottom: 2em;
width: 100%;
max-width: 700px;
@media (orientation: landscape) {
margin-top: 8%;
}
}
</style>
diff --git a/src/components/timeline_menu/timeline_menu.vue b/src/components/timeline_menu/timeline_menu.vue
index bdcfb73d65..717c8a8e8a 100644
--- a/src/components/timeline_menu/timeline_menu.vue
+++ b/src/components/timeline_menu/timeline_menu.vue
@@ -1,112 +1,112 @@
<template>
<Popover
trigger="click"
class="TimelineMenu"
:class="{ 'open': isOpen }"
:bound-to="{ x: 'container' }"
bound-to-selector=".Timeline"
popover-class="timeline-menu-popover popover-default"
@show="openMenu"
@close="() => isOpen = false"
>
<template #content>
<ListsMenuContent
v-if="useListsMenu"
:show-pin="false"
class="timelines"
/>
<BookmarkFoldersMenuContent
v-else-if="useBookmarkFoldersMenu"
class="timelines"
/>
<ul v-else>
<NavigationEntry
v-for="item in timelinesList"
:key="item.name"
:show-pin="false"
:item="item"
/>
</ul>
</template>
<template #trigger>
- <span class="button-unstyled title timeline-menu-title">
- <span class="timeline-title">{{ timelineName() }}</span>
+ <span class="button-unstyled timeline-menu-title">
+ <h1 class="title timeline-title">{{ timelineName() }}</h1>
<span>
<FAIcon
size="sm"
icon="chevron-down"
/>
</span>
<span
class="click-blocker"
@click="blockOpen"
/>
</span>
</template>
</Popover>
</template>
<script src="./timeline_menu.js"></script>
<style lang="scss">
.timeline-menu-popover {
min-width: 24rem;
max-width: 100vw;
margin-top: 0.6rem;
font-size: 1rem;
border-top-right-radius: 0;
border-top-left-radius: 0;
ul {
list-style: none;
margin: 0;
padding: 0;
}
}
.TimelineMenu {
margin-right: auto;
min-width: 0;
.popover-trigger-button {
vertical-align: bottom;
}
.panel::after {
border-top-right-radius: 0;
border-top-left-radius: 0;
}
.timeline-menu-title {
margin: 0;
cursor: pointer;
user-select: none;
width: 100%;
display: flex;
.timeline-menu-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
svg {
margin-left: 0.6em;
transition: transform 100ms;
}
.click-blocker {
cursor: default;
flex-grow: 1;
}
}
&.open .timeline-menu-title svg {
transform: rotate(180deg);
}
.panel {
box-shadow: var(--popoverShadow);
}
}
</style>
diff --git a/src/components/update_notification/update_notification.vue b/src/components/update_notification/update_notification.vue
index 78e70a743d..6fc363d41b 100644
--- a/src/components/update_notification/update_notification.vue
+++ b/src/components/update_notification/update_notification.vue
@@ -1,103 +1,103 @@
<template>
<Modal
:is-open="!!shouldShow"
class="UpdateNotification"
:no-background="true"
>
<div
class="UpdateNotificationModal panel"
:class="{ '-peek': !showingMore }"
>
<div class="panel-heading">
- <span class="title">
+ <h1 class="title">
{{ $t('update.big_update_title') }}
- </span>
+ </h1>
</div>
<div class="panel-body">
<div
class="content"
:class="{ '-noImage': !showingImage }"
>
<img
v-if="showingImage"
class="pleroma-tan"
:src="pleromaTanVariant"
:style="pleromaTanStyles"
>
<div class="spacer-top" />
<div class="text">
<p>
{{ $t('update.big_update_content') }}
</p>
<div
ref="animatedText"
class="extra-info-group"
>
<i18n-t
keypath="update.update_bugs"
tag="p"
>
<template #pleromaGitlab>
<a
target="_blank"
href="https://git.pleroma.social/"
>{{ $t('update.update_bugs_gitlab') }}</a>
</template>
</i18n-t>
<i18n-t
keypath="update.update_changelog"
tag="p"
>
<template #theFullChangelog>
<a
target="_blank"
href="https://pleroma.social/announcements/"
>{{ $t('update.update_changelog_here') }}</a>
</template>
</i18n-t>
<p class="art-credit">
<i18n-t
keypath="update.art_by"
tag="small"
>
<template #linkToArtist>
<a
target="_blank"
href="https://post.ebin.club/users/pipivovott"
>pipivovott</a>
</template>
</i18n-t>
</p>
</div>
</div>
<div class="spacer-bottom" />
</div>
</div>
<div class="panel-footer">
<button
class="button-default"
@click.prevent="neverShowAgain"
>
{{ $t("general.never_show_again") }}
</button>
<button
v-if="!showingMore"
class="button-default"
@click.prevent="toggleShow"
>
{{ $t("general.show_more") }}
</button>
<button
class="button-default"
@click.prevent="dismiss"
>
{{ $t("general.dismiss") }}
</button>
</div>
</div>
</Modal>
</template>
<script src="./update_notification.js"></script>
<style src="./update_notification.scss" lang="scss"></style>
diff --git a/src/components/user_link/user_link.vue b/src/components/user_link/user_link.vue
index efd96e12ab..80b941d32b 100644
--- a/src/components/user_link/user_link.vue
+++ b/src/components/user_link/user_link.vue
@@ -1,38 +1,42 @@
<template>
- <router-link
- :title="user.screen_name_ui"
- :to="userProfileLink(user)"
- >
- {{ at ? '@' : '' }}{{ user.screen_name_ui }}<UnicodeDomainIndicator
- :user="user"
- />
- </router-link>
+ <div class="user-profile-link">
+ <router-link
+ :title="user.screen_name_ui"
+ :to="userProfileLink(user)"
+ >
+ <slot>
+ {{ at ? '@' : '' }}{{ user.screen_name_ui }}<UnicodeDomainIndicator
+ :user="user"
+ />
+ </slot>
+ </router-link>
+ </div>
</template>
<script>
import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
const UserLink = {
props: {
user: Object,
at: {
type: Boolean,
default: true
}
},
components: {
UnicodeDomainIndicator
},
methods: {
userProfileLink (user) {
return generateProfileLink(
user.id, user.screen_name,
this.$store.state.instance.restrictedNicknames
)
}
}
}
export default UserLink
</script>
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 1ec12d0ceb..86b211bfde 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -1,240 +1,240 @@
<template>
<div>
<div
v-if="user"
class="user-profile panel panel-default"
>
<div class="panel-body">
<UserCard
:user-id="userId"
:switcher="true"
:selected="timeline.viewing"
avatar-action="zoom"
rounded="top"
:has-note-editor="true"
/>
<span
v-if="!!user.birthday"
class="user-birthday"
>
<FAIcon
class="fa-old-padding"
icon="birthday-cake"
/>
{{ $t('user_card.birthday', { birthday: formattedBirthday }) }}
</span>
<div
v-if="user.fields_html && user.fields_html.length > 0"
class="user-profile-fields"
>
<dl
v-for="(field, index) in user.fields_html"
:key="index"
class="user-profile-field"
>
<dt
:title="user.fields_text[index].name"
class="user-profile-field-name"
>
<RichContent
:html="field.name"
:emoji="user.emoji"
/>
</dt>
<dd
:title="user.fields_text[index].value"
class="user-profile-field-value"
>
<RichContent
:html="field.value"
:emoji="user.emoji"
/>
</dd>
</dl>
</div>
</div>
<tab-switcher
:active-tab="tab"
:render-only-focused="true"
:on-switch="onTabSwitch"
>
<Timeline
key="statuses"
:label="$t('user_card.statuses')"
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="timeline"
timeline-name="user"
:user-id="userId"
:pinned-status-ids="user.pinnedStatusIds"
:in-profile="true"
:footer-slipgate="footerRef"
/>
<div
v-if="followsTabVisible"
key="followees"
class="panel-body"
:label="$t('user_card.followees')"
:disabled="!user.friends_count"
>
<FriendList
:user-id="userId"
:non-interactive="true"
>
<template #item="{item}">
<FollowCard :user="item" />
</template>
</FriendList>
</div>
<div
v-if="followersTabVisible"
key="followers"
class="panel-body"
:label="$t('user_card.followers')"
:disabled="!user.followers_count"
>
<FollowerList
:user-id="userId"
:non-interactive="true"
>
<template #item="{item}">
<FollowCard
:user="item"
:no-follows-you="isUs"
/>
</template>
</FollowerList>
</div>
<Timeline
key="media"
:label="$t('user_card.media')"
:disabled="!media.visibleStatuses.length"
:embedded="true"
:title="$t('user_card.media')"
timeline-name="media"
:timeline="media"
:user-id="userId"
:in-profile="true"
:footer-slipgate="footerRef"
/>
<Timeline
v-if="favoritesTabVisible"
key="favorites"
:label="$t('user_card.favorites')"
:disabled="!favorites.visibleStatuses.length"
:embedded="true"
:title="$t('user_card.favorites')"
timeline-name="favorites"
:timeline="favorites"
:user-id="isUs ? undefined : userId"
:in-profile="true"
:footer-slipgate="footerRef"
/>
</tab-switcher>
<div
:ref="setFooterRef"
class="panel-footer"
/>
</div>
<div
v-else
class="panel user-profile-placeholder"
>
<div class="panel-heading">
- <div class="title">
+ <h1 class="title">
{{ $t('settings.profile_tab') }}
- </div>
+ </h1>
</div>
<div>
<span v-if="error">{{ error }}</span>
<FAIcon
v-else
spin
icon="circle-notch"
/>
</div>
</div>
</div>
</template>
<script src="./user_profile.js"></script>
<style lang="scss">
.user-profile {
flex: 2;
flex-basis: 500px;
// No sticky header on user profile
--currentPanelStack: 1;
.user-birthday {
margin: 0 0.75em 0.5em;
}
.user-profile-fields {
margin: 0 0.5em;
img {
object-fit: contain;
vertical-align: middle;
max-width: 100%;
max-height: 400px;
&.emoji {
width: 18px;
height: 18px;
}
}
.user-profile-field {
display: flex;
margin: 0.25em;
border: 1px solid var(--border);
border-radius: var(--roundness);
.user-profile-field-name {
flex: 0 1 30%;
font-weight: 500;
text-align: right;
color: var(--lightText);
min-width: 120px;
border-right: 1px solid var(--border);
}
.user-profile-field-value {
flex: 1 1 70%;
color: var(--text);
margin: 0 0 0 0.25em;
}
.user-profile-field-name,
.user-profile-field-value {
line-height: 1.3;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
padding: 0.5em 1.5em;
box-sizing: border-box;
}
}
}
.userlist-placeholder {
display: flex;
justify-content: center;
align-items: middle;
padding: 2em;
}
}
.user-profile-placeholder {
.panel-body {
display: flex;
justify-content: center;
align-items: middle;
padding: 7em;
}
}
</style>
diff --git a/src/components/user_reporting_modal/user_reporting_modal.vue b/src/components/user_reporting_modal/user_reporting_modal.vue
index 2bda509a48..100d1e7f74 100644
--- a/src/components/user_reporting_modal/user_reporting_modal.vue
+++ b/src/components/user_reporting_modal/user_reporting_modal.vue
@@ -1,170 +1,170 @@
<template>
<Modal
v-if="isOpen"
@backdropClicked="closeModal"
>
<div class="user-reporting-panel panel">
<div class="panel-heading">
<i18n-t
- tag="div"
+ tag="h1"
keypath="user_reporting.title"
class="title"
>
<UserLink :user="user" />
</i18n-t>
</div>
<div class="panel-body">
<div class="user-reporting-panel-left">
<div>
<p>{{ $t('user_reporting.add_comment_description') }}</p>
<textarea
v-model="comment"
class="input form-control"
:placeholder="$t('user_reporting.additional_comments')"
rows="1"
@input="resize"
/>
</div>
<div v-if="!user.is_local">
<p>{{ $t('user_reporting.forward_description') }}</p>
<Checkbox v-model="forward">
{{ $t('user_reporting.forward_to', [remoteInstance]) }}
</Checkbox>
</div>
<div>
<button
class="btn button-default"
:disabled="processing"
@click="reportUser"
>
{{ $t('user_reporting.submit') }}
</button>
<div
v-if="error"
class="alert error"
>
{{ $t('user_reporting.generic_error') }}
</div>
</div>
</div>
<div class="user-reporting-panel-right">
<List :items="statuses">
<template #item="{item}">
<div class="status-fadein user-reporting-panel-sitem">
<Status
:in-conversation="false"
:focused="false"
:statusoid="item"
/>
<Checkbox
:model-value="isChecked(item.id)"
@update:model-value="checked => toggleStatus(checked, item.id)"
/>
</div>
</template>
</List>
</div>
</div>
</div>
</Modal>
</template>
<script src="./user_reporting_modal.js"></script>
<style lang="scss">
.user-reporting-panel {
width: 90vw;
max-width: 700px;
min-height: 20vh;
max-height: 80vh;
.panel-body {
display: flex;
flex-direction: column-reverse;
border-top: 1px solid;
border-color: var(--border);
overflow: hidden;
}
&-left {
padding: 1.1em 0.7em 0.7em;
line-height: var(--post-line-height);
box-sizing: border-box;
> div {
margin-bottom: 1em;
&:last-child {
margin-bottom: 0;
}
}
p {
margin-top: 0;
}
textarea.form-control {
line-height: 16px;
resize: none;
overflow: hidden;
transition: min-height 200ms 100ms;
min-height: 44px;
width: 100%;
}
.btn {
min-width: 10em;
padding: 0 2em;
}
.alert {
margin: 1em 0 0;
line-height: 1.3em;
}
}
&-right {
display: flex;
flex-direction: column;
overflow-y: auto;
}
&-sitem {
display: flex;
justify-content: space-between;
/* TODO cleanup this */
> .Status {
flex: 1;
}
> .checkbox {
margin: 0.75em;
}
}
@media all and (min-width: 801px) {
.panel-body {
flex-direction: row;
}
&-left {
width: 50%;
max-width: 320px;
border-right: 1px solid;
border-color: var(--border);
padding: 1.1em;
> div {
margin-bottom: 2em;
}
}
&-right {
width: 50%;
flex: 1 1 auto;
margin-bottom: 12px;
}
}
}
</style>
diff --git a/src/components/who_to_follow/who_to_follow.vue b/src/components/who_to_follow/who_to_follow.vue
index 56543d91bf..7cb4d47664 100644
--- a/src/components/who_to_follow/who_to_follow.vue
+++ b/src/components/who_to_follow/who_to_follow.vue
@@ -1,17 +1,19 @@
<template>
<div class="panel panel-default">
<div class="panel-heading">
- {{ $t('who_to_follow.who_to_follow') }}
+ <h1 class="title">
+ {{ $t('who_to_follow.who_to_follow') }}
+ </h1>
</div>
<div class="panel-body">
<FollowCard
v-for="user in users"
:key="user.id"
:user="user"
class="list-item"
/>
</div>
</div>
</template>
<script src="./who_to_follow.js"></script>
diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.vue b/src/components/who_to_follow_panel/who_to_follow_panel.vue
index 0fecec0bde..92d6f6d7ce 100644
--- a/src/components/who_to_follow_panel/who_to_follow_panel.vue
+++ b/src/components/who_to_follow_panel/who_to_follow_panel.vue
@@ -1,60 +1,60 @@
<template>
<div class="who-to-follow-panel">
<div class="panel panel-default base01-background">
<div class="panel-heading timeline-heading base02-background base04">
- <div class="title">
+ <h1 class="title">
{{ $t('who_to_follow.who_to_follow') }}
- </div>
+ </h1>
</div>
<div class="who-to-follow">
<p
v-for="user in usersToFollow"
:key="user.id"
class="who-to-follow-items"
>
<img :src="user.img">
<router-link :to="userProfileLink(user.id, user.name)">
{{ user.name }}
</router-link><br>
</p>
<p class="who-to-follow-more">
<router-link :to="{ name: 'who-to-follow' }">
{{ $t('who_to_follow.more') }}
</router-link>
</p>
</div>
</div>
</div>
</template>
<script src="./who_to_follow_panel.js"></script>
<style lang="scss">
.who-to-follow * {
vertical-align: middle;
}
.who-to-follow img {
width: 32px;
height: 32px;
}
.who-to-follow {
padding: 0 1em;
margin: 0;
}
.who-to-follow-items {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0;
margin: 1em 0;
}
.who-to-follow-more {
padding: 0;
margin: 1em 0;
text-align: center;
}
</style>
diff --git a/src/panel.scss b/src/panel.scss
index e974e7f6d1..47d55aa4a1 100644
--- a/src/panel.scss
+++ b/src/panel.scss
@@ -1,210 +1,212 @@
/* stylelint-disable no-descending-specificity */
.panel {
--__panel-background: var(--background);
--__panel-backdrop-filter: var(--backdrop-filter);
.tab-switcher .tabs {
background: var(--__panel-background);
backdrop-filter: var(--__panel-backdrop-filter);
}
position: relative;
display: flex;
flex-direction: column;
.panel-heading {
background-color: inherit;
}
&::after,
& {
border-radius: var(--roundness);
}
&::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 5;
box-shadow: var(--shadow);
pointer-events: none;
}
}
.panel-body {
padding: var(--panel-body-padding, 0);
background: var(--background);
backdrop-filter: var(--__panel-backdrop-filter);
.tab-switcher .tabs {
background: none;
backdrop-filter: none;
}
&:empty::before {
content: "¯\\_(ツ)_/¯"; // Could use words but it'd require translations
display: block;
padding: 1em;
text-align: center;
}
> p {
line-height: 1.3;
padding: 1em;
margin: 0;
}
}
.panel-heading,
.panel-footer {
--panel-heading-height-padding: calc(var(--panel-header-height) * 0.2);
--__panel-heading-gap: calc(var(--panel-header-height) * 0.1565);
--__panel-heading-height: var(--panel-header-height);
--__panel-heading-height-inner: calc(var(--__panel-heading-height) - 2 * var(--panel-heading-height-padding, 0));
font-size: calc(var(--panelHeaderSize) / 3.2);
backdrop-filter: var(--__panel-backdrop-filter);
position: relative;
box-sizing: border-box;
display: grid;
grid-auto-flow: column;
grid-template-columns: minmax(50%, 1fr);
grid-auto-columns: auto;
grid-column-gap: var(--__panel-heading-gap);
flex: none;
background-size: cover;
padding: var(--panel-heading-height-padding);
height: var(--__panel-heading-height);
line-height: var(--__panel-heading-height-inner);
z-index: 4;
&.-flexible-height {
--__panel-heading-height: auto;
&::after,
&::before {
display: none;
}
}
&.-stub {
&,
&::after {
border-radius: var(--roundness);
}
}
&.-sticky {
position: sticky;
top: var(--navbar-height);
}
&::after,
&::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
pointer-events: none;
}
.title {
font-size: 1.3em;
+ margin: 0;
+ font-weight: normal;
}
.alert {
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;
}
&:not(.-flexible-height) {
> .button-default,
> .alert {
height: var(--__panel-heading-height-inner);
min-height: 0;
box-sizing: border-box;
margin: 0;
min-width: 1px;
padding-top: 0;
padding-bottom: 0;
align-self: stretch;
}
> .alert {
line-height: calc(var(--__panel-heading-height-inner) - 2px);
}
}
}
// TODO Should refactor panels into separate component and utilize slots
.panel-heading {
border-radius: var(--roundness) var(--roundness) 0 0;
border-width: 0 0 1px;
align-items: start;
background-image:
linear-gradient(to bottom, var(--background), var(--background)),
linear-gradient(to bottom, var(--__panel-background), var(--__panel-background));
&::after {
background-color: var(--background);
z-index: -2;
border-radius: var(--roundness) var(--roundness) 0 0;
box-shadow: var(--shadow);
}
&:not(.-flexible-height) {
> .button-default {
flex-shrink: 0;
}
}
.rightside-button {
align-self: stretch;
text-align: center;
width: var(--__panel-heading-height);
height: var(--__panel-heading-height);
margin: calc(-1 * var(--panel-heading-height-padding)) 0;
margin-right: calc(-1 * var(--__panel-heading-gap));
> button {
box-sizing: border-box;
padding: calc(1 * var(--panel-heading-height-padding)) 0;
height: 100%;
width: 100%;
text-align: center;
svg {
font-size: 1.2em;
}
}
}
.rightside-icon {
align-self: stretch;
text-align: center;
width: var(--__panel-heading-height);
margin-right: calc(-1 * var(--__panel-heading-gap));
svg {
font-size: 1.2em;
}
}
}
.panel-footer {
border-top-left-radius: 0;
border-top-right-radius: 0;
align-items: center;
border-width: 1px 0 0;
border-style: solid;
border-color: var(--border);
background-color: var(--__panel-background);
}
/* stylelint-enable no-descending-specificity */

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 19, 6:37 AM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1769039
Default Alt Text
(112 KB)

Event Timeline