Add preview button to post editor

This commit is contained in:
silverpill 2022-12-20 17:52:33 +00:00
parent 5191727639
commit 1a9ae2cb16
7 changed files with 90 additions and 12 deletions

View file

@ -1,6 +1,6 @@
import { BACKEND_URL } from "@/constants"
import { PAGE_SIZE, http } from "./common"
import { Profile } from "./users"
import { defaultProfile, Profile } from "./users"
export interface Attachment {
id: string;
@ -155,6 +155,45 @@ export async function getPostContext(
return data
}
export async function previewPost(
authToken: string,
content: string,
): Promise<Post> {
const url = `${BACKEND_URL}/api/v1/statuses/preview`
const response = await http(url, {
method: "POST",
json: {
status: content,
content_type: "text/markdown",
},
authToken,
})
const data = await response.json()
return {
id: "",
uri: "",
created_at: "",
edited_at: null,
account: defaultProfile(),
content: data.content,
in_reply_to_id: null,
reblog: null,
visibility: Visibility.Public,
replies_count: 0,
favourites_count: 0,
reblogs_count: 0,
media_attachments: [],
mentions: [],
tags: [],
favourited: false,
reblogged: false,
ipfs_cid: null,
token_id: null,
token_tx_id: null,
links: [],
}
}
export interface PostData {
content: string;
in_reply_to_id: string | null;

View file

@ -44,7 +44,7 @@ export interface Profile {
statuses_count: number;
}
export function guest(): Profile {
export function defaultProfile(): Profile {
return {
id: "",
username: "",

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye-off"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>

After

Width:  |  Height:  |  Size: 462 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>

After

Width:  |  Height:  |  Size: 318 B

View file

@ -11,12 +11,18 @@
<textarea
id="content"
ref="postFormContentRef"
v-show="preview === null"
v-model="content"
@input="saveLocalDraft()"
rows="1"
required
:placeholder="inReplyTo ? 'Your reply' : 'What\'s on your mind?'"
></textarea>
<post-content
v-if="preview"
:post="preview"
@click.prevent=""
></post-content>
<div v-if="attachments.length > 0" class="attachments">
<div
v-for="(attachment, index) in attachments"
@ -75,6 +81,17 @@
</li>
</menu>
</div>
<div class="toolbar-space"></div>
<button
v-if="canPreview()"
type="button"
class="icon"
title="Toggle preview"
@click="togglePreview()"
>
<img v-if="preview === null" :src="require('@/assets/feather/eye.svg')">
<img v-else :src="require('@/assets/feather/eye-off.svg')">
</button>
<div class="character-counter" title="Characters left">
{{ getCharacterCount() }}
</div>
@ -106,16 +123,18 @@ import { nextTick, onMounted } from "vue"
import { $, $computed, $ref } from "vue/macros"
import {
Visibility,
VISIBILITY_MAP,
createPost,
previewPost,
uploadAttachment,
Attachment,
Mention,
Post,
createPost,
Attachment,
uploadAttachment,
Visibility,
VISIBILITY_MAP,
} from "@/api/posts"
import { User } from "@/api/users"
import Avatar from "@/components/Avatar.vue"
import PostContent from "@/components/PostContent.vue"
import VisibilityIcon from "@/components/VisibilityIcon.vue"
import { useInstanceInfo } from "@/store/instance"
import { useCurrentUser } from "@/store/user"
@ -147,6 +166,7 @@ let attachments = $ref<Attachment[]>([])
let visibility = $ref(Visibility.Public)
let visibilityMenuVisible = $ref(false)
let preview = $ref<Post | null>(null)
let isLoading = $ref(false)
let errorMessage = $ref<string | null>(null)
@ -173,6 +193,7 @@ if (props.inReplyTo && props.inReplyTo.visibility !== Visibility.Public) {
onMounted(() => {
if (postFormContentRef) {
setupAutoResize(postFormContentRef)
triggerResize(postFormContentRef)
}
})
@ -236,6 +257,18 @@ function getCharacterCount(): number {
return (instance.post_character_limit - content.length)
}
function canPreview(): boolean {
return content.length > 0
}
async function togglePreview() {
if (preview === null) {
preview = await previewPost(ensureAuthToken(), content)
} else {
preview = null
}
}
function canPublish(): boolean {
return getCharacterCount() >= 0 && !isLoading
}
@ -266,6 +299,7 @@ async function publish() {
removeLocalDraft()
content = ""
attachments = []
preview = null
if (postFormContentRef) {
await nextTick()
triggerResize(postFormContentRef)
@ -350,9 +384,12 @@ $line-height: 1.5;
gap: calc($block-inner-padding / 2);
padding: calc($block-inner-padding / 1.5) $block-inner-padding;
.toolbar-space {
flex-grow: 1;
}
.character-counter {
font-weight: bold;
margin-left: auto;
}
.submit-btn-small {

View file

@ -110,7 +110,7 @@ import { onMounted, watch } from "vue"
import { $, $$, $computed, $ref } from "vue/macros"
import { searchProfilesByEthereumAddress } from "@/api/search"
import { guest, Profile, ProfileWrapper } from "@/api/users"
import { defaultProfile, Profile, ProfileWrapper } from "@/api/users"
import {
cancelSubscription,
getSubscriptionConfig,
@ -137,7 +137,7 @@ const { instance } = $(useInstanceInfo())
const { connectWallet: connectEthereumWallet } = useWallet()
const recipient = new ProfileWrapper(props.profile)
const recipientEthereumAddress = recipient.getVerifiedEthereumAddress()
let sender = $ref<ProfileWrapper>(new ProfileWrapper(currentUser || guest()))
let sender = $ref(new ProfileWrapper(currentUser || defaultProfile()))
let { walletAddress, walletError, getSigner } = $(useWallet())
let subscriptionsEnabled = $ref<boolean | null>(null)
let subscriptionConfig = $ref<SubscriptionConfig | null>(null)

View file

@ -124,7 +124,7 @@ import {
getPricePerMonth,
Invoice,
} from "@/api/subscriptions-monero"
import { guest, Profile, ProfilePaymentOption, ProfileWrapper } from "@/api/users"
import { defaultProfile, Profile, ProfilePaymentOption, ProfileWrapper } from "@/api/users"
import Avatar from "@/components/Avatar.vue"
import Loader from "@/components/Loader.vue"
import QrCode from "@/components/QrCode.vue"
@ -142,7 +142,7 @@ const { currentUser } = $(useCurrentUser())
const recipient = new ProfileWrapper(props.profile)
const senderAcct = $ref("")
let senderError = $ref<string | null>(null)
let sender = $ref<ProfileWrapper>(new ProfileWrapper(currentUser || guest()))
let sender = $ref(new ProfileWrapper(currentUser || defaultProfile()))
let subscriptionOption = $ref<ProfilePaymentOption | null>(null)
let subscriptionDetails = $ref<SubscriptionDetails | null>(null)
const paymentDuration = $ref<number>(1)