import 'moment/locale/ca';
import 'moment/locale/fa';
import 'moment/locale/pt-br';
+import 'moment/locale/ja';
+import 'moment/locale/ka';
import {
UserOperation,
Comment,
- CommentNode,
+ CommentNode as CommentNodeI,
Post,
PrivateMessage,
User,
import twemoji from 'twemoji';
import emojiShortName from 'emoji-short-name';
import Toastify from 'toastify-js';
+import tippy from 'tippy.js';
+import EmojiButton from '@joeattardi/emoji-button';
-export const repoUrl = 'https://github.com/dessalines/lemmy';
-export const markdownHelpUrl = '/docs/about_guide.html';
+export const repoUrl = 'https://github.com/LemmyNet/lemmy';
+export const helpGuideUrl = '/docs/about_guide.html';
+export const markdownHelpUrl = `${helpGuideUrl}#markdown-guide`;
+export const sortingHelpUrl = `${helpGuideUrl}#sorting`;
export const archiveUrl = 'https://archive.is';
export const postRefetchSeconds: number = 60 * 1000;
export const fetchLimit: number = 20;
export const mentionDropdownFetchLimit = 10;
+export const languages = [
+ { code: 'ca', name: 'Català' },
+ { code: 'en', name: 'English' },
+ { code: 'eo', name: 'Esperanto' },
+ { code: 'es', name: 'Español' },
+ { code: 'de', name: 'Deutsch' },
+ { code: 'ka', name: 'ქართული ენა' },
+ { code: 'fa', name: 'فارسی' },
+ { code: 'ja', name: '日本語' },
+ { code: 'pt_BR', name: 'Português Brasileiro' },
+ { code: 'zh', name: '中文' },
+ { code: 'fi', name: 'Suomi' },
+ { code: 'fr', name: 'Français' },
+ { code: 'sv', name: 'Svenska' },
+ { code: 'ru', name: 'Русский' },
+ { code: 'nl', name: 'Nederlands' },
+ { code: 'it', name: 'Italiano' },
+];
+
+export const themes = [
+ 'litera',
+ 'materia',
+ 'minty',
+ 'solar',
+ 'united',
+ 'cyborg',
+ 'darkly',
+ 'journal',
+ 'sketchy',
+ 'vaporwave',
+ 'vaporwave-dark',
+ 'i386',
+];
+
+export const emojiPicker = new EmojiButton({
+ // Use the emojiShortName from native
+ style: 'twemoji',
+ theme: 'dark',
+ position: 'auto-start',
+ // TODO i18n
+});
+
export function randomStr() {
return Math.random()
.toString(36)
typographer: true,
})
.use(markdown_it_container, 'spoiler', {
- validate: function(params: any) {
+ validate: function (params: any) {
return params.trim().match(/^spoiler\s+(.*)$/);
},
- render: function(tokens: any, idx: any) {
+ render: function (tokens: any, idx: any) {
var m = tokens[idx].info.trim().match(/^spoiler\s+(.*)$/);
if (tokens[idx].nesting === 1) {
defs: objectFlip(emojiShortName),
});
-md.renderer.rules.emoji = function(token, idx) {
+md.renderer.rules.emoji = function (token, idx) {
return twemoji.parse(token[idx].content);
};
return modIds.includes(creator_id);
}
-var imageRegex = new RegExp(
- `(http)?s?:?(\/\/[^"']*\.(?:png|jpg|jpeg|gif|png|svg))`
+const imageRegex = new RegExp(
+ /(http)?s?:?(\/\/[^"']*\.(?:jpg|jpeg|gif|png|svg))/
);
-var videoRegex = new RegExp(`(http)?s?:?(\/\/[^"']*\.(?:mp4))`);
+const videoRegex = new RegExp(`(http)?s?:?(\/\/[^"']*\.(?:mp4))`);
export function isImage(url: string) {
return imageRegex.test(url);
}
export function validEmail(email: string) {
- let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+ let re = /^(([^\s"(),.:;<>@[\\\]]+(\.[^\s"(),.:;<>@[\\\]]+)*)|(".+"))@((\[(?:\d{1,3}\.){3}\d{1,3}])|(([\dA-Za-z\-]+\.)+[A-Za-z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
let timeout: any;
// Calling debounce returns a new anonymous function
- return function() {
+ return function () {
// reference the context and args for the setTimeout function
var context = this,
args = arguments;
clearTimeout(timeout);
// Set the new timeout
- timeout = setTimeout(function() {
+ timeout = setTimeout(function () {
// Inside the timeout function, clear the timeout variable
// which will let the next execution run when in 'immediate' mode
timeout = null;
};
}
-export const languages = [
- { code: 'ca', name: 'Català' },
- { code: 'en', name: 'English' },
- { code: 'eo', name: 'Esperanto' },
- { code: 'es', name: 'Español' },
- { code: 'de', name: 'Deutsch' },
- { code: 'fa', name: 'فارسی' },
- { code: 'pt_BR', name: 'Português Brasileiro' },
- { code: 'zh', name: '中文' },
- { code: 'fi', name: 'Suomi' },
- { code: 'fr', name: 'Français' },
- { code: 'sv', name: 'Svenska' },
- { code: 'ru', name: 'Русский' },
- { code: 'nl', name: 'Nederlands' },
- { code: 'it', name: 'Italiano' },
-];
-
export function getLanguage(): string {
let user = UserService.Instance.user;
let lang = user && user.lang ? user.lang : 'browser';
lang = 'fa';
} else if (lang.startsWith('pt')) {
lang = 'pt-br';
+ } else if (lang.startsWith('ja')) {
+ lang = 'ja';
+ } else if (lang.startsWith('ka')) {
+ lang = 'ka';
} else {
lang = 'en';
}
return lang;
}
-export const themes = [
- 'litera',
- 'materia',
- 'minty',
- 'solar',
- 'united',
- 'cyborg',
- 'darkly',
- 'journal',
- 'sketchy',
- 'vaporwave',
- 'vaporwave-dark',
- 'i386',
-];
-
export function setTheme(theme: string = 'darkly') {
// unload all the other themes
for (var i = 0; i < themes.length; i++) {
);
}
-/// Converts to image thumbnail (only supports pictshare currently)
-export function imageThumbnailer(url: string): string {
- let split = url.split('pictshare');
- if (split.length > 1) {
- let out = `${split[0]}pictshare/192${split[1]}`;
- return out;
- } else {
- return url;
+// Converts to image thumbnail
+export function pictshareImage(
+ hash: string,
+ thumbnail: boolean = false
+): string {
+ let root = `/pictshare`;
+
+ // Necessary for other servers / domains
+ if (hash.includes('pictshare')) {
+ let split = hash.split('/pictshare/');
+ root = `${split[0]}/pictshare`;
+ hash = split[1];
}
+
+ let out = `${root}/${thumbnail ? '192/' : ''}${hash}`;
+ return out;
}
export function isCommentType(item: Comment | PrivateMessage): item is Comment {
}).showToast();
}
+export function messageToastify(
+ creator: string,
+ avatar: string,
+ body: string,
+ link: string,
+ router: any
+) {
+ let backgroundColor = `var(--light)`;
+
+ let toast = Toastify({
+ text: `${body}<br />${creator}`,
+ avatar: avatar,
+ backgroundColor: backgroundColor,
+ close: true,
+ gravity: 'top',
+ position: 'right',
+ duration: 0,
+ onClick: () => {
+ if (toast) {
+ toast.hideToast();
+ router.history.push(link);
+ }
+ },
+ }).showToast();
+}
+
export function setupTribute(): Tribute {
return new Tribute({
collection: [
{
trigger: ':',
menuItemTemplate: (item: any) => {
- let emoji = `:${item.original.key}:`;
- return `${item.original.val} ${emoji}`;
+ let shortName = `:${item.original.key}:`;
+ let twemojiIcon = twemoji.parse(item.original.val);
+ return `${twemojiIcon} ${shortName}`;
},
selectTemplate: (item: any) => {
return `:${item.original.key}:`;
allowSpaces: false,
autocompleteMode: true,
menuItemLimit: mentionDropdownFetchLimit,
+ menuShowMinLength: 2,
},
// Users
{
allowSpaces: false,
autocompleteMode: true,
menuItemLimit: mentionDropdownFetchLimit,
+ menuShowMinLength: 2,
},
// Communities
allowSpaces: false,
autocompleteMode: true,
menuItemLimit: mentionDropdownFetchLimit,
+ menuShowMinLength: 2,
},
],
});
}
+let tippyInstance = tippy('[data-tippy-content]');
+
+export function setupTippy() {
+ tippyInstance.forEach(e => e.destroy());
+ tippyInstance = tippy('[data-tippy-content]', {
+ delay: [500, 0],
+ // Display on "long press"
+ touch: ['hold', 500],
+ });
+}
+
function userSearch(text: string, cb: any) {
if (text) {
let form: SearchForm = {
export function commentsToFlatNodes(
comments: Array<Comment>
-): Array<CommentNode> {
- let nodes: Array<CommentNode> = [];
+): Array<CommentNodeI> {
+ let nodes: Array<CommentNodeI> = [];
for (let comment of comments) {
nodes.push({ comment: comment });
}
return nodes;
}
-export function commentSort(tree: Array<CommentNode>, sort: CommentSortType) {
+export function commentSort(tree: Array<CommentNodeI>, sort: CommentSortType) {
// First, put removed and deleted comments at the bottom, then do your other sorts
if (sort == CommentSortType.Top) {
tree.sort(
}
}
-export function commentSortSortType(tree: Array<CommentNode>, sort: SortType) {
+export function commentSortSortType(tree: Array<CommentNodeI>, sort: SortType) {
commentSort(tree, convertCommentSortType(sort));
}
}
}
-export function postSort(posts: Array<Post>, sort: SortType) {
+export function postSort(
+ posts: Array<Post>,
+ sort: SortType,
+ communityType: boolean
+) {
// First, put removed and deleted comments at the bottom, then do your other sorts
if (
sort == SortType.TopAll ||
) {
posts.sort(
(a, b) =>
- +a.removed - +b.removed || +a.deleted - +b.deleted || b.score - a.score
+ +a.removed - +b.removed ||
+ +a.deleted - +b.deleted ||
+ (communityType && +b.stickied - +a.stickied) ||
+ b.score - a.score
);
} else if (sort == SortType.New) {
posts.sort(
(a, b) =>
+a.removed - +b.removed ||
+a.deleted - +b.deleted ||
+ (communityType && +b.stickied - +a.stickied) ||
b.published.localeCompare(a.published)
);
} else if (sort == SortType.Hot) {
(a, b) =>
+a.removed - +b.removed ||
+a.deleted - +b.deleted ||
+ (communityType && +b.stickied - +a.stickied) ||
hotRankPost(b) - hotRankPost(a)
);
}
}
+
+export const colorList: Array<string> = [
+ hsl(0),
+ hsl(100),
+ hsl(150),
+ hsl(200),
+ hsl(250),
+ hsl(300),
+];
+
+function hsl(num: number) {
+ return `hsla(${num}, 35%, 50%, 1)`;
+}
+
+function randomHsl() {
+ return `hsla(${Math.random() * 360}, 100%, 50%, 1)`;
+}
+
+export function previewLines(text: string, lines: number = 3): string {
+ // Use lines * 2 because markdown requires 2 lines
+ return text
+ .split('\n')
+ .slice(0, lines * 2)
+ .join('\n');
+}
+
+export function hostname(url: string): string {
+ return new URL(url).hostname;
+}