Add preview button to post editor
This commit is contained in:
parent
5191727639
commit
1a9ae2cb16
7 changed files with 90 additions and 12 deletions
|
@ -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;
|
||||
|
|
|
@ -44,7 +44,7 @@ export interface Profile {
|
|||
statuses_count: number;
|
||||
}
|
||||
|
||||
export function guest(): Profile {
|
||||
export function defaultProfile(): Profile {
|
||||
return {
|
||||
id: "",
|
||||
username: "",
|
||||
|
|
1
src/assets/feather/eye-off.svg
Normal file
1
src/assets/feather/eye-off.svg
Normal 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 |
1
src/assets/feather/eye.svg
Normal file
1
src/assets/feather/eye.svg
Normal 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 |
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue