Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85711635
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
112 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rPUFE pleroma-fe-upstream
Attached
Detach File
Event Timeline
Log In to Comment