summaryrefslogtreecommitdiffstats
path: root/ui/src
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2020-06-23 21:11:38 -0400
committerDessalines <tyhou13@gmx.com>2020-06-23 21:11:38 -0400
commitdc94e58cbf7e7de10d97331a3056380a3416e0b0 (patch)
tree85ed25783b0470ead3012a9718aea50b39c940dd /ui/src
parentfd6a040568239d2e6949394fdc0ce0f7ac70275c (diff)
parent790b944031f9433be765936763d848ffa6e1b496 (diff)
Merge branch 'master' into federation_merge_from_master_2
Diffstat (limited to 'ui/src')
-rw-r--r--ui/src/components/comment-form.tsx90
-rw-r--r--ui/src/components/comment-node.tsx47
-rw-r--r--ui/src/components/community-form.tsx6
-rw-r--r--ui/src/components/inbox.tsx20
-rw-r--r--ui/src/components/login.tsx1
-rw-r--r--ui/src/components/navbar.tsx4
-rw-r--r--ui/src/components/post-form.tsx42
-rw-r--r--ui/src/components/post-listing.tsx10
-rw-r--r--ui/src/components/private-message-form.tsx8
-rw-r--r--ui/src/components/private-message.tsx9
-rw-r--r--ui/src/components/site-form.tsx8
-rw-r--r--ui/src/components/user-listing.tsx4
-rw-r--r--ui/src/components/user.tsx25
-rw-r--r--ui/src/index.html3
-rw-r--r--ui/src/services/UserService.ts4
-rw-r--r--ui/src/utils.ts100
-rw-r--r--ui/src/version.ts2
17 files changed, 251 insertions, 132 deletions
diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx
index b3c1a9a1..0fb7824e 100644
--- a/ui/src/components/comment-form.tsx
+++ b/ui/src/components/comment-form.tsx
@@ -18,6 +18,7 @@ import {
setupTribute,
wsJsonToRes,
emojiPicker,
+ pictrsDeleteToast,
} from '../utils';
import { WebSocketService, UserService } from '../services';
import autosize from 'autosize';
@@ -60,7 +61,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
buttonTitle: !this.props.node
? capitalizeFirstLetter(i18n.t('post'))
: this.props.edit
- ? capitalizeFirstLetter(i18n.t('edit'))
+ ? capitalizeFirstLetter(i18n.t('save'))
: capitalizeFirstLetter(i18n.t('reply')),
previewMode: false,
loading: false,
@@ -137,7 +138,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
/>
{this.state.previewMode && (
<div
- className="md-div"
+ className="card card-body md-div"
dangerouslySetInnerHTML={mdToHtml(
this.state.commentForm.content
)}
@@ -150,7 +151,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
<button
type="submit"
class="btn btn-sm btn-secondary mr-2"
- disabled={this.props.disabled}
+ disabled={this.props.disabled || this.state.loading}
>
{this.state.loading ? (
<svg class="icon icon-spinner spin">
@@ -244,18 +245,32 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
});
}
- handleFinished() {
- this.state.previewMode = false;
- this.state.loading = false;
- this.state.commentForm.content = '';
- this.setState(this.state);
- let form: any = document.getElementById(this.formId);
- form.reset();
- if (this.props.node) {
- this.props.onReplyCancel();
+ handleFinished(data: CommentResponse) {
+ let isReply =
+ this.props.node !== undefined && data.comment.parent_id !== null;
+ let xor =
+ +!(data.comment.parent_id !== null) ^ +(this.props.node !== undefined);
+
+ if (
+ (data.comment.creator_id == UserService.Instance.user.id &&
+ // If its a reply, make sure parent child match
+ isReply &&
+ data.comment.parent_id == this.props.node.comment.id) ||
+ // Otherwise, check the XOR of the two
+ (!isReply && xor)
+ ) {
+ this.state.previewMode = false;
+ this.state.loading = false;
+ this.state.commentForm.content = '';
+ this.setState(this.state);
+ let form: any = document.getElementById(this.formId);
+ form.reset();
+ if (this.props.node) {
+ this.props.onReplyCancel();
+ }
+ autosize.update(form);
+ this.setState(this.state);
}
- autosize.update(document.querySelector('textarea'));
- this.setState(this.state);
}
handleCommentSubmit(i: CommentForm, event: any) {
@@ -305,9 +320,9 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
file = event;
}
- const imageUploadUrl = `/pictshare/api/upload.php`;
+ const imageUploadUrl = `/pictrs/image`;
const formData = new FormData();
- formData.append('file', file);
+ formData.append('images[]', file);
i.state.imageLoading = true;
i.setState(i.state);
@@ -318,16 +333,31 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
})
.then(res => res.json())
.then(res => {
- let url = `${window.location.origin}/pictshare/${res.url}`;
- let imageMarkdown =
- res.filetype == 'mp4' ? `[vid](${url}/raw)` : `![](${url})`;
- let content = i.state.commentForm.content;
- content = content ? `${content}\n${imageMarkdown}` : imageMarkdown;
- i.state.commentForm.content = content;
- i.state.imageLoading = false;
- i.setState(i.state);
- let textarea: any = document.getElementById(i.id);
- autosize.update(textarea);
+ console.log('pictrs upload:');
+ console.log(res);
+ if (res.msg == 'ok') {
+ let hash = res.files[0].file;
+ let url = `${window.location.origin}/pictrs/image/${hash}`;
+ let deleteToken = res.files[0].delete_token;
+ let deleteUrl = `${window.location.origin}/pictrs/image/delete/${deleteToken}/${hash}`;
+ let imageMarkdown = `![](${url})`;
+ let content = i.state.commentForm.content;
+ content = content ? `${content}\n${imageMarkdown}` : imageMarkdown;
+ i.state.commentForm.content = content;
+ i.state.imageLoading = false;
+ i.setState(i.state);
+ let textarea: any = document.getElementById(i.id);
+ autosize.update(textarea);
+ pictrsDeleteToast(
+ i18n.t('click_to_delete_picture'),
+ i18n.t('picture_deleted'),
+ deleteUrl
+ );
+ } else {
+ i.state.imageLoading = false;
+ i.setState(i.state);
+ toast(JSON.stringify(res), 'danger');
+ }
})
.catch(error => {
i.state.imageLoading = false;
@@ -343,14 +373,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
if (UserService.Instance.user) {
if (res.op == UserOperation.CreateComment) {
let data = res.data as CommentResponse;
- if (data.comment.creator_id == UserService.Instance.user.id) {
- this.handleFinished();
- }
+ this.handleFinished(data);
} else if (res.op == UserOperation.EditComment) {
let data = res.data as CommentResponse;
- if (data.comment.creator_id == UserService.Instance.user.id) {
- this.handleFinished();
- }
+ this.handleFinished(data);
}
}
}
diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx
index ca828a45..155efe8e 100644
--- a/ui/src/components/comment-node.tsx
+++ b/ui/src/components/comment-node.tsx
@@ -132,7 +132,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
>
<div
id={`comment-${node.comment.id}`}
- className={`details comment-node border-top border-light ${
+ className={`details comment-node border-top border-light py-2 ${
this.isCommentNew ? 'mark' : ''
}`}
style={
@@ -148,7 +148,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
'ml-2'
}`}
>
- <div class="d-flex flex-wrap align-items-center mb-1 mt-1 text-muted small">
+ <div class="d-flex flex-wrap align-items-center text-muted small">
<span class="mr-2">
<UserListing
user={{
@@ -299,25 +299,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)}
<button
class="btn btn-link btn-animate text-muted"
- onClick={linkEvent(this, this.handleSaveCommentClick)}
- data-tippy-content={
- node.comment.saved ? i18n.t('unsave') : i18n.t('save')
- }
- >
- {this.state.saveLoading ? (
- this.loadingIcon
- ) : (
- <svg
- class={`icon icon-inline ${
- node.comment.saved && 'text-warning'
- }`}
- >
- <use xlinkHref="#icon-star"></use>
- </svg>
- )}
- </button>
- <button
- class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t('reply')}
>
@@ -352,6 +333,30 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)}
{!this.props.showContext && this.linkBtn}
<button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleSaveCommentClick
+ )}
+ data-tippy-content={
+ node.comment.saved
+ ? i18n.t('unsave')
+ : i18n.t('save')
+ }
+ >
+ {this.state.saveLoading ? (
+ this.loadingIcon
+ ) : (
+ <svg
+ class={`icon icon-inline ${
+ node.comment.saved && 'text-warning'
+ }`}
+ >
+ <use xlinkHref="#icon-star"></use>
+ </svg>
+ )}
+ </button>
+ <button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')}
diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx
index eedc2003..90e12738 100644
--- a/ui/src/components/community-form.tsx
+++ b/ui/src/components/community-form.tsx
@@ -207,7 +207,11 @@ export class CommunityForm extends Component<
)}
<div class="form-group row">
<div class="col-12">
- <button type="submit" class="btn btn-secondary mr-2">
+ <button
+ type="submit"
+ class="btn btn-secondary mr-2"
+ disabled={this.state.loading}
+ >
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx
index 4fa1498a..edbacd51 100644
--- a/ui/src/components/inbox.tsx
+++ b/ui/src/components/inbox.tsx
@@ -123,7 +123,10 @@ export class Inbox extends Component<any, InboxState> {
this.state.unreadOrAll == UnreadOrAll.Unread && (
<ul class="list-inline mb-1 text-muted small font-weight-bold">
<li className="list-inline-item">
- <span class="pointer" onClick={this.markAllAsRead}>
+ <span
+ class="pointer"
+ onClick={linkEvent(this, this.markAllAsRead)}
+ >
{i18n.t('mark_all_as_read')}
</span>
</li>
@@ -392,8 +395,14 @@ export class Inbox extends Component<any, InboxState> {
this.refetch();
}
- markAllAsRead() {
+ markAllAsRead(i: Inbox) {
WebSocketService.Instance.markAllAsRead();
+ i.state.replies = [];
+ i.state.mentions = [];
+ i.state.messages = [];
+ i.sendUnreadCount();
+ window.scrollTo(0, 0);
+ i.setState(i.state);
}
parseMessage(msg: WebSocketJsonResponse) {
@@ -447,12 +456,7 @@ export class Inbox extends Component<any, InboxState> {
this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.MarkAllAsRead) {
- this.state.replies = [];
- this.state.mentions = [];
- this.state.messages = [];
- this.sendUnreadCount();
- window.scrollTo(0, 0);
- this.setState(this.state);
+ // Moved to be instant
} else if (res.op == UserOperation.EditComment) {
let data = res.data as CommentResponse;
editCommentRes(data, this.state.replies);
diff --git a/ui/src/components/login.tsx b/ui/src/components/login.tsx
index 84014f68..ce04d0d4 100644
--- a/ui/src/components/login.tsx
+++ b/ui/src/components/login.tsx
@@ -111,6 +111,7 @@ export class Login extends Component<any, State> {
required
/>
<button
+ type="button"
disabled={!validEmail(this.state.loginForm.username_or_email)}
onClick={linkEvent(this, this.handlePasswordReset)}
className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold"
diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx
index f1936be1..4cb74391 100644
--- a/ui/src/components/navbar.tsx
+++ b/ui/src/components/navbar.tsx
@@ -22,7 +22,7 @@ import {
} from '../interfaces';
import {
wsJsonToRes,
- pictshareAvatarThumbnail,
+ pictrsAvatarThumbnail,
showAvatars,
fetchLimit,
isCommentType,
@@ -218,7 +218,7 @@ export class Navbar extends Component<any, NavbarState> {
<span>
{UserService.Instance.user.avatar && showAvatars() && (
<img
- src={pictshareAvatarThumbnail(
+ src={pictrsAvatarThumbnail(
UserService.Instance.user.avatar
)}
height="32"
diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx
index 22224c34..9f5aa363 100644
--- a/ui/src/components/post-form.tsx
+++ b/ui/src/components/post-form.tsx
@@ -36,6 +36,7 @@ import {
setupTippy,
emojiPicker,
hostname,
+ pictrsDeleteToast,
} from '../utils';
import autosize from 'autosize';
import Tribute from 'tributejs/src/Tribute.js';
@@ -284,7 +285,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
/>
{this.state.previewMode && (
<div
- className="md-div"
+ className="card card-body md-div"
dangerouslySetInnerHTML={mdToHtml(this.state.postForm.body)}
/>
)}
@@ -364,7 +365,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
<div class="form-group row">
<div class="col-sm-10">
<button
- disabled={!this.state.postForm.community_id}
+ disabled={
+ !this.state.postForm.community_id || this.state.loading
+ }
type="submit"
class="btn btn-secondary mr-2"
>
@@ -410,6 +413,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
handlePostSubmit(i: PostForm, event: any) {
event.preventDefault();
+
+ // Coerce empty url string to undefined
+ if (i.state.postForm.url && i.state.postForm.url === '') {
+ i.state.postForm.url = undefined;
+ }
+
if (i.props.post) {
WebSocketService.Instance.editPost(i.state.postForm);
} else {
@@ -523,9 +532,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
file = event;
}
- const imageUploadUrl = `/pictshare/api/upload.php`;
+ const imageUploadUrl = `/pictrs/image`;
const formData = new FormData();
- formData.append('file', file);
+ formData.append('images[]', file);
i.state.imageLoading = true;
i.setState(i.state);
@@ -536,13 +545,26 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
})
.then(res => res.json())
.then(res => {
- let url = `${window.location.origin}/pictshare/${encodeURI(res.url)}`;
- if (res.filetype == 'mp4') {
- url += '/raw';
+ console.log('pictrs upload:');
+ console.log(res);
+ if (res.msg == 'ok') {
+ let hash = res.files[0].file;
+ let url = `${window.location.origin}/pictrs/image/${hash}`;
+ let deleteToken = res.files[0].delete_token;
+ let deleteUrl = `${window.location.origin}/pictrs/image/delete/${deleteToken}/${hash}`;
+ i.state.postForm.url = url;
+ i.state.imageLoading = false;
+ i.setState(i.state);
+ pictrsDeleteToast(
+ i18n.t('click_to_delete_picture'),
+ i18n.t('picture_deleted'),
+ deleteUrl
+ );
+ } else {
+ i.state.imageLoading = false;
+ i.setState(i.state);
+ toast(JSON.stringify(res), 'danger');
}
- i.state.postForm.url = url;
- i.state.imageLoading = false;
- i.setState(i.state);
})
.catch(error => {
i.state.imageLoading = false;
diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx
index def42e3c..b4cc4f92 100644
--- a/ui/src/components/post-listing.tsx
+++ b/ui/src/components/post-listing.tsx
@@ -29,7 +29,7 @@ import {
isImage,
isVideo,
getUnixTime,
- pictshareImage,
+ pictrsImage,
setupTippy,
hostname,
previewLines,
@@ -163,15 +163,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
getImage(thumbnail: boolean = false) {
let post = this.props.post;
if (isImage(post.url)) {
- if (post.url.includes('pictshare')) {
- return pictshareImage(post.url, thumbnail);
+ if (post.url.includes('pictrs')) {
+ return pictrsImage(post.url, thumbnail);
} else if (post.thumbnail_url) {
- return pictshareImage(post.thumbnail_url, thumbnail);
+ return pictrsImage(post.thumbnail_url, thumbnail);
} else {
return post.url;
}
} else if (post.thumbnail_url) {
- return pictshareImage(post.thumbnail_url, thumbnail);
+ return pictrsImage(post.thumbnail_url, thumbnail);
}
}
diff --git a/ui/src/components/private-message-form.tsx b/ui/src/components/private-message-form.tsx
index 64e22d61..8cb7590e 100644
--- a/ui/src/components/private-message-form.tsx
+++ b/ui/src/components/private-message-form.tsx
@@ -157,7 +157,7 @@ export class PrivateMessageForm extends Component<
/>
{this.state.previewMode && (
<div
- className="md-div"
+ className="card card-body md-div"
dangerouslySetInnerHTML={mdToHtml(
this.state.privateMessageForm.content
)}
@@ -186,7 +186,11 @@ export class PrivateMessageForm extends Component<
)}
<div class="form-group row">
<div class="offset-sm-2 col-sm-10">
- <button type="submit" class="btn btn-secondary mr-2">
+ <button
+ type="submit"
+ class="btn btn-secondary mr-2"
+ disabled={this.state.loading}
+ >
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
diff --git a/ui/src/components/private-message.tsx b/ui/src/components/private-message.tsx
index 3acd6e19..71924f0c 100644
--- a/ui/src/components/private-message.tsx
+++ b/ui/src/components/private-message.tsx
@@ -5,12 +5,7 @@ import {
EditPrivateMessageForm,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
-import {
- mdToHtml,
- pictshareAvatarThumbnail,
- showAvatars,
- toast,
-} from '../utils';
+import { mdToHtml, pictrsAvatarThumbnail, showAvatars, toast } from '../utils';
import { MomentTime } from './moment-time';
import { PrivateMessageForm } from './private-message-form';
import { i18n } from '../i18next';
@@ -78,7 +73,7 @@ export class PrivateMessage extends Component<
<img
height="32"
width="32"
- src={pictshareAvatarThumbnail(
+ src={pictrsAvatarThumbnail(
this.mine
? message.recipient_avatar
: message.creator_avatar
diff --git a/ui/src/components/site-form.tsx b/ui/src/components/site-form.tsx
index f0c80585..a51286c8 100644
--- a/ui/src/components/site-form.tsx
+++ b/ui/src/components/site-form.tsx
@@ -78,7 +78,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
<form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
<h5>{`${
this.props.site
- ? capitalizeFirstLetter(i18n.t('edit'))
+ ? capitalizeFirstLetter(i18n.t('save'))
: capitalizeFirstLetter(i18n.t('name'))
} ${i18n.t('your_site')}`}</h5>
<div class="form-group row">
@@ -175,7 +175,11 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</div>
<div class="form-group row">
<div class="col-12">
- <button type="submit" class="btn btn-secondary mr-2">
+ <button
+ type="submit"
+ class="btn btn-secondary mr-2"
+ disabled={this.state.loading}
+ >
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
diff --git a/ui/src/components/user-listing.tsx b/ui/src/components/user-listing.tsx
index 903aa1a7..0e150b94 100644
--- a/ui/src/components/user-listing.tsx
+++ b/ui/src/components/user-listing.tsx
@@ -1,7 +1,7 @@
import { Component } from 'inferno';
import { Link } from 'inferno-router';
import { UserView } from '../interfaces';
-import { pictshareAvatarThumbnail, showAvatars, hostname } from '../utils';
+import { pictrsAvatarThumbnail, showAvatars, hostname } from '../utils';
interface UserOther {
name: string;
@@ -40,7 +40,7 @@ export class UserListing extends Component<UserListingProps, any> {
<img
height="32"
width="32"
- src={pictshareAvatarThumbnail(user.avatar)}
+ src={pictrsAvatarThumbnail(user.avatar)}
class="rounded-circle mr-2"
/>
)}
diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx
index 78807153..f635a1cd 100644
--- a/ui/src/components/user.tsx
+++ b/ui/src/components/user.tsx
@@ -927,7 +927,7 @@ export class User extends Component<any, UserState> {
handleUserSettingsThemeChange(i: User, event: any) {
i.state.userSettingsForm.theme = event.target.value;
- setTheme(event.target.value);
+ setTheme(event.target.value, true);
i.setState(i.state);
}
@@ -993,9 +993,9 @@ export class User extends Component<any, UserState> {
handleImageUpload(i: User, event: any) {
event.preventDefault();
let file = event.target.files[0];
- const imageUploadUrl = `/pictshare/api/upload.php`;
+ const imageUploadUrl = `/pictrs/image`;
const formData = new FormData();
- formData.append('file', file);
+ formData.append('images[]', file);
i.state.avatarLoading = true;
i.setState(i.state);
@@ -1006,14 +1006,19 @@ export class User extends Component<any, UserState> {
})
.then(res => res.json())
.then(res => {
- let url = `${window.location.origin}/pictshare/${res.url}`;
- if (res.filetype == 'mp4') {
- url += '/raw';
+ console.log('pictrs upload:');
+ console.log(res);
+ if (res.msg == 'ok') {
+ let hash = res.files[0].file;
+ let url = `${window.location.origin}/pictrs/image/${hash}`;
+ i.state.userSettingsForm.avatar = url;
+ i.state.avatarLoading = false;
+ i.setState(i.state);
+ } else {
+ i.state.avatarLoading = false;
+ i.setState(i.state);
+ toast(JSON.stringify(res), 'danger');
}
- i.state.userSettingsForm.avatar = url;
- console.log(url);
- i.state.avatarLoading = false;
- i.setState(i.state);
})
.catch(error => {
i.state.avatarLoading = false;
diff --git a/ui/src/index.html b/ui/src/index.html
index f39773d0..07d188e2 100644
--- a/ui/src/index.html
+++ b/ui/src/index.html
@@ -15,7 +15,8 @@
<link rel="stylesheet" type="text/css" href="/static/assets/css/toastify.css" />
<link rel="stylesheet" type="text/css" href="/static/assets/css/selectr.min.css" />
<link rel="stylesheet" type="text/css" href="/static/assets/css/tippy.css" />
- <link rel="stylesheet" type="text/css" href="/static/assets/css/themes/darkly.min.css" id="darkly" />
+ <link rel="stylesheet" type="text/css" href="/static/assets/css/themes/litely.min.css" id="default-light" media="(prefers-color-scheme: light)" />
+ <link rel="stylesheet" type="text/css" href="/static/assets/css/themes/darkly.min.css" id="default-dark" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)" />
<link rel="stylesheet" type="text/css" href="/static/assets/css/main.css" />
<!-- Scripts -->
diff --git a/ui/src/services/UserService.ts b/ui/src/services/UserService.ts
index 47e28c73..786d5d07 100644
--- a/ui/src/services/UserService.ts
+++ b/ui/src/services/UserService.ts
@@ -41,9 +41,7 @@ export class UserService {
private setUser(jwt: string) {
this.user = jwt_decode(jwt);
- if (this.user.theme != 'darkly') {
- setTheme(this.user.theme);
- }
+ setTheme(this.user.theme, true);
this.sub.next({ user: this.user });
console.log(this.user);
}
diff --git a/ui/src/utils.ts b/ui/src/utils.ts
index 5ce84b39..071b86ac 100644
--- a/ui/src/utils.ts
+++ b/ui/src/utils.ts
@@ -103,6 +103,7 @@ export const themes = [
'vaporwave',
'vaporwave-dark',
'i386',
+ 'litely',
];
export const emojiPicker = new EmojiButton({
@@ -113,11 +114,26 @@ export const emojiPicker = new EmojiButton({
// TODO i18n
});
-export function randomStr() {
- return Math.random()
- .toString(36)
- .replace(/[^a-z]+/g, '')
- .substr(2, 10);
+const DEFAULT_ALPHABET =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+function getRandomCharFromAlphabet(alphabet: string): string {
+ return alphabet.charAt(Math.floor(Math.random() * alphabet.length));
+}
+
+export function randomStr(
+ idDesiredLength: number = 20,
+ alphabet = DEFAULT_ALPHABET
+): string {
+ /**
+ * Create n-long array and map it to random chars from given alphabet.
+ * Then join individual chars as string
+ */
+ return Array.from({ length: idDesiredLength })
+ .map(() => {
+ return getRandomCharFromAlphabet(alphabet);
+ })
+ .join('');
}
export function wsJsonToRes(msg: WebSocketJsonResponse): WebSocketResponse {
@@ -404,7 +420,7 @@ export function getMomentLanguage(): string {
return lang;
}
-export function setTheme(theme: string = 'darkly') {
+export function setTheme(theme: string = 'darkly', loggedIn: boolean = false) {
// unload all the other themes
for (var i = 0; i < themes.length; i++) {
let styleSheet = document.getElementById(themes[i]);
@@ -413,10 +429,23 @@ export function setTheme(theme: string = 'darkly') {
}
}
- // Load the theme dynamically
- let cssLoc = `/static/assets/css/themes/${theme}.min.css`;
- loadCss(theme, cssLoc);
- document.getElementById(theme).removeAttribute('disabled');
+ // if the user is not logged in, we load the default themes and let the browser decide
+ if (!loggedIn) {
+ document.getElementById('default-light').removeAttribute('disabled');
+ document.getElementById('default-dark').removeAttribute('disabled');
+ } else {
+ document
+ .getElementById('default-light')
+ .setAttribute('disabled', 'disabled');
+ document
+ .getElementById('default-dark')
+ .setAttribute('disabled', 'disabled');
+
+ // Load the theme dynamically
+ let cssLoc = `/static/assets/css/themes/${theme}.min.css`;
+ loadCss(theme, cssLoc);
+ document.getElementById(theme).removeAttribute('disabled');
+ }
}
export function loadCss(id: string, loc: string) {
@@ -440,10 +469,12 @@ export function objectFlip(obj: any) {
return ret;
}
-export function pictshareAvatarThumbnail(src: string): string {
- // sample url: http://localhost:8535/pictshare/gs7xuu.jpg
- let split = src.split('pictshare');
- let out = `${split[0]}pictshare/${canUseWebP() ? 'webp/' : ''}96${split[1]}`;
+export function pictrsAvatarThumbnail(src: string): string {
+ // sample url: http://localhost:8535/pictrs/image/thumbnail256/gs7xuu.jpg
+ let split = src.split('/pictrs/image');
+ let out = `${split[0]}/pictrs/image/${
+ canUseWebP() ? 'webp/' : ''
+ }thumbnail96${split[1]}`;
return out;
}
@@ -455,21 +486,18 @@ export function showAvatars(): boolean {
}
// Converts to image thumbnail
-export function pictshareImage(
- hash: string,
- thumbnail: boolean = false
-): string {
- let root = `/pictshare`;
+export function pictrsImage(hash: string, thumbnail: boolean = false): string {
+ let root = `/pictrs/image`;
// Necessary for other servers / domains
- if (hash.includes('pictshare')) {
- let split = hash.split('/pictshare/');
- root = `${split[0]}/pictshare`;
+ if (hash.includes('pictrs')) {
+ let split = hash.split('/pictrs/image/');
+ root = `${split[0]}/pictrs/image`;
hash = split[1];
}
let out = `${root}/${canUseWebP() ? 'webp/' : ''}${
- thumbnail ? '192/' : ''
+ thumbnail ? 'thumbnail256/' : ''
}${hash}`;
return out;
}
@@ -488,6 +516,29 @@ export function toast(text: string, background: string = 'success') {
}).showToast();
}
+export function pictrsDeleteToast(
+ clickToDeleteText: string,
+ deletePictureText: string,
+ deleteUrl: string
+) {
+ let backgroundColor = `var(--light)`;
+ let toast = Toastify({
+ text: clickToDeleteText,
+ backgroundColor: backgroundColor,
+ gravity: 'top',
+ position: 'right',
+ duration: 0,
+ onClick: () => {
+ if (toast) {
+ window.location.replace(deleteUrl);
+ alert(deletePictureText);
+ toast.hideToast();
+ }
+ },
+ close: true,
+ }).showToast();
+}
+
export function messageToastify(
creator: string,
avatar: string,
@@ -501,7 +552,7 @@ export function messageToastify(
text: `${body}<br />${creator}`,
avatar: avatar,
backgroundColor: backgroundColor,
- className: 'text-body',
+ className: 'text-dark',
close: true,
gravity: 'top',
position: 'right',
@@ -910,7 +961,6 @@ function canUseWebP() {
return false;
// var elem = document.createElement('canvas');
-
// if (!!(elem.getContext && elem.getContext('2d'))) {
// var testString = !(window.mozInnerScreenX == null) ? 'png' : 'webp';
// // was able or not to get WebP representation
diff --git a/ui/src/version.ts b/ui/src/version.ts
index 9ab