mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
225 lines
6.3 KiB
TypeScript
225 lines
6.3 KiB
TypeScript
import { IFile, ValueOf } from '~/redux/types';
|
||
import formatDistanceToNow from 'date-fns/formatDistanceToNow';
|
||
import isAfter from 'date-fns/isAfter';
|
||
import differenceInMonths from 'date-fns/differenceInMonths';
|
||
import differenceInMinutes from 'date-fns/differenceInMinutes';
|
||
import ru from 'date-fns/locale/ru';
|
||
import Axios from 'axios';
|
||
import { PRESETS } from '~/constants/urls';
|
||
import { ICommentBlock, COMMENT_BLOCK_DETECTORS, COMMENT_BLOCK_TYPES } from '~/constants/comment';
|
||
import format from 'date-fns/format';
|
||
|
||
export const getStyle = (oElm: any, strCssRule: string) => {
|
||
if (document.defaultView && document.defaultView.getComputedStyle) {
|
||
return document.defaultView.getComputedStyle(oElm, '').getPropertyValue(strCssRule);
|
||
}
|
||
|
||
if (oElm.currentStyle) {
|
||
return oElm.currentStyle[strCssRule.replace(/-(\w)/g, (strMatch, p1) => p1.toUpperCase())];
|
||
}
|
||
|
||
return '';
|
||
};
|
||
|
||
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
|
||
const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;
|
||
|
||
return {
|
||
x: centerX + radius * Math.cos(angleInRadians),
|
||
y: centerY + radius * Math.sin(angleInRadians),
|
||
};
|
||
}
|
||
|
||
export const describeArc = (
|
||
x: number,
|
||
y: number,
|
||
radius: number,
|
||
startAngle: number = 0,
|
||
endAngle: number = 360
|
||
): string => {
|
||
const start = polarToCartesian(x, y, radius, endAngle);
|
||
const end = polarToCartesian(x, y, radius, startAngle);
|
||
|
||
const largeArcFlag = endAngle - startAngle <= 180 ? 0 : 1;
|
||
|
||
return [
|
||
'M',
|
||
start.x,
|
||
start.y,
|
||
'A',
|
||
radius,
|
||
radius,
|
||
0,
|
||
largeArcFlag,
|
||
0,
|
||
end.x,
|
||
end.y,
|
||
'L',
|
||
x,
|
||
y,
|
||
'L',
|
||
start.x,
|
||
start.y,
|
||
].join(' ');
|
||
};
|
||
|
||
export const getURL = (file: Partial<IFile>, size?: typeof PRESETS[keyof typeof PRESETS]) => {
|
||
if (!file || !file.url) return null;
|
||
|
||
if (size) {
|
||
return file.url
|
||
.replace('REMOTE_CURRENT://', `${process.env.REMOTE_CURRENT}cache/${size}/`)
|
||
.replace('REMOTE_OLD://', process.env.REMOTE_OLD);
|
||
}
|
||
|
||
return file.url
|
||
.replace('REMOTE_CURRENT://', process.env.REMOTE_CURRENT)
|
||
.replace('REMOTE_OLD://', process.env.REMOTE_OLD);
|
||
};
|
||
|
||
export const formatText = (text: string): string =>
|
||
!text
|
||
? ''
|
||
: text
|
||
.replace(
|
||
/(https?:\/\/(www\.)?(youtube\.com|youtu\.be)\/(watch)?(\?v=)?[\w\-\&\=]+)/gim,
|
||
'\n$1\n'
|
||
)
|
||
.replace(/\n{1,}/gim, '\n')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>')
|
||
.replace(
|
||
/~([\wа-яА-Я-]+)/giu,
|
||
'<span class="username" onClick="window.postMessage({ type: \'username\', username: \'$1\'});">~$1</span>'
|
||
)
|
||
.replace(/:\/\//gim, ':|--|')
|
||
.replace(/(\/\/[^\n]+)/gim, '<span class="grey">$1</span>')
|
||
.replace(/(\*\*[\s\S]*?\*\*)/gim, '<b class="bold white">$1</b>')
|
||
.replace(/(\_\_[\s\S]*?\_\_)/gim, '<i>$1</i>')
|
||
.replace(/(\!\![\s\S]*?(\!\!|\n|$))/gim, '<span class="green">$1</span>')
|
||
.replace(/(\/\*[\s\S]*?\*\/)/gim, '<span class="grey">$1</span>')
|
||
.replace(/([=|-]{5,})/gim, '<hr />')
|
||
.replace(/:\|--\|/gim, '://')
|
||
.replace(
|
||
/(\b(https?|ftp|file):\/\/([-A-Z0-9+&@#%?=~_|!:,.;]*)([-A-Z0-9+&@#%?\/=~_|!:,.;]*)[-A-Z0-9+&@#\/%=~_|])/gi,
|
||
'<a href="$1" target="blank" rel="nofollow">$1</a>'
|
||
)
|
||
.split('\n')
|
||
.filter(el => el.trim().length)
|
||
.join('\n');
|
||
|
||
export const formatTextParagraphs = (text: string): string =>
|
||
(text &&
|
||
formatText(text)
|
||
.split('\n')
|
||
.map(str => `<p>${str}</p>`)
|
||
.join('\n')) ||
|
||
null;
|
||
|
||
export const findBlockType = (line: string): ValueOf<typeof COMMENT_BLOCK_TYPES> => {
|
||
const match = Object.values(COMMENT_BLOCK_DETECTORS).find(detector => line.match(detector.test));
|
||
return (match && match.type) || COMMENT_BLOCK_TYPES.TEXT;
|
||
};
|
||
|
||
export const splitCommentByBlocks = (text: string): ICommentBlock[] =>
|
||
text.split('\n').map(line => ({
|
||
type: findBlockType(line),
|
||
content: line,
|
||
}));
|
||
|
||
export const formatCommentText = (author: string, text: string): ICommentBlock[] =>
|
||
text ? splitCommentByBlocks(formatText(text)) : null;
|
||
|
||
export const formatCellText = (text: string): string => formatTextParagraphs(text);
|
||
|
||
export const getPrettyDate = (date: string): string => {
|
||
if (differenceInMonths(new Date(), new Date(date)) >= 3) {
|
||
return format(new Date(date), 'd MMMM yyyy', { locale: ru });
|
||
}
|
||
|
||
return isAfter(new Date(date), new Date()) ||
|
||
differenceInMinutes(new Date(), new Date(date)) <= 30
|
||
? 'Только что'
|
||
: formatDistanceToNow(new Date(date), {
|
||
locale: ru,
|
||
includeSeconds: true,
|
||
addSuffix: true,
|
||
});
|
||
};
|
||
|
||
export const getYoutubeTitle = async (id: string) => {
|
||
Axios.get(`http://youtube.com/get_video_info?video_id=${id}`).then(console.log);
|
||
};
|
||
|
||
export const getYoutubeThumb = (url: string) => {
|
||
const match =
|
||
url &&
|
||
url.match(
|
||
/http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?/
|
||
);
|
||
|
||
return match && match[1] ? `https://i.ytimg.com/vi/${match[1]}/hqdefault.jpg` : null;
|
||
};
|
||
|
||
export function plural(n: number, one: string, two: string, five: string) {
|
||
if (n % 10 === 1 && n % 100 !== 11) {
|
||
return `${n} ${one}`;
|
||
} else if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) {
|
||
return `${n} ${two}`;
|
||
} else {
|
||
return `${n} ${five}`;
|
||
}
|
||
}
|
||
|
||
export const stringToColour = (str: string) => {
|
||
let hash = 0;
|
||
|
||
for (let i = 0; i < str.length; i++) {
|
||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||
}
|
||
|
||
let colour = '#';
|
||
|
||
for (let i = 0; i < 3; i++) {
|
||
let value = (hash >> (i * 8)) & 0xff;
|
||
colour += ('00' + value.toString(16)).substr(-2);
|
||
}
|
||
|
||
return colour;
|
||
};
|
||
|
||
export const darken = (col: string, amt: number) => {
|
||
var usePound = false;
|
||
|
||
if (col[0] == '#') {
|
||
col = col.slice(1);
|
||
usePound = true;
|
||
}
|
||
|
||
var num = parseInt(col, 16);
|
||
|
||
var r = (num >> 16) + amt;
|
||
|
||
if (r > 255) r = 255;
|
||
else if (r < 0) r = 0;
|
||
|
||
var b = ((num >> 8) & 0x00ff) + amt;
|
||
|
||
if (b > 255) b = 255;
|
||
else if (b < 0) b = 0;
|
||
|
||
var g = (num & 0x0000ff) + amt;
|
||
|
||
if (g > 255) g = 255;
|
||
else if (g < 0) g = 0;
|
||
|
||
return (usePound ? '#' : '') + (g | (b << 8) | (r << 16)).toString(16);
|
||
};
|
||
|
||
export const sizeOf = (bytes: number): string => {
|
||
if (bytes == 0) {
|
||
return '0.00 B';
|
||
}
|
||
var e = Math.floor(Math.log(bytes) / Math.log(1024));
|
||
return (bytes / Math.pow(1024, e)).toFixed(2) + ' ' + ' KMGTP'.charAt(e) + 'B';
|
||
};
|