A lot of stuff
This commit is contained in:
parent
a1c9b30cf6
commit
ad969e5807
13 changed files with 227 additions and 167 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,3 +9,4 @@ node_modules
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
/db
|
/db
|
||||||
|
/db-old
|
|
@ -29,7 +29,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
border-bottom: var(--dark-2) solid 2px;
|
|
||||||
width: calc(100% - 30px);
|
width: calc(100% - 30px);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
28
src/lib/components/Form.svelte
Normal file
28
src/lib/components/Form.svelte
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<script>
|
||||||
|
import Area from '$lib/components/Area.svelte';
|
||||||
|
import { handleSubmit } from '$lib/util.js';
|
||||||
|
|
||||||
|
export let form = {};
|
||||||
|
export let action = '/';
|
||||||
|
export let name = 'Empty form';
|
||||||
|
|
||||||
|
let submitFunc = async e => form = JSON.parse(await handleSubmit(e))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Area handleSubmit=''>
|
||||||
|
<span slot="header">
|
||||||
|
{name}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span slot='main'>
|
||||||
|
<form action={action} on:submit|preventDefault={submitFunc} method='POST'>
|
||||||
|
<slot></slot>
|
||||||
|
</form>
|
||||||
|
</span>
|
||||||
|
<p slot="footer">
|
||||||
|
{#if form?.success}
|
||||||
|
<p>{form?.success}</p>
|
||||||
|
{/if}
|
||||||
|
By using the Sanifae service, you agree to the <a href='/tos'>Terms of Service</a>.
|
||||||
|
</p>
|
||||||
|
</Area>
|
|
@ -70,6 +70,7 @@
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
|
@ -94,7 +95,7 @@
|
||||||
{:else}
|
{:else}
|
||||||
<Area>
|
<Area>
|
||||||
<span slot="header" id='header'>
|
<span slot="header" id='header'>
|
||||||
<img class='pfp' src='/pfp/{username}.png'/>
|
<img class='pfp' src='/img/pfp/{username}.png'/>
|
||||||
<div class='header-area'>
|
<div class='header-area'>
|
||||||
<div><a href='/users/{username}'>
|
<div><a href='/users/{username}'>
|
||||||
{username}
|
{username}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { backend } from './handlers.js';
|
import { backend } from './handlers.js';
|
||||||
|
import { mkdir, access } from 'node:fs/promises';
|
||||||
|
|
||||||
const AUTH_ACTIONS = [
|
const AUTH_ACTIONS = [
|
||||||
'postCreate',
|
'postCreate',
|
||||||
|
@ -9,24 +10,79 @@ const AUTH_ACTIONS = [
|
||||||
'follow'
|
'follow'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const FILE_DIRS = [
|
||||||
|
'/db',
|
||||||
|
'/db/files/upload',
|
||||||
|
'/db/files/pfp'
|
||||||
|
]
|
||||||
|
|
||||||
import sqlite3 from 'sqlite3'
|
import sqlite3 from 'sqlite3'
|
||||||
import { open } from 'sqlite'
|
import { open } from 'sqlite'
|
||||||
|
|
||||||
var db;
|
var db;
|
||||||
|
|
||||||
|
async function newDir(dir) {
|
||||||
|
await access(newDir)
|
||||||
|
.then(() => {})
|
||||||
|
.catch(async () => await mkdir(dir, { recursive: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initFolders() {
|
||||||
|
for (var i = 0; i < FILE_DIRS.length; i++) {
|
||||||
|
await newDir( `${process.cwd()}/${FILE_DIRS[i]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function initDb() {
|
async function initDb() {
|
||||||
|
await initFolders();
|
||||||
|
|
||||||
db = await open({
|
db = await open({
|
||||||
filename: `${process.cwd()}/db/main.db`,
|
filename: `${process.cwd()}/db/main.db`,
|
||||||
driver: sqlite3.Database
|
driver: sqlite3.Database
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.run('CREATE TABLE IF NOT EXISTS auth (username CHAR(64), password CHAR(1024))');
|
await db.run('CREATE TABLE IF NOT EXISTS auth ( \
|
||||||
await db.run('CREATE TABLE IF NOT EXISTS token (username CHAR(64), token CHAR(1024))');
|
username CHAR(64), \
|
||||||
await db.run('CREATE TABLE IF NOT EXISTS post (username CHAR(64), id CHAR(64), content CHAR(10240), upvotes INTEGER, downvotes INTEGER, rating REAL, reply CHAR(64), time INTEGER)');
|
password CHAR(1024) \
|
||||||
await db.run('CREATE TABLE IF NOT EXISTS vote (id CHAR(64), username CHAR(64), type INTEGER)');
|
)');
|
||||||
await db.run('CREATE TABLE IF NOT EXISTS user (username CHAR(64), followers INTEGER, following INTEGER, upvotes INTEGER, downvotes INTEGER, reputation REAL)');
|
|
||||||
await db.run('CREATE TABLE IF NOT EXISTS bio (username CHAR(64), content CHAR(10240), roles INTEGER)');
|
await db.run('CREATE TABLE IF NOT EXISTS token ( \
|
||||||
await db.run('CREATE TABLE IF NOT EXISTS follow (username CHAR(64), following CHAR(64))');
|
username CHAR(64), \
|
||||||
|
token CHAR(1024) \
|
||||||
|
)');
|
||||||
|
|
||||||
|
await db.run('CREATE TABLE IF NOT EXISTS post ( \
|
||||||
|
username CHAR(64), \
|
||||||
|
id CHAR(64), \
|
||||||
|
content CHAR(10240), \
|
||||||
|
upvotes INTEGER, \
|
||||||
|
downvotes INTEGER, \
|
||||||
|
rating REAL, \
|
||||||
|
reply CHAR(64), \
|
||||||
|
time INTEGER \
|
||||||
|
)');
|
||||||
|
|
||||||
|
await db.run('CREATE TABLE IF NOT EXISTS vote ( \
|
||||||
|
id CHAR(64), \
|
||||||
|
username CHAR(64), \
|
||||||
|
type INTEGER \
|
||||||
|
)');
|
||||||
|
|
||||||
|
await db.run('CREATE TABLE IF NOT EXISTS user ( \
|
||||||
|
username CHAR(64), \
|
||||||
|
followers INTEGER, \
|
||||||
|
following INTEGER, \
|
||||||
|
upvotes INTEGER, \
|
||||||
|
downvotes INTEGER, \
|
||||||
|
reputation REAL, \
|
||||||
|
roles INTEGER, \
|
||||||
|
pinned CHAR(64) \
|
||||||
|
)');
|
||||||
|
|
||||||
|
await db.run('CREATE TABLE IF NOT EXISTS follow (\
|
||||||
|
username CHAR(64), \
|
||||||
|
following CHAR(64) \
|
||||||
|
)');
|
||||||
}
|
}
|
||||||
|
|
||||||
let backendProxy = async ({route, backendParams}) => {
|
let backendProxy = async ({route, backendParams}) => {
|
||||||
|
|
|
@ -84,9 +84,9 @@ let fileCreate = (type) => {
|
||||||
if (validExtensions.indexOf(extensionSafe) == -1)
|
if (validExtensions.indexOf(extensionSafe) == -1)
|
||||||
return { success: 'Illegal file extension. Permitted file extensions are: ' + validExtensions.join(', ') };
|
return { success: 'Illegal file extension. Permitted file extensions are: ' + validExtensions.join(', ') };
|
||||||
|
|
||||||
let fileName = (type == 'post') ? `post-${imgHash}.${extensionSafe}` : `pfp-${user}.png`
|
let fileName = (type == 'post') ? `upload/${imgHash}.${extensionSafe}` : `pfp/${user}.png`
|
||||||
|
|
||||||
writeFile(`${process.cwd()}/db/${fileName}`,imgData,{encoding: 'base64'});
|
writeFile(`${process.cwd()}/db/files/${fileName}`,imgData,{encoding: 'base64'});
|
||||||
|
|
||||||
return { success: 'Successfully uploaded file.', 'href': `/img/${imgHash}.${extensionSafe}`};
|
return { success: 'Successfully uploaded file.', 'href': `/img/${imgHash}.${extensionSafe}`};
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ backend.fileCreate = fileCreate('post');
|
||||||
backend.pfp = fileCreate('pfp');
|
backend.pfp = fileCreate('pfp');
|
||||||
|
|
||||||
backend.userRoles = async ({user},{db}) => {
|
backend.userRoles = async ({user},{db}) => {
|
||||||
var rolesLocal = await db.all('SELECT roles from bio WHERE username = ?', [
|
var rolesLocal = await db.all('SELECT roles from user WHERE username = ?', [
|
||||||
user
|
user
|
||||||
] );
|
] );
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ backend.register = async ({user, pass, pass2},{db}) => {
|
||||||
passHash
|
passHash
|
||||||
])
|
])
|
||||||
|
|
||||||
await updateUser({user: user});
|
await updateUser({user: user}, {db});
|
||||||
|
|
||||||
return { success: 'Successfully created account.', location: '/'};
|
return { success: 'Successfully created account.', location: '/'};
|
||||||
}
|
}
|
||||||
|
@ -236,21 +236,9 @@ backend.userGet = async ({user},{db}) => {
|
||||||
|
|
||||||
if (!followers) followers = [];
|
if (!followers) followers = [];
|
||||||
|
|
||||||
return {data: posts[0], following, followers};
|
posts[0].rolesArr = await backend.userRoles({user},{db});
|
||||||
}
|
|
||||||
|
|
||||||
backend.userBio = async ({user},{db}) => {
|
return {data: posts[0], following, followers };
|
||||||
var posts = await db.all('SELECT * from bio WHERE username = ?', [
|
|
||||||
user
|
|
||||||
])
|
|
||||||
|
|
||||||
if (!posts || posts.length < 1) {
|
|
||||||
return {'success': 'Bio does not exist.'}
|
|
||||||
}
|
|
||||||
|
|
||||||
posts[0].rolesArr = (await userRoles({user})) || [];
|
|
||||||
|
|
||||||
return {data: posts[0]};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) => {
|
backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) => {
|
||||||
|
@ -264,11 +252,14 @@ backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) =>
|
||||||
|
|
||||||
sort = sort.replaceAll('%d',Math.floor(new Date() * 1000));
|
sort = sort.replaceAll('%d',Math.floor(new Date() * 1000));
|
||||||
|
|
||||||
|
let pageParams = [
|
||||||
|
page*ROW_COUNT,
|
||||||
|
ROW_COUNT
|
||||||
|
]
|
||||||
|
|
||||||
if (type == 'all') {
|
if (type == 'all') {
|
||||||
posts = await db.all('SELECT * from post ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
posts = await db.all('SELECT * from post ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||||
page*ROW_COUNT,
|
...pageParams
|
||||||
ROW_COUNT
|
|
||||||
])
|
])
|
||||||
} else if (type == 'post') {
|
} else if (type == 'post') {
|
||||||
posts = await db.all('SELECT * from post WHERE id = ?', [
|
posts = await db.all('SELECT * from post WHERE id = ?', [
|
||||||
|
@ -279,21 +270,18 @@ backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) =>
|
||||||
|
|
||||||
posts.push(...(await db.all('SELECT * from post WHERE reply = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
posts.push(...(await db.all('SELECT * from post WHERE reply = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||||
id,
|
id,
|
||||||
page*ROW_COUNT,
|
...pageParams
|
||||||
ROW_COUNT
|
|
||||||
])))
|
])))
|
||||||
|
|
||||||
} else if (type == 'user') {
|
} else if (type == 'user') {
|
||||||
posts = await db.all('SELECT * from post WHERE username = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
posts = await db.all('SELECT * from post WHERE username = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||||
user,
|
user,
|
||||||
page*ROW_COUNT,
|
...pageParams
|
||||||
ROW_COUNT
|
|
||||||
])
|
])
|
||||||
} else if (type == 'follow') {
|
} else if (type == 'follow') {
|
||||||
posts = await db.all('SELECT * from post WHERE username IN (SELECT following from follow WHERE username = ?) ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
posts = await db.all('SELECT * from post WHERE username IN (SELECT following from follow WHERE username = ?) ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||||
userAuth,
|
userAuth,
|
||||||
page*ROW_COUNT,
|
...pageParams
|
||||||
ROW_COUNT
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +334,7 @@ backend.vote = async ({id, vote}, {user, db}) => {
|
||||||
if (!user[0])
|
if (!user[0])
|
||||||
return {success: 'fail' };
|
return {success: 'fail' };
|
||||||
|
|
||||||
await updateUser({user: user[0].username});
|
await updateUser({user: user[0].username}, {db});
|
||||||
|
|
||||||
return {data: {up,down}};
|
return {data: {up,down}};
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ let formatPost = function(post) {
|
||||||
|
|
||||||
extension = safeName(extension);
|
extension = safeName(extension);
|
||||||
|
|
||||||
splitPost = {'type': EXTENSION_MAP[extension] || 'none', 'url': `/img/${matchCleaned}`};
|
splitPost = {'type': EXTENSION_MAP[extension] || 'none', 'url': `/img/file/${matchCleaned}`};
|
||||||
|
|
||||||
return splitPost;
|
return splitPost;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,10 @@
|
||||||
:global(input, textarea) {
|
:global(input, textarea) {
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 0.2rem;
|
border-radius: 0.2rem;
|
||||||
box-shadow: 0px 2px 2.5px 0px var(--dark-2);
|
box-shadow: 0px 0px 2px 2px var(--dark-2);
|
||||||
|
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,34 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import Area from '$lib/components/Area.svelte';
|
import Form from '$lib/components/Form.svelte';
|
||||||
import { handleSubmit } from '$lib/util.js';
|
|
||||||
|
|
||||||
export let form = {};
|
|
||||||
|
|
||||||
let submitFunc = async e => form = JSON.parse(await handleSubmit(e))
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Area handleSubmit=''>
|
<Form action='/api/login' name='Log in'>
|
||||||
<span slot="header">
|
<p>
|
||||||
Log in
|
<input name='user' placeholder='Username'>
|
||||||
</span>
|
|
||||||
|
|
||||||
<span slot='main'>
|
|
||||||
<h2>Login</h2>
|
|
||||||
<form action='/api/login' on:submit|preventDefault={submitFunc} method='POST'>
|
|
||||||
<p>
|
|
||||||
Username: <input name='user'>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Password: <input type='password' name='pass'>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<input type='submit' value='Log in'>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</span>
|
|
||||||
<p slot="footer">
|
|
||||||
{#if form?.success}
|
|
||||||
<p>{form?.success}</p>
|
|
||||||
{/if}
|
|
||||||
</p>
|
</p>
|
||||||
</Area>
|
<p>
|
||||||
|
<input type='password' name='pass' placeholder='Password'>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type='submit' value='Log in'>
|
||||||
|
</p>
|
||||||
|
</Form>
|
|
@ -1,38 +1,18 @@
|
||||||
<script>
|
<script>
|
||||||
import Area from '$lib/components/Area.svelte';
|
import Form from '$lib/components/Form.svelte';
|
||||||
import { handleSubmit } from '$lib/util.js';
|
|
||||||
|
|
||||||
export let form = {};
|
|
||||||
|
|
||||||
let submitFunc = async e => form = JSON.parse(await handleSubmit(e))
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Area handleSubmit=''>
|
<Form action='/api/register' name='Register'>
|
||||||
<span slot="header">
|
<p>
|
||||||
Register
|
<input name='user' placeholder='Username'>
|
||||||
</span>
|
|
||||||
|
|
||||||
<span slot='main'>
|
|
||||||
<h2>Register</h2>
|
|
||||||
<form action='/api/register' on:submit|preventDefault={submitFunc} method='POST'>
|
|
||||||
<p>
|
|
||||||
Username: <input name='user'>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Password: <input type='password' name='pass'>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Confirm Password: <input type='password' name='pass2'>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<input type='submit' value='Register'>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</span>
|
|
||||||
<p slot="footer">
|
|
||||||
{#if form?.success}
|
|
||||||
<p>{form?.success}</p>
|
|
||||||
{/if}
|
|
||||||
By using the Sanifae service, you agree to the <a href='/tos'>Terms of Service</a>.
|
|
||||||
</p>
|
</p>
|
||||||
</Area>
|
<p>
|
||||||
|
<input type='password' name='pass' placeholder='Password'>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type='password' name='pass2' placeholder='Password (confirm)'>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type='submit' value='Register'>
|
||||||
|
</p>
|
||||||
|
</Form>
|
|
@ -1,14 +1,23 @@
|
||||||
import { backend, backendProxy } from '../../../lib/db/db.js';
|
import { backend, backendProxy } from '../../../../lib/db/db.js';
|
||||||
|
|
||||||
import { readFile, writeFile } from 'node:fs/promises';
|
import { readFile, writeFile } from 'node:fs/promises';
|
||||||
|
|
||||||
|
const FILE_DIRS = [
|
||||||
|
'upload',
|
||||||
|
'pfp'
|
||||||
|
]
|
||||||
|
|
||||||
/** @type {import('./$types').RequestHandler} */
|
/** @type {import('./$types').RequestHandler} */
|
||||||
export async function GET({ url, cookies, params }) {
|
export async function GET({ url, cookies, params }) {
|
||||||
var imgName = params['img'];
|
var imgName = params['img'];
|
||||||
|
|
||||||
imgName = imgName.replace(/(\s+)/g, '\\$1');
|
imgName = imgName.replace(/(\s+)/g, '\\$1');
|
||||||
|
|
||||||
var res = await readFile(`${process.cwd()}/db/post-${imgName}`);
|
var dir = params['dir'];
|
||||||
|
|
||||||
|
if (FILE_DIRS.indexOf(dir) == -1) dir = FILE_DIRS[0];
|
||||||
|
|
||||||
|
var res = await readFile(`${process.cwd()}/db/files/${dir}/${imgName}`);
|
||||||
|
|
||||||
var response = new Response(res);
|
var response = new Response(res);
|
||||||
var extension = imgName.split('.').pop();
|
var extension = imgName.split('.').pop();
|
|
@ -1,24 +0,0 @@
|
||||||
import { VALID_EXTENSIONS } from '../../../lib/db/db.js';
|
|
||||||
|
|
||||||
import { readFile } from 'node:fs/promises';
|
|
||||||
|
|
||||||
/** @type {import('./$types').RequestHandler} */
|
|
||||||
export async function GET({ url, cookies, params }) {
|
|
||||||
var imgName = params['img'];
|
|
||||||
|
|
||||||
imgName = imgName.replace(/(\s+)/g, '\\$1');
|
|
||||||
|
|
||||||
var res;
|
|
||||||
|
|
||||||
var res = await readFile(`${process.cwd()}/db/pfp-${imgName}`);
|
|
||||||
|
|
||||||
var response = new Response(res);
|
|
||||||
var extension = imgName.split('.').pop();
|
|
||||||
|
|
||||||
if (extension == 'svg') {
|
|
||||||
response = new Response(res, {'headers': {
|
|
||||||
'Content-Type': 'image/png'
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
|
@ -10,7 +10,6 @@
|
||||||
let uploadForm = {};
|
let uploadForm = {};
|
||||||
|
|
||||||
let userData = data.postJsonUser.data;
|
let userData = data.postJsonUser.data;
|
||||||
let userBio = data.postJsonUserBio.data;
|
|
||||||
|
|
||||||
let following = data.postJsonUser.following;
|
let following = data.postJsonUser.following;
|
||||||
let followers = data.postJsonUser.followers;
|
let followers = data.postJsonUser.followers;
|
||||||
|
@ -37,67 +36,106 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.pfp {
|
.pfp {
|
||||||
width: 50px;
|
width: 100px;
|
||||||
height: 50px;
|
height: 100px;
|
||||||
margin-right: 10px;
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pfp-small {
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sections {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sections div {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sections div:nth-child(1) {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{#if userData}
|
{#if userData}
|
||||||
<Area>
|
<Area>
|
||||||
<span slot="header" id='header'>
|
<span slot="header" id='header'>
|
||||||
<img class='pfp' src='/pfp/{userData.username}.png'/>
|
<div class='profile'>
|
||||||
<a href='/users/{userData.username}'>
|
<img class='pfp' src='/img/pfp/{userData.username}.png'/>
|
||||||
{userData.username}
|
<a href='/users/{userData.username}'>
|
||||||
</a>
|
{userData.username}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button clickFunc={follow}>
|
||||||
|
Follow
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
<span slot="main">
|
<span slot="main">
|
||||||
<div class='left'></div>
|
<p class='data'>
|
||||||
<p>
|
<span class='follower'>
|
||||||
<b>Reputation:</b> {userData.reputation}
|
<b>{userData.reputation}</b> Reputation
|
||||||
|
</span>
|
||||||
|
<span class='follower'>
|
||||||
|
<b>{userData.upvotes}</b> Upvotes
|
||||||
|
</span>
|
||||||
|
<span class='follower'>
|
||||||
|
<b>{userData.downvotes}</b> Downvotes
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
|
||||||
<b>Upvotes:</b> {userData.upvotes}
|
{#if userData.rolesArr}
|
||||||
</p>
|
<p>
|
||||||
<p>
|
{#each userData.rolesArr as role}
|
||||||
<b>Downvotes:</b> {userData.downvotes}
|
<b class='follower'>{role}</b>
|
||||||
</p>
|
|
||||||
<h2>Roles</h2>
|
|
||||||
<p>
|
|
||||||
{#if userBio && userBio.rolesArr}
|
|
||||||
{#each userBio.rolesArr as role}
|
|
||||||
<i class='follower'>{role}</i>
|
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
</p>
|
||||||
</p>
|
{/if}
|
||||||
|
|
||||||
<h2>Following</h2>
|
<div class='sections'>
|
||||||
{#each following as user}
|
<div>
|
||||||
<a class='follower' href='/users/{user.following}'>
|
<h2>{following.length} followers</h2>
|
||||||
<img class='pfp' src='/pfp/{user.following}.png'/>
|
{#each following as user}
|
||||||
</a>
|
<a class='follower' href='/users/{user.following}'>
|
||||||
{/each}
|
<img class='pfp-small' src='/img/pfp/{user.following}.png'/>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>{followers.length} following</h2>
|
||||||
|
{#each followers as user}
|
||||||
|
<a class='follower' href='/users/{user.username}'>
|
||||||
|
<img class='pfp-small' src='/img/pfp/{user.username}.png'/>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>Followers</h2>
|
|
||||||
{#each followers as user}
|
|
||||||
<a class='follower' href='/users/{user.username}'>
|
|
||||||
<img class='pfp' src='/pfp/{user.username}.png'/>
|
|
||||||
</a>
|
|
||||||
{/each}
|
|
||||||
{#if data.resAcc.data == userData.username}
|
{#if data.resAcc.data == userData.username}
|
||||||
<h2>Set PFP</h2>
|
<h2>Set PFP</h2>
|
||||||
<FileUpload bind:form={uploadForm} type='small' apiUrl={'/api/pfp'}/>
|
<FileUpload bind:form={uploadForm} type='small' apiUrl={'/api/pfp'}/>
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<Button clickFunc={follow}>
|
|
||||||
Follow
|
|
||||||
</Button>
|
|
||||||
</span>
|
</span>
|
||||||
</Area>
|
</Area>
|
||||||
{:else}
|
{:else}
|
||||||
|
|
Loading…
Reference in a new issue