Compare commits

...

3 commits

Author SHA1 Message Date
Henry Jameson
d1db92c896 Merge branch 'drafts-improvements' into shigusegubu-themes3 2024-12-27 17:10:34 +02:00
Henry Jameson
cc184858cd drafts list update 2024-12-27 17:10:17 +02:00
Henry Jameson
14e30dabd6 post form dropdown 2024-12-27 17:04:06 +02:00
6 changed files with 334 additions and 303 deletions

View file

@ -1,21 +1,5 @@
<template> <template>
<article class="Draft"> <article class="Draft">
<div class="actions">
<button
class="btn button-default"
:class="{ toggled: editing }"
:aria-expanded="editing"
@click.prevent.stop="toggleEditing"
>
{{ $t('drafts.continue') }}
</button>
<button
class="btn button-default"
@click.prevent.stop="abandon"
>
{{ $t('drafts.abandon') }}
</button>
</div>
<div <div
v-if="!editing" v-if="!editing"
class="status-content" class="status-content"
@ -66,6 +50,22 @@
{{ $t('drafts.abandon_confirm') }} {{ $t('drafts.abandon_confirm') }}
</confirm-modal> </confirm-modal>
</teleport> </teleport>
<div class="actions">
<button
class="btn button-default"
:class="{ toggled: editing }"
:aria-expanded="editing"
@click.prevent.stop="toggleEditing"
>
{{ $t('drafts.continue') }}
</button>
<button
class="btn button-default"
@click.prevent.stop="abandon"
>
{{ $t('drafts.abandon') }}
</button>
</div>
</article> </article>
</template> </template>
@ -73,13 +73,7 @@
<style lang="scss"> <style lang="scss">
.Draft { .Draft {
margin: 1em;
.status-content { .status-content {
border: 1px solid;
border-color: var(--faint);
border-radius: var(--inputRadius);
color: var(--text);
padding: 0.5em; padding: 0.5em;
margin: 0.5em 0; margin: 0.5em 0;
} }

View file

@ -7,7 +7,11 @@
</div> </div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p v-if="drafts.length === 0">
{{ $t('drafts.no_drafts') }}
</p>
<List <List
v-else
:items="drafts" :items="drafts"
> >
<template #item="{ item: draft }"> <template #item="{ item: draft }">

View file

@ -7,6 +7,7 @@ import PollForm from '../poll/poll_form.vue'
import Attachment from '../attachment/attachment.vue' import Attachment from '../attachment/attachment.vue'
import Gallery from 'src/components/gallery/gallery.vue' import Gallery from 'src/components/gallery/gallery.vue'
import StatusContent from '../status_content/status_content.vue' import StatusContent from '../status_content/status_content.vue'
import Popover from 'src/components/popover/popover.vue'
import fileTypeService from '../../services/file_type/file_type.service.js' import fileTypeService from '../../services/file_type/file_type.service.js'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js' import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js' import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js'
@ -25,7 +26,10 @@ import {
faUpload, faUpload,
faBan, faBan,
faTimes, faTimes,
faCircleNotch faCircleNotch,
faChevronDown,
faChevronLeft,
faChevronRight
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
library.add( library.add(
@ -34,7 +38,10 @@ library.add(
faUpload, faUpload,
faBan, faBan,
faTimes, faTimes,
faCircleNotch faCircleNotch,
faChevronDown,
faChevronLeft,
faChevronRight
) )
const buildMentionsString = ({ user, attentions = [] }, currentUser) => { const buildMentionsString = ({ user, attentions = [] }, currentUser) => {
@ -123,7 +130,8 @@ const PostStatusForm = {
Attachment, Attachment,
StatusContent, StatusContent,
Gallery, Gallery,
DraftCloser DraftCloser,
Popover
}, },
mounted () { mounted () {
this.updateIdempotencyKey() this.updateIdempotencyKey()

View file

@ -0,0 +1,249 @@
.post-status-form {
position: relative;
.attachments {
margin-bottom: 0.5em;
}
.form-bottom {
display: flex;
justify-content: space-between;
padding: 0.5em;
height: 2.5em;
.post-button {
width: 10em;
}
p {
margin: 0.35em;
padding: 0.35em;
display: flex;
}
}
.more-post-actions {
height: 100%;
.btn {
height: 100%;
}
}
.form-bottom-left {
display: flex;
flex: 1;
padding-right: 7px;
margin-right: 7px;
max-width: 10em;
}
.preview-heading {
display: flex;
flex-wrap: wrap;
}
.preview-toggle {
flex: 10 0 auto;
cursor: pointer;
user-select: none;
padding-left: 0.5em;
&:hover {
text-decoration: underline;
}
svg,
i {
margin-left: 0.2em;
font-size: 0.8em;
transform: rotate(90deg);
}
}
.preview-container {
margin-bottom: 1em;
}
.preview-error {
font-style: italic;
color: var(--textFaint);
}
.preview-status {
border: 1px solid var(--border);
border-radius: var(--roundness);
padding: 0.5em;
margin: 0;
}
.reply-or-quote-selector {
flex: 1 0 auto;
margin-bottom: 0.5em;
display: grid;
grid-template-columns: 1fr 1fr;
}
.text-format {
.only-format {
color: var(--textFaint);
}
}
.visibility-tray {
display: flex;
justify-content: space-between;
padding-top: 5px;
align-items: baseline;
}
.visibility-notice.edit-warning {
> :first-child {
margin-top: 0;
}
> :last-child {
margin-bottom: 0;
}
}
// Order is not necessary but a good indicator
.media-upload-icon {
order: 1;
justify-content: left;
}
.emoji-icon {
order: 2;
justify-content: center;
}
.poll-icon {
order: 3;
justify-content: right;
}
.media-upload-icon,
.poll-icon,
.emoji-icon {
font-size: 1.85em;
line-height: 1.1;
flex: 1;
padding: 0 0.1em;
display: flex;
align-items: center;
}
.error {
text-align: center;
}
.media-upload-wrapper {
margin-right: 0.2em;
margin-bottom: 0.5em;
width: 18em;
img,
video {
object-fit: contain;
max-height: 10em;
}
.video {
max-height: 10em;
}
input {
flex: 1;
width: 100%;
}
}
.status-input-wrapper {
display: flex;
position: relative;
width: 100%;
flex-direction: column;
}
.btn[disabled] {
cursor: not-allowed;
}
form {
display: flex;
flex-direction: column;
margin: 0.6em;
position: relative;
}
.form-group {
display: flex;
flex-direction: column;
padding: 0.25em 0.5em 0.5em;
line-height: 1.85;
}
.input.form-post-body {
// TODO: make a resizable textarea component?
box-sizing: content-box; // needed for easier computation of dynamic size
overflow: hidden;
transition: min-height 200ms 100ms;
// stock padding + 1 line of text (for counter)
padding-bottom: calc(var(--_padding) + var(--post-line-height) * 1em);
// two lines of text
height: calc(var(--post-line-height) * 1em);
min-height: calc(var(--post-line-height) * 1em);
resize: none;
background: transparent;
&.scrollable-form {
overflow-y: auto;
}
}
.main-input {
position: relative;
}
.character-counter {
position: absolute;
bottom: 0;
right: 0;
padding: 0;
margin: 0 0.5em;
&.error {
color: var(--cRed);
}
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 0.6; }
}
@keyframes fade-out {
from { opacity: 0.6; }
to { opacity: 0; }
}
.drop-indicator {
position: absolute;
width: 100%;
height: 100%;
font-size: 5em;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.6;
color: var(--text);
background-color: var(--bg);
border-radius: var(--roundness);
border: 2px dashed var(--text);
}
.auto-save-status {
align-self: center;
}
}

View file

@ -264,6 +264,12 @@
:visible="pollFormVisible" :visible="pollFormVisible"
:params="newStatus.poll" :params="newStatus.poll"
/> />
<span
v-if="!disableDraft && shouldAutoSaveDraft"
class="auto-save-status"
>
{{ autoSaveState }}
</span>
<div <div
ref="bottom" ref="bottom"
class="form-bottom" class="form-bottom"
@ -296,41 +302,52 @@
<FAIcon icon="poll-h" /> <FAIcon icon="poll-h" />
</button> </button>
</div> </div>
<span <div class="btn-group">
v-if="!disableDraft && shouldAutoSaveDraft" <button
class="auto-save-status" class="btn button-default post-button"
> :disabled="isOverLengthLimit || posting || uploadingFiles || disableSubmit"
{{ autoSaveState }} @click.stop.prevent="postStatus($event, newStatus)"
</span> >
<button <template v-if="posting">
v-else-if="!disableDraft" {{ $t('post_status.posting') }}
class="btn button-default" </template>
@click="saveDraft" <template v-else>
> {{ $t('post_status.post') }}
{{ $t('post_status.save_to_drafts_button') }} </template>
</button> </button>
<button <Popover
v-if="posting" v-if="!disableDraft"
disabled class="more-post-actions"
class="btn button-default" :normal-button="true"
> trigger="click"
{{ $t('post_status.posting') }} placement="bottom"
</button> :offset="{ y: 5 }"
<button :bound-to="{ x: 'container' }"
v-else-if="isOverLengthLimit" >
disabled <template #trigger>
class="btn button-default" <FAIcon
> class="fa-scale-110 fa-old-padding"
{{ $t('post_status.post') }} icon="chevron-down"
</button> />
<button </template>
v-else <template #content="{close}">
:disabled="uploadingFiles || disableSubmit" <div
class="btn button-default" class="dropdown-menu"
@click.stop.prevent="postStatus($event, newStatus)" role="menu"
> >
{{ $t('post_status.post') }} <button
</button> class="menu-item dropdown-item dropdown-item-icon"
role="menu"
@click.prevent="saveDraft"
@click="close"
v-if="!disableDraft"
>
{{ $t('post_status.save_to_drafts_button') }}
</button>
</div>
</template>
</Popover>
</div>
</div> </div>
<div <div
v-show="showDropIcon !== 'hide'" v-show="showDropIcon !== 'hide'"
@ -391,246 +408,4 @@
<script src="./post_status_form.js"></script> <script src="./post_status_form.js"></script>
<style lang="scss"> <style src="./post_status_form.scss" lang="scss"></style>
.post-status-form {
position: relative;
.attachments {
margin-bottom: 0.5em;
}
.form-bottom {
display: flex;
justify-content: space-between;
padding: 0.5em;
height: 2.5em;
button {
width: 10em;
}
p {
margin: 0.35em;
padding: 0.35em;
display: flex;
}
}
.form-bottom-left {
display: flex;
flex: 1;
padding-right: 7px;
margin-right: 7px;
max-width: 10em;
}
.preview-heading {
display: flex;
flex-wrap: wrap;
}
.preview-toggle {
flex: 10 0 auto;
cursor: pointer;
user-select: none;
padding-left: 0.5em;
&:hover {
text-decoration: underline;
}
svg,
i {
margin-left: 0.2em;
font-size: 0.8em;
transform: rotate(90deg);
}
}
.preview-container {
margin-bottom: 1em;
}
.preview-error {
font-style: italic;
color: var(--textFaint);
}
.preview-status {
border: 1px solid var(--border);
border-radius: var(--roundness);
padding: 0.5em;
margin: 0;
}
.reply-or-quote-selector {
flex: 1 0 auto;
margin-bottom: 0.5em;
display: grid;
grid-template-columns: 1fr 1fr;
}
.text-format {
.only-format {
color: var(--textFaint);
}
}
.visibility-tray {
display: flex;
justify-content: space-between;
padding-top: 5px;
align-items: baseline;
}
.visibility-notice.edit-warning {
> :first-child {
margin-top: 0;
}
> :last-child {
margin-bottom: 0;
}
}
// Order is not necessary but a good indicator
.media-upload-icon {
order: 1;
justify-content: left;
}
.emoji-icon {
order: 2;
justify-content: center;
}
.poll-icon {
order: 3;
justify-content: right;
}
.media-upload-icon,
.poll-icon,
.emoji-icon {
font-size: 1.85em;
line-height: 1.1;
flex: 1;
padding: 0 0.1em;
display: flex;
align-items: center;
}
.error {
text-align: center;
}
.media-upload-wrapper {
margin-right: 0.2em;
margin-bottom: 0.5em;
width: 18em;
img,
video {
object-fit: contain;
max-height: 10em;
}
.video {
max-height: 10em;
}
input {
flex: 1;
width: 100%;
}
}
.status-input-wrapper {
display: flex;
position: relative;
width: 100%;
flex-direction: column;
}
.btn[disabled] {
cursor: not-allowed;
}
form {
display: flex;
flex-direction: column;
margin: 0.6em;
position: relative;
}
.form-group {
display: flex;
flex-direction: column;
padding: 0.25em 0.5em 0.5em;
line-height: 1.85;
}
.input.form-post-body {
// TODO: make a resizable textarea component?
box-sizing: content-box; // needed for easier computation of dynamic size
overflow: hidden;
transition: min-height 200ms 100ms;
// stock padding + 1 line of text (for counter)
padding-bottom: calc(var(--_padding) + var(--post-line-height) * 1em);
// two lines of text
height: calc(var(--post-line-height) * 1em);
min-height: calc(var(--post-line-height) * 1em);
resize: none;
background: transparent;
&.scrollable-form {
overflow-y: auto;
}
}
.main-input {
position: relative;
}
.character-counter {
position: absolute;
bottom: 0;
right: 0;
padding: 0;
margin: 0 0.5em;
&.error {
color: var(--cRed);
}
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 0.6; }
}
@keyframes fade-out {
from { opacity: 0.6; }
to { opacity: 0; }
}
.drop-indicator {
position: absolute;
width: 100%;
height: 100%;
font-size: 5em;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.6;
color: var(--text);
background-color: var(--bg);
border-radius: var(--roundness);
border: 2px dashed var(--text);
}
.auto-save-status {
align-self: center;
}
}
</style>

View file

@ -1513,6 +1513,7 @@
}, },
"drafts": { "drafts": {
"drafts": "Drafts", "drafts": "Drafts",
"no_drafts": "You have no drafts",
"continue": "Continue composing", "continue": "Continue composing",
"abandon": "Abandon draft", "abandon": "Abandon draft",
"abandon_confirm_title": "Abandon confirmation", "abandon_confirm_title": "Abandon confirmation",