Overhauled post creation
Made the menu significantly better and made it possible to upload files directly from the post page
This commit is contained in:
parent
b2ce13eea1
commit
2b8158f666
11 changed files with 219 additions and 125 deletions
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#main {
|
#main {
|
||||||
min-height: 250px;
|
min-height: 250px;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main.tiny {
|
#main.tiny {
|
||||||
|
|
27
src/lib/components/Button.svelte
Normal file
27
src/lib/components/Button.svelte
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<style>
|
||||||
|
.button {
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: var(--dark-3);
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
|
margin: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button a {
|
||||||
|
color: var(--light-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export let clickFunc = () => {};
|
||||||
|
export let button = '';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={clickFunc} class='button'>
|
||||||
|
<a href='#'><slot/></a>
|
||||||
|
</button>
|
55
src/lib/components/FileUpload.svelte
Normal file
55
src/lib/components/FileUpload.svelte
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<script>
|
||||||
|
import Button from '$lib/components/Button.svelte';
|
||||||
|
|
||||||
|
export let form;
|
||||||
|
|
||||||
|
let fileInput;
|
||||||
|
let files;
|
||||||
|
let preview;
|
||||||
|
|
||||||
|
function getBase64(image) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(image);
|
||||||
|
reader.onload = e => {
|
||||||
|
preview = e.target.result;
|
||||||
|
uploadFunction(e.target.result);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
async function uploadFunction(imgBase64) {
|
||||||
|
const imgData = imgBase64.split(',').pop();
|
||||||
|
|
||||||
|
var fData = (new FormData());
|
||||||
|
|
||||||
|
fData.append('img',imgData);
|
||||||
|
fData.append('extension',fileInput.value.split('.').pop());
|
||||||
|
|
||||||
|
form = await fetch(`/api/fileCreate`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: fData
|
||||||
|
}).then(x => x.json());
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<form action='/api/postCreate' method='POST' >
|
||||||
|
{#if preview}
|
||||||
|
<img src={preview} alt="Image preview"/>
|
||||||
|
{:else}
|
||||||
|
<img src='/icon_sanifae.svg' alt="Image preview"/>
|
||||||
|
{/if}
|
||||||
|
<input class="hidden" id="file-to-upload" type="file" bind:files bind:this={fileInput} on:change={() => getBase64(files[0])}/>
|
||||||
|
<p>
|
||||||
|
<Button class="upload-btn" clickFunc={ () => fileInput.click() }>Upload</Button>
|
||||||
|
</p>
|
||||||
|
</form>
|
|
@ -1,14 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import Area from '$lib/components/Area.svelte';
|
import Area from '$lib/components/Area.svelte';
|
||||||
|
import PostButton from '$lib/components/PostButton.svelte';
|
||||||
import {formatPost} from '$lib/util.js';
|
import PostBody from '$lib/components/PostBody.svelte';
|
||||||
|
|
||||||
export let success, username, content, upvotes, downvotes, id;
|
export let success, username, content, upvotes, downvotes, id;
|
||||||
|
|
||||||
let query = (id) ? `/post/${id}` : '';
|
let query = (id) ? `/post/${id}` : '';
|
||||||
|
|
||||||
let contentSplit = formatPost(content || '');
|
|
||||||
|
|
||||||
let fData;
|
let fData;
|
||||||
|
|
||||||
function vote(v) {
|
function vote(v) {
|
||||||
|
@ -29,10 +27,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.button {
|
|
||||||
width: auto;
|
|
||||||
height: 35px;
|
|
||||||
}
|
|
||||||
.votes {
|
.votes {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
|
@ -59,44 +54,31 @@
|
||||||
</p>
|
</p>
|
||||||
</Area>
|
</Area>
|
||||||
{:else}
|
{:else}
|
||||||
<Area tiny='{!!id}'>
|
<Area>
|
||||||
<span slot="header">
|
<span slot="header">
|
||||||
<a href='/user/{username}'>
|
<a href='/user/{username}'>
|
||||||
{username}
|
{username}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span slot="main">
|
<span slot="main">
|
||||||
{#each contentSplit as line}
|
<PostBody content={content} />
|
||||||
{#if line && line.type == 'img'}
|
|
||||||
<img src={line.url} alt='Image preview'>
|
|
||||||
{:else}
|
|
||||||
<p>{line}</p>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</span>
|
</span>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<span class='vote-area'>
|
<PostButton
|
||||||
<a on:click={() => vote('up')} href=''>
|
clickFunc={() => vote('up')}
|
||||||
<img src='/upvote.svg' class='button' alt='Upvote'>
|
data={upvotes * 1}
|
||||||
</a>
|
icon='/upvote.svg'
|
||||||
<span class='votes'>
|
/>
|
||||||
{upvotes + 0}
|
<PostButton
|
||||||
</span>
|
clickFunc={() => vote('down')}
|
||||||
</span>
|
data={downvotes * 1}
|
||||||
<span class='vote-area'>
|
icon='/downvote.svg'
|
||||||
<a on:click={() => vote('down')} href=''>
|
/>
|
||||||
<img src='/downvote.svg' class='button' alt='Downvote'>
|
|
||||||
</a>
|
|
||||||
<span class='votes'>
|
|
||||||
{downvotes + 0}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
{#if id}
|
{#if id}
|
||||||
<span class='vote-area'>
|
<PostButton
|
||||||
<a href='/post/{id}'>
|
href='/post/{id}'
|
||||||
<img src='/view.svg' class='button' alt='View'>
|
icon='/view.svg'
|
||||||
</a>
|
/>
|
||||||
</span>
|
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
</Area>
|
</Area>
|
||||||
|
|
27
src/lib/components/PostBody.svelte
Normal file
27
src/lib/components/PostBody.svelte
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<style>
|
||||||
|
img {
|
||||||
|
max-width: 250px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {formatPost} from '$lib/util.js';
|
||||||
|
|
||||||
|
export let content = '';
|
||||||
|
|
||||||
|
let contentSplit;
|
||||||
|
$: contentSplit = formatPost(content || '');
|
||||||
|
|
||||||
|
console.log(contentSplit);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{#each contentSplit as line}
|
||||||
|
{#if line && line.type == 'img'}
|
||||||
|
<img src={line.url} alt='Image preview'>
|
||||||
|
{:else}
|
||||||
|
<p>{line}</p>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</span>
|
31
src/lib/components/PostButton.svelte
Normal file
31
src/lib/components/PostButton.svelte
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<style>
|
||||||
|
.votes {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
.vote-area {
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
width: auto;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export let clickFunc = () => {};
|
||||||
|
export let href = '#';
|
||||||
|
export let data = ' ';
|
||||||
|
export let icon = '/upvote.svg';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span class='vote-area'>
|
||||||
|
<a on:click={clickFunc} href='{href}'>
|
||||||
|
<img src='{icon}' class='button' alt='Vote button'>
|
||||||
|
</a>
|
||||||
|
<span class='votes'>
|
||||||
|
{data}
|
||||||
|
</span>
|
||||||
|
</span>
|
|
@ -81,11 +81,16 @@ let formatPost = function(post) {
|
||||||
return post;
|
return post;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function block(bool) {
|
||||||
|
return (bool) ? 'block' : 'inline';
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
checkLength,
|
checkLength,
|
||||||
checkRegex,
|
checkRegex,
|
||||||
calcVote,
|
calcVote,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
calcVoteUser,
|
calcVoteUser,
|
||||||
formatPost
|
formatPost,
|
||||||
|
block
|
||||||
};
|
};
|
|
@ -2,6 +2,7 @@
|
||||||
:global(:root) {
|
:global(:root) {
|
||||||
--dark-1: #1a1b1d;
|
--dark-1: #1a1b1d;
|
||||||
--dark-2: #22242b;
|
--dark-2: #22242b;
|
||||||
|
--dark-3: #5d606b;
|
||||||
|
|
||||||
--light-1: #ffffff;
|
--light-1: #ffffff;
|
||||||
|
|
||||||
|
@ -83,9 +84,6 @@
|
||||||
<a href='/new_post'>
|
<a href='/new_post'>
|
||||||
Create
|
Create
|
||||||
</a>
|
</a>
|
||||||
<a href='/new_file'>
|
|
||||||
Create file
|
|
||||||
</a>
|
|
||||||
{:else}
|
{:else}
|
||||||
<a href='/account'>
|
<a href='/account'>
|
||||||
Log in / Register
|
Log in / Register
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
<script>
|
|
||||||
import Area from '$lib/components/Area.svelte';
|
|
||||||
|
|
||||||
/** @type {import('./$types').ActionData} */
|
|
||||||
export let form;
|
|
||||||
|
|
||||||
let fileInput;
|
|
||||||
let files;
|
|
||||||
let preview;
|
|
||||||
|
|
||||||
function getBase64(image) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsDataURL(image);
|
|
||||||
reader.onload = e => {
|
|
||||||
preview = e.target.result;
|
|
||||||
uploadFunction(e.target.result);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
async function uploadFunction(imgBase64) {
|
|
||||||
const imgData = imgBase64.split(',').pop();
|
|
||||||
|
|
||||||
var fData = (new FormData());
|
|
||||||
|
|
||||||
fData.append('img',imgData);
|
|
||||||
fData.append('extension',fileInput.value.split('.').pop());
|
|
||||||
|
|
||||||
form = await fetch(`/api/fileCreate`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: fData
|
|
||||||
}).then(x => x.json());
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
textarea {
|
|
||||||
width: 10rem;
|
|
||||||
height: 10rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 250px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<Area>
|
|
||||||
<p slot="header">
|
|
||||||
Upload File
|
|
||||||
</p>
|
|
||||||
<form slot="main" action='/api/postCreate' method='POST' >
|
|
||||||
{#if preview}
|
|
||||||
<img src={preview} alt="Image preview"/>
|
|
||||||
{:else}
|
|
||||||
<img src='/icon_sanifae.svg' alt="Image preview"/>
|
|
||||||
{/if}
|
|
||||||
<input class="hidden" id="file-to-upload" type="file" bind:files bind:this={fileInput} on:change={() => getBase64(files[0])}/>
|
|
||||||
<p>
|
|
||||||
<a href='#' class="upload-btn" on:click={ () => fileInput.click() }>Upload</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
<p slot="footer">
|
|
||||||
{#if form?.success}
|
|
||||||
{#if form?.href}
|
|
||||||
<a href='{form?.href}'>{form?.success}</a>
|
|
||||||
{:else}
|
|
||||||
{form?.success}
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
Create an image for the world to see.
|
|
||||||
</p>
|
|
||||||
</Area>
|
|
|
@ -1,10 +1,30 @@
|
||||||
<script>
|
<script>
|
||||||
import Area from '$lib/components/Area.svelte';
|
import Area from '$lib/components/Area.svelte';
|
||||||
|
import FileUpload from '$lib/components/FileUpload.svelte';
|
||||||
|
import PostBody from '$lib/components/PostBody.svelte';
|
||||||
|
import Button from '$lib/components/Button.svelte';
|
||||||
|
|
||||||
import { handleSubmit } from '$lib/util.js';
|
import { handleSubmit, formatPost } from '$lib/util.js';;
|
||||||
|
|
||||||
/** @type {import('./$types').ActionData} */
|
/** @type {import('./$types').ActionData} */
|
||||||
export let form;
|
export let form;
|
||||||
|
|
||||||
|
let uploadForm = {};
|
||||||
|
|
||||||
|
let formContent = '';
|
||||||
|
let formBody;
|
||||||
|
|
||||||
|
let currentState = 'editor';
|
||||||
|
|
||||||
|
function setState(editor) {
|
||||||
|
currentState = editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (uploadForm.href) {
|
||||||
|
currentState = 'editor';
|
||||||
|
formContent += `\nimg||${uploadForm.href.split('/').pop()}`;
|
||||||
|
uploadForm.href = false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -12,21 +32,42 @@
|
||||||
width: 10rem;
|
width: 10rem;
|
||||||
height: 10rem;
|
height: 10rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<Area>
|
<Area>
|
||||||
<p slot="header">
|
<p slot="header">
|
||||||
Create Post
|
Create Post
|
||||||
</p>
|
</p>
|
||||||
<form slot="main" action='/api/postCreate' method='POST' on:submit|preventDefault={async e => form = JSON.parse(await handleSubmit(e)) }>
|
<div class='main' slot='main'>
|
||||||
<p>
|
<form action='/api/postCreate'
|
||||||
<textarea name='content'></textarea>
|
method='POST'
|
||||||
</p>
|
on:submit|preventDefault={async e => form = JSON.parse(await handleSubmit(e)) }
|
||||||
<p>
|
>
|
||||||
<input formaction="?/create" type='submit' value='Post'>
|
<textarea name='content' style='display: none;' value={formContent}></textarea
|
||||||
</p>
|
|
||||||
</form>
|
</form>
|
||||||
|
<input formaction="?/create" type='submit' value='Post' bind:this={formBody} style='display: none;'>
|
||||||
|
{#if currentState == 'editor'}
|
||||||
|
<p>
|
||||||
|
<textarea name='content' bind:value={formContent}></textarea>
|
||||||
|
</p>
|
||||||
|
{:else if currentState == 'visual'}
|
||||||
|
<PostBody content={formContent} />
|
||||||
|
{:else}
|
||||||
|
<FileUpload bind:form={uploadForm} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
|
<div class='wrapper'>
|
||||||
|
<Button clickFunc={() => { setState('editor')}}>Edit</Button>
|
||||||
|
<Button clickFunc={() => { setState('visual')}}>View</Button>
|
||||||
|
<Button clickFunc={() => { setState('upload')}}>Upload file</Button>
|
||||||
|
<Button clickFunc={() => formBody.click()}>Create</Button>
|
||||||
|
</div>
|
||||||
<p>
|
<p>
|
||||||
{#if form?.success}
|
{#if form?.success}
|
||||||
{#if form?.href}
|
{#if form?.href}
|
||||||
|
|
|
@ -11,4 +11,5 @@
|
||||||
content={data.content}
|
content={data.content}
|
||||||
upvotes={data.upvotes}
|
upvotes={data.upvotes}
|
||||||
downvotes={data.downvotes}
|
downvotes={data.downvotes}
|
||||||
|
id={data.id}
|
||||||
></Post>
|
></Post>
|
Loading…
Reference in a new issue