You've already forked AstralRinth
forked from didirus/AstralRinth
Run pnpm format
This commit is contained in:
@@ -17,15 +17,16 @@ const config = {
|
||||
'--xl': '(min-width: 1280px)',
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
require('postcss-pxtorem'),
|
||||
require('autoprefixer'),
|
||||
process.env.NODE_ENV === 'development' && require('cssnano')({
|
||||
preset: 'default',
|
||||
})
|
||||
process.env.NODE_ENV === 'development' &&
|
||||
require('cssnano')({
|
||||
preset: 'default',
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { fetch } from 'undici';
|
||||
import { promises as fs } from 'fs';
|
||||
import sharp from 'sharp';
|
||||
import FastAverageColor from 'fast-average-color';
|
||||
import cliProgress from 'cli-progress';
|
||||
|
||||
export async function landingPage(API_URL: string) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import-glob "./styles/normalize.postcss"; /* Doesn't need to glob but fixes warning */
|
||||
@import-glob "./styles/themes/**.postcss";
|
||||
@import-glob "./styles/variables/**.postcss";
|
||||
@import-glob "./styles/classes/**.postcss";
|
||||
@import-glob "./styles/classes/**.postcss";
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
align-items: flex-start;
|
||||
margin-left: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
display: flex;
|
||||
grid-gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,4 +98,4 @@
|
||||
p {
|
||||
line-height: 130%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
border: none;
|
||||
border-top: 1px solid var(--color-divider);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
&__description {
|
||||
font-size: 1.2rem;
|
||||
color: var(--color-text-light)
|
||||
color: var(--color-text-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
color: var(--color-text-lightest);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
&:hover {
|
||||
color: var(--color-link);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,4 +134,4 @@
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@
|
||||
flex-wrap: wrap;
|
||||
margin-top: auto;
|
||||
grid-gap: 0.25rem 0.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
.title-tertiary {
|
||||
font-size: 16px;
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ ul {
|
||||
}
|
||||
|
||||
.icon {
|
||||
height: auto;
|
||||
width: 16px;
|
||||
min-width: 16px;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
height: auto;
|
||||
width: 16px;
|
||||
min-width: 16px;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
--rounded-max: 999999999px;
|
||||
|
||||
--font-standard: Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto,
|
||||
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
|
||||
--font-size-nm: 1rem; /* 16px */
|
||||
--font-size-xl: 1.5rem; /* 24px */
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
--shadow-raised-lg: 0px 2px 4px hsla(221, 39%, 11%, 0.2);
|
||||
--shadow-raised: 0px -2px 4px hsla(221, 39%, 11%, 0.1);
|
||||
--shadow-floating: hsla(0, 0%, 0%, 0) 0px 0px 0px 0px, hsla(0, 0%, 0%, 0) 0px 0px 0px 0px,
|
||||
hsla(0, 0%, 0%, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
|
||||
hsla(0, 0%, 0%, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
|
||||
--shadow-mobile-bar: hsla(0, 0%, 0%, 0.3) 0 0 20px 2px;
|
||||
|
||||
/* Text colors */
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
--shadow-raised-lg: 0px 2px 4px hsla(221, 39%, 11%, 0.2);
|
||||
--shadow-raised: 0px 2px 4px hsla(221, 39%, 11%, 0.1);
|
||||
--shadow-floating: hsla(0, 0%, 0%, 0) 0px 0px 0px 0px, hsla(0, 0%, 0%, 0) 0px 0px 0px 0px,
|
||||
hsla(0, 0%, 0%, 0.1) 0px 4px 6px -1px, hsla(0, 0%, 0%, 0.1) 0px 2px 4px -1px;
|
||||
hsla(0, 0%, 0%, 0.1) 0px 4px 6px -1px, hsla(0, 0%, 0%, 0.1) 0px 2px 4px -1px;
|
||||
--shadow-mobile-bar: hsla(0, 0%, 0%, 0.3) 0 0 20px 2px;
|
||||
|
||||
/* Text colors */
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
:root {
|
||||
/* Borders */
|
||||
--border-width: 1px;
|
||||
--border-style: solid;
|
||||
--border: var(--border-width) var(--border-style);
|
||||
/* Borders */
|
||||
--border-width: 1px;
|
||||
--border-style: solid;
|
||||
--border: var(--border-width) var(--border-style);
|
||||
|
||||
/* Rounded radii */
|
||||
--rounded-sm: 8px;
|
||||
--rounded: 10px;
|
||||
--rounded-lg: 12px;
|
||||
--rounded-max: 100px;
|
||||
--rounded-top: var(--rounded) var(--rounded) 0 0;
|
||||
--rounded-bottom: 0 0 var(--rounded) var(--rounded);
|
||||
--rounded-sm-top: var(--rounded-sm) var(--rounded-sm) 0 0;
|
||||
--rounded-sm-bottom: 0 0 var(--rounded-sm) var(--rounded-sm);
|
||||
}
|
||||
/* Rounded radii */
|
||||
--rounded-sm: 8px;
|
||||
--rounded: 10px;
|
||||
--rounded-lg: 12px;
|
||||
--rounded-max: 100px;
|
||||
--rounded-top: var(--rounded) var(--rounded) 0 0;
|
||||
--rounded-bottom: 0 0 var(--rounded) var(--rounded);
|
||||
--rounded-sm-top: var(--rounded-sm) var(--rounded-sm) 0 0;
|
||||
--rounded-sm-bottom: 0 0 var(--rounded-sm) var(--rounded-sm);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
:root {
|
||||
|
||||
/* these are values for the display CSS property */
|
||||
/*
|
||||
/* these are values for the display CSS property */
|
||||
/*
|
||||
--display-values: (
|
||||
block,
|
||||
flex,
|
||||
@@ -22,7 +21,7 @@
|
||||
);
|
||||
*/
|
||||
|
||||
/*
|
||||
/*
|
||||
These are our margin and padding utility spacers. The default step size we
|
||||
use is 8px. This gives us a key of:
|
||||
0 => 0px
|
||||
@@ -32,18 +31,18 @@
|
||||
4 => 24px
|
||||
5 => 32px
|
||||
6 => 40px */
|
||||
--spacer: 8px;
|
||||
--spacer: 8px;
|
||||
|
||||
/* Our spacing scale */
|
||||
--spacer-0: 0; /* 0 */
|
||||
--spacer-1: calc(var(--spacer) * 0.5); /* 4px */
|
||||
--spacer-2: --spacer; /* 8px */
|
||||
--spacer-3: calc(var(--spacer) * 2); /* 16px */
|
||||
--spacer-4: calc(var(--spacer) * 3); /* 24px */
|
||||
--spacer-5: calc(var(--spacer) * 4); /* 32px */
|
||||
--spacer-6: calc(var(--spacer) * 5); /* 40px */
|
||||
/* Our spacing scale */
|
||||
--spacer-0: 0; /* 0 */
|
||||
--spacer-1: calc(var(--spacer) * 0.5); /* 4px */
|
||||
--spacer-2: --spacer; /* 8px */
|
||||
--spacer-3: calc(var(--spacer) * 2); /* 16px */
|
||||
--spacer-4: calc(var(--spacer) * 3); /* 24px */
|
||||
--spacer-5: calc(var(--spacer) * 4); /* 32px */
|
||||
--spacer-6: calc(var(--spacer) * 5); /* 40px */
|
||||
|
||||
/*
|
||||
/*
|
||||
/* The list of spacer values
|
||||
--spacers: (
|
||||
--spacer-0,
|
||||
@@ -210,4 +209,4 @@
|
||||
@custom-media --sm (min-width: 544px);
|
||||
@custom-media --md (min-width: 768px);
|
||||
@custom-media --lg (min-width: 1012px);
|
||||
@custom-media --xl (min-width: 544px);
|
||||
@custom-media --xl (min-width: 544px);
|
||||
|
||||
@@ -1,38 +1,39 @@
|
||||
:root {
|
||||
/* Heading sizes - mobile */
|
||||
/* h4-h6 remain the same size on both mobile & desktop */
|
||||
--h00-size-mobile: 40px;
|
||||
--h0-size-mobile: 32px;
|
||||
--h1-size-mobile: 26px;
|
||||
--h2-size-mobile: 22px;
|
||||
--h3-size-mobile: 18px;
|
||||
/* Heading sizes - mobile */
|
||||
/* h4-h6 remain the same size on both mobile & desktop */
|
||||
--h00-size-mobile: 40px;
|
||||
--h0-size-mobile: 32px;
|
||||
--h1-size-mobile: 26px;
|
||||
--h2-size-mobile: 22px;
|
||||
--h3-size-mobile: 18px;
|
||||
|
||||
/* Heading sizes - desktop */
|
||||
--h00-size: 48px;
|
||||
--h0-size: 40px;
|
||||
--h1-size: 32px;
|
||||
--h2-size: 24px;
|
||||
--h3-size: 20px;
|
||||
--h4-size: 16px;
|
||||
--h5-size: 14px;
|
||||
--h6-size: 12px;
|
||||
/* Heading sizes - desktop */
|
||||
--h00-size: 48px;
|
||||
--h0-size: 40px;
|
||||
--h1-size: 32px;
|
||||
--h2-size: 24px;
|
||||
--h3-size: 20px;
|
||||
--h4-size: 16px;
|
||||
--h5-size: 14px;
|
||||
--h6-size: 12px;
|
||||
|
||||
--font-size-lg: 19px;
|
||||
--font-size-sm: 13px;
|
||||
--font-size: 16px;
|
||||
--font-size-lg: 19px;
|
||||
--font-size-sm: 13px;
|
||||
--font-size: 16px;
|
||||
|
||||
/* Line heights */
|
||||
--lh-condensed-ultra: 1;
|
||||
--lh-condensed: 1.25;
|
||||
--lh-default: 1.5;
|
||||
/* Line heights */
|
||||
--lh-condensed-ultra: 1;
|
||||
--lh-condensed: 1.25;
|
||||
--lh-default: 1.5;
|
||||
|
||||
/* Font weights */
|
||||
--font-weight-light: 300;
|
||||
--font-weight-normal: 400;
|
||||
--font-weight-semibold: 500;
|
||||
--font-weight-bold: 600;
|
||||
/* Font weights */
|
||||
--font-weight-light: 300;
|
||||
--font-weight-normal: 400;
|
||||
--font-weight-semibold: 500;
|
||||
--font-weight-bold: 600;
|
||||
|
||||
/* Font stacks */
|
||||
--body-font: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
|
||||
--mono-font: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
|
||||
}
|
||||
/* Font stacks */
|
||||
--body-font: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif,
|
||||
'Apple Color Emoji', 'Segoe UI Emoji';
|
||||
--mono-font: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
|
||||
}
|
||||
|
||||
@@ -4,54 +4,56 @@
|
||||
* @see https://stackoverflow.com/a/67338038/938822
|
||||
*/
|
||||
export function ago(
|
||||
/** A Date object, timestamp or string parsable with Date.parse() */
|
||||
date: string | number | Date,
|
||||
/** A Date object, timestamp or string parsable with Date.parse() */
|
||||
nowDate: string | number | Date = Date.now(),
|
||||
/** A Intl formater */
|
||||
rft: Intl.RelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' })
|
||||
/** A Date object, timestamp or string parsable with Date.parse() */
|
||||
date: string | number | Date,
|
||||
/** A Date object, timestamp or string parsable with Date.parse() */
|
||||
nowDate: string | number | Date = Date.now(),
|
||||
/** A Intl formater */
|
||||
rft: Intl.RelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' })
|
||||
): string {
|
||||
const SECOND = 1000;
|
||||
const MINUTE = 60 * SECOND;
|
||||
const HOUR = 60 * MINUTE;
|
||||
const DAY = 24 * HOUR;
|
||||
const WEEK = 7 * DAY;
|
||||
const MONTH = 30 * DAY;
|
||||
const YEAR = 365 * DAY;
|
||||
const intervals = [
|
||||
{ ge: YEAR, divisor: YEAR, unit: 'year' },
|
||||
{ ge: MONTH, divisor: MONTH, unit: 'month' },
|
||||
{ ge: WEEK, divisor: WEEK, unit: 'week' },
|
||||
{ ge: DAY, divisor: DAY, unit: 'day' },
|
||||
{ ge: HOUR, divisor: HOUR, unit: 'hour' },
|
||||
{ ge: MINUTE, divisor: MINUTE, unit: 'minute' },
|
||||
{ ge: 30 * SECOND, divisor: SECOND, unit: 'seconds' },
|
||||
{ ge: 0, divisor: 1, text: 'just now' },
|
||||
];
|
||||
const now = typeof nowDate === 'object' ? nowDate.getTime() : new Date(nowDate).getTime();
|
||||
const diff = now - (typeof date === 'object' ? date : new Date(date)).getTime();
|
||||
const diffAbs = Math.abs(diff);
|
||||
for (const interval of intervals) {
|
||||
if (diffAbs >= interval.ge) {
|
||||
const x = Math.round(Math.abs(diff) / interval.divisor);
|
||||
const isFuture = diff < 0;
|
||||
return interval.unit ? rft.format(isFuture ? x : -x, interval.unit as Unit) : interval.text;
|
||||
}
|
||||
}
|
||||
const SECOND = 1000;
|
||||
const MINUTE = 60 * SECOND;
|
||||
const HOUR = 60 * MINUTE;
|
||||
const DAY = 24 * HOUR;
|
||||
const WEEK = 7 * DAY;
|
||||
const MONTH = 30 * DAY;
|
||||
const YEAR = 365 * DAY;
|
||||
const intervals = [
|
||||
{ ge: YEAR, divisor: YEAR, unit: 'year' },
|
||||
{ ge: MONTH, divisor: MONTH, unit: 'month' },
|
||||
{ ge: WEEK, divisor: WEEK, unit: 'week' },
|
||||
{ ge: DAY, divisor: DAY, unit: 'day' },
|
||||
{ ge: HOUR, divisor: HOUR, unit: 'hour' },
|
||||
{ ge: MINUTE, divisor: MINUTE, unit: 'minute' },
|
||||
{ ge: 30 * SECOND, divisor: SECOND, unit: 'seconds' },
|
||||
{ ge: 0, divisor: 1, text: 'just now' },
|
||||
];
|
||||
const now = typeof nowDate === 'object' ? nowDate.getTime() : new Date(nowDate).getTime();
|
||||
const diff = now - (typeof date === 'object' ? date : new Date(date)).getTime();
|
||||
const diffAbs = Math.abs(diff);
|
||||
for (const interval of intervals) {
|
||||
if (diffAbs >= interval.ge) {
|
||||
const x = Math.round(Math.abs(diff) / interval.divisor);
|
||||
const isFuture = diff < 0;
|
||||
return interval.unit
|
||||
? rft.format(isFuture ? x : -x, interval.unit as Unit)
|
||||
: interval.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Unit =
|
||||
| 'second'
|
||||
| 'seconds'
|
||||
| 'minute'
|
||||
| 'minutes'
|
||||
| 'hour'
|
||||
| 'hours'
|
||||
| 'day'
|
||||
| 'days'
|
||||
| 'week'
|
||||
| 'weeks'
|
||||
| 'month'
|
||||
| 'months'
|
||||
| 'year'
|
||||
| 'years';
|
||||
| 'second'
|
||||
| 'seconds'
|
||||
| 'minute'
|
||||
| 'minutes'
|
||||
| 'hour'
|
||||
| 'hours'
|
||||
| 'day'
|
||||
| 'days'
|
||||
| 'week'
|
||||
| 'weeks'
|
||||
| 'month'
|
||||
| 'months'
|
||||
| 'year'
|
||||
| 'years';
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function classCombine(names) {
|
||||
return names.filter(name => name && !name.includes('undefined')).join(' ')
|
||||
}
|
||||
return names.filter((name) => name && !name.includes('undefined')).join(' ');
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export { ago } from './ago';
|
||||
export { simplify } from './number';
|
||||
export { Permissions } from './permissions';
|
||||
export { formatVersions } from './versions';
|
||||
export { formatVersions } from './versions';
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Convert large numbers to human readable strings
|
||||
* @source https://github.com/rohmanhm/simplify-number
|
||||
*/
|
||||
export function simplify(num = 0): string {
|
||||
let numberVar = num;
|
||||
|
||||
// 2 decimal places => 100, 3 => 1000, etc
|
||||
const decPlaces = Math.pow(10, 1);
|
||||
|
||||
// Enumerate number abbreviations
|
||||
const abbrev = ['K', 'M', 'B', 'T'];
|
||||
|
||||
// Go through the array backwards, so we do the largest first
|
||||
for (let i = abbrev.length - 1; i >= 0; i--) {
|
||||
// Convert array index to "1000", "1000000", etc
|
||||
const size = Math.pow(10, (i + 1) * 3);
|
||||
|
||||
// If the number is bigger or equal do the abbreviation
|
||||
if (size <= numberVar) {
|
||||
// Here, we multiply by decPlaces, round, and then divide by decPlaces.
|
||||
// This gives us nice rounding to a particular decimal place.
|
||||
numberVar = Math.round((numberVar * decPlaces) / size) / decPlaces;
|
||||
|
||||
// Handle special case where we round up to the next abbreviation
|
||||
if (numberVar === 1000 && i < abbrev.length - 1) {
|
||||
numberVar = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
// Add the letter for the abbreviation
|
||||
(numberVar as any) += abbrev[i];
|
||||
|
||||
// We are done... stop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return String(numberVar);
|
||||
}
|
||||
@@ -5,130 +5,130 @@ import insane from 'insane';
|
||||
const renderer = new marked.Renderer();
|
||||
|
||||
renderer.image = (href, text) => {
|
||||
if (/^https?:\/\/(www\.)?youtube\.com\/watch\?v=[a-zA-Z0-9_]{11}$/.test(href)) {
|
||||
const id = href.substring(32, 43);
|
||||
return `<iframe src="https://www.youtube-nocookie.com/embed/${id}?&modestbranding=1&autoplay=0&rel=0" frameborder="0" allowfullscreen></iframe>`;
|
||||
} else {
|
||||
return `<img src="${href}" alt="${text}" />`;
|
||||
}
|
||||
if (/^https?:\/\/(www\.)?youtube\.com\/watch\?v=[a-zA-Z0-9_]{11}$/.test(href)) {
|
||||
const id = href.substring(32, 43);
|
||||
return `<iframe src="https://www.youtube-nocookie.com/embed/${id}?&modestbranding=1&autoplay=0&rel=0" frameborder="0" allowfullscreen></iframe>`;
|
||||
} else {
|
||||
return `<img src="${href}" alt="${text}" />`;
|
||||
}
|
||||
};
|
||||
|
||||
renderer.link = (href, title, text) => {
|
||||
if (href === null) {
|
||||
return text;
|
||||
}
|
||||
let out = '<a href="' + href + '" rel="external nofollow"';
|
||||
if (title) {
|
||||
out += ' title="' + title + '"';
|
||||
}
|
||||
out += '>' + text + '</a>';
|
||||
return out;
|
||||
if (href === null) {
|
||||
return text;
|
||||
}
|
||||
let out = '<a href="' + href + '" rel="external nofollow"';
|
||||
if (title) {
|
||||
out += ' title="' + title + '"';
|
||||
}
|
||||
out += '>' + text + '</a>';
|
||||
return out;
|
||||
};
|
||||
|
||||
marked.setOptions({
|
||||
renderer,
|
||||
highlight: function (code, lang) {
|
||||
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
|
||||
return hljs.highlight(code, { language }).value;
|
||||
},
|
||||
langPrefix: 'hljs language-',
|
||||
headerPrefix: '',
|
||||
gfm: true,
|
||||
smartLists: true,
|
||||
renderer,
|
||||
highlight: function (code, lang) {
|
||||
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
|
||||
return hljs.highlight(code, { language }).value;
|
||||
},
|
||||
langPrefix: 'hljs language-',
|
||||
headerPrefix: '',
|
||||
gfm: true,
|
||||
smartLists: true,
|
||||
});
|
||||
|
||||
function sanitize(html: string): string {
|
||||
return insane(html, {
|
||||
allowedAttributes: {
|
||||
a: ['href', 'name', 'target', 'title', 'rel'],
|
||||
iframe: ['allowfullscreen', 'src', 'width', 'height'],
|
||||
img: ['src', 'width', 'height', 'alt'],
|
||||
h1: ['id'],
|
||||
h2: ['id'],
|
||||
h3: ['id'],
|
||||
h4: ['id'],
|
||||
h5: ['id'],
|
||||
h6: ['id'],
|
||||
code: ['class'],
|
||||
span: ['class'],
|
||||
input: ['type', 'checked', 'disabled'],
|
||||
font: ['color'],
|
||||
},
|
||||
allowedClasses: {},
|
||||
allowedSchemes: ['http', 'https', 'mailto'],
|
||||
allowedTags: [
|
||||
'a',
|
||||
'b',
|
||||
'blockquote',
|
||||
'br',
|
||||
'caption',
|
||||
'center',
|
||||
'code',
|
||||
'del',
|
||||
'details',
|
||||
'div',
|
||||
'em',
|
||||
'font',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'hr',
|
||||
'i',
|
||||
'iframe',
|
||||
'img',
|
||||
'input',
|
||||
'ins',
|
||||
'kbd',
|
||||
'li',
|
||||
'main',
|
||||
'ol',
|
||||
'p',
|
||||
'pre',
|
||||
'span',
|
||||
'strike',
|
||||
'strong',
|
||||
'sub',
|
||||
'summary',
|
||||
'sup',
|
||||
'table',
|
||||
'tbody',
|
||||
'td',
|
||||
'th',
|
||||
'thead',
|
||||
'tr',
|
||||
'u',
|
||||
'ul',
|
||||
],
|
||||
filter: ({ tag, attrs }): boolean => {
|
||||
if (tag === 'iframe') {
|
||||
return /^https?:\/\/(www\.)?(youtube|youtube-nocookie)\.com\/embed\/[a-zA-Z0-9_]{11}(\?)?(&modestbranding=1)?(&autoplay=0)?(&loop=1)?(&playlist=[a-zA-Z0-9_]{11})?(&rel=0)?$/.test(
|
||||
attrs.src || ''
|
||||
);
|
||||
} else if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) {
|
||||
return attrs.id !== 'svelte';
|
||||
} else if (tag === 'input') {
|
||||
return attrs.type === 'checkbox' && attrs.disabled === '';
|
||||
} else if (tag === 'code' || tag === 'span') {
|
||||
return !attrs.class || attrs.class.replace(' ', '').startsWith('hljs');
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
transformText: null,
|
||||
});
|
||||
return insane(html, {
|
||||
allowedAttributes: {
|
||||
a: ['href', 'name', 'target', 'title', 'rel'],
|
||||
iframe: ['allowfullscreen', 'src', 'width', 'height'],
|
||||
img: ['src', 'width', 'height', 'alt'],
|
||||
h1: ['id'],
|
||||
h2: ['id'],
|
||||
h3: ['id'],
|
||||
h4: ['id'],
|
||||
h5: ['id'],
|
||||
h6: ['id'],
|
||||
code: ['class'],
|
||||
span: ['class'],
|
||||
input: ['type', 'checked', 'disabled'],
|
||||
font: ['color'],
|
||||
},
|
||||
allowedClasses: {},
|
||||
allowedSchemes: ['http', 'https', 'mailto'],
|
||||
allowedTags: [
|
||||
'a',
|
||||
'b',
|
||||
'blockquote',
|
||||
'br',
|
||||
'caption',
|
||||
'center',
|
||||
'code',
|
||||
'del',
|
||||
'details',
|
||||
'div',
|
||||
'em',
|
||||
'font',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'hr',
|
||||
'i',
|
||||
'iframe',
|
||||
'img',
|
||||
'input',
|
||||
'ins',
|
||||
'kbd',
|
||||
'li',
|
||||
'main',
|
||||
'ol',
|
||||
'p',
|
||||
'pre',
|
||||
'span',
|
||||
'strike',
|
||||
'strong',
|
||||
'sub',
|
||||
'summary',
|
||||
'sup',
|
||||
'table',
|
||||
'tbody',
|
||||
'td',
|
||||
'th',
|
||||
'thead',
|
||||
'tr',
|
||||
'u',
|
||||
'ul',
|
||||
],
|
||||
filter: ({ tag, attrs }): boolean => {
|
||||
if (tag === 'iframe') {
|
||||
return /^https?:\/\/(www\.)?(youtube|youtube-nocookie)\.com\/embed\/[a-zA-Z0-9_]{11}(\?)?(&modestbranding=1)?(&autoplay=0)?(&loop=1)?(&playlist=[a-zA-Z0-9_]{11})?(&rel=0)?$/.test(
|
||||
attrs.src || ''
|
||||
);
|
||||
} else if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) {
|
||||
return attrs.id !== 'svelte';
|
||||
} else if (tag === 'input') {
|
||||
return attrs.type === 'checkbox' && attrs.disabled === '';
|
||||
} else if (tag === 'code' || tag === 'span') {
|
||||
return !attrs.class || attrs.class.replace(' ', '').startsWith('hljs');
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
transformText: null,
|
||||
});
|
||||
}
|
||||
|
||||
export function markdown(markdown: string): string {
|
||||
return marked.parse(markdown);
|
||||
return marked.parse(markdown);
|
||||
}
|
||||
|
||||
export function markdownInline(markdown: string): string {
|
||||
return marked.parseInline(markdown);
|
||||
return marked.parseInline(markdown);
|
||||
}
|
||||
|
||||
export function markdownXSS(markdown: string): string {
|
||||
return sanitize(marked.parse(markdown));
|
||||
return sanitize(marked.parse(markdown));
|
||||
}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
export class Permissions {
|
||||
data = {
|
||||
uploadVersions: false,
|
||||
deleteVersion: false,
|
||||
editDetails: false,
|
||||
editBody: false,
|
||||
manageInvites: false,
|
||||
removeMember: false,
|
||||
editMember: false,
|
||||
deleteProject: false,
|
||||
};
|
||||
data = {
|
||||
uploadVersions: false,
|
||||
deleteVersion: false,
|
||||
editDetails: false,
|
||||
editBody: false,
|
||||
manageInvites: false,
|
||||
removeMember: false,
|
||||
editMember: false,
|
||||
deleteProject: false,
|
||||
};
|
||||
|
||||
get settingsPage(): boolean {
|
||||
return (
|
||||
this.data.manageInvites ||
|
||||
this.data.removeMember ||
|
||||
this.data.editMember ||
|
||||
this.data.deleteProject
|
||||
);
|
||||
}
|
||||
get settingsPage(): boolean {
|
||||
return (
|
||||
this.data.manageInvites ||
|
||||
this.data.removeMember ||
|
||||
this.data.editMember ||
|
||||
this.data.deleteProject
|
||||
);
|
||||
}
|
||||
|
||||
constructor(from: number | 'ALL' | null) {
|
||||
if (from === 'ALL' || from === 0b11111111 || from === null) {
|
||||
Object.keys(this.data).forEach((v) => (this.data[v] = true));
|
||||
} else if (typeof from === 'number') {
|
||||
this.data = {
|
||||
uploadVersions: !!(from & (1 << 0)),
|
||||
deleteVersion: !!(from & (1 << 1)),
|
||||
editDetails: !!(from & (1 << 2)),
|
||||
editBody: !!(from & (1 << 3)),
|
||||
manageInvites: !!(from & (1 << 4)),
|
||||
removeMember: !!(from & (1 << 5)),
|
||||
editMember: !!(from & (1 << 6)),
|
||||
deleteProject: !!(from & (1 << 7)),
|
||||
};
|
||||
}
|
||||
}
|
||||
constructor(from: number | 'ALL' | null) {
|
||||
if (from === 'ALL' || from === 0b11111111 || from === null) {
|
||||
Object.keys(this.data).forEach((v) => (this.data[v] = true));
|
||||
} else if (typeof from === 'number') {
|
||||
this.data = {
|
||||
uploadVersions: !!(from & (1 << 0)),
|
||||
deleteVersion: !!(from & (1 << 1)),
|
||||
editDetails: !!(from & (1 << 2)),
|
||||
editBody: !!(from & (1 << 3)),
|
||||
manageInvites: !!(from & (1 << 4)),
|
||||
removeMember: !!(from & (1 << 5)),
|
||||
editMember: !!(from & (1 << 6)),
|
||||
deleteProject: !!(from & (1 << 7)),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ let idCounter = 0;
|
||||
export function uniqueId(prefix = ''): string {
|
||||
const id = ++idCounter;
|
||||
return prefix + id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +1,87 @@
|
||||
import gameVersions from '$generated/gameVersions.json';
|
||||
|
||||
export function formatVersions(versionArray: string[]): string {
|
||||
const allVersions = gameVersions.slice().reverse();
|
||||
const allReleases = allVersions.filter((x) => x.version_type === 'release');
|
||||
const allVersions = gameVersions.slice().reverse();
|
||||
const allReleases = allVersions.filter((x) => x.version_type === 'release');
|
||||
|
||||
const intervals = [];
|
||||
let currentInterval = 0;
|
||||
const intervals = [];
|
||||
let currentInterval = 0;
|
||||
|
||||
for (let i = 0; i < versionArray.length; i++) {
|
||||
const index = allVersions.findIndex((x) => x.version === versionArray[i]);
|
||||
const releaseIndex = allReleases.findIndex((x) => x.version === versionArray[i]);
|
||||
for (let i = 0; i < versionArray.length; i++) {
|
||||
const index = allVersions.findIndex((x) => x.version === versionArray[i]);
|
||||
const releaseIndex = allReleases.findIndex((x) => x.version === versionArray[i]);
|
||||
|
||||
if (i === 0) {
|
||||
intervals.push([[versionArray[i], index, releaseIndex]]);
|
||||
} else {
|
||||
const intervalBase = intervals[currentInterval];
|
||||
if (i === 0) {
|
||||
intervals.push([[versionArray[i], index, releaseIndex]]);
|
||||
} else {
|
||||
const intervalBase = intervals[currentInterval];
|
||||
|
||||
if (
|
||||
(index - intervalBase[intervalBase.length - 1][1] === 1 ||
|
||||
releaseIndex - intervalBase[intervalBase.length - 1][2] === 1) &&
|
||||
(allVersions[intervalBase[0][1]].version_type === 'release' ||
|
||||
allVersions[index].version_type !== 'release')
|
||||
) {
|
||||
intervalBase[1] = [versionArray[i], index, releaseIndex];
|
||||
} else {
|
||||
currentInterval += 1;
|
||||
intervals[currentInterval] = [[versionArray[i], index, releaseIndex]];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
(index - intervalBase[intervalBase.length - 1][1] === 1 ||
|
||||
releaseIndex - intervalBase[intervalBase.length - 1][2] === 1) &&
|
||||
(allVersions[intervalBase[0][1]].version_type === 'release' ||
|
||||
allVersions[index].version_type !== 'release')
|
||||
) {
|
||||
intervalBase[1] = [versionArray[i], index, releaseIndex];
|
||||
} else {
|
||||
currentInterval += 1;
|
||||
intervals[currentInterval] = [[versionArray[i], index, releaseIndex]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const newIntervals = [];
|
||||
for (let i = 0; i < intervals.length; i++) {
|
||||
const interval = intervals[i];
|
||||
const newIntervals = [];
|
||||
for (let i = 0; i < intervals.length; i++) {
|
||||
const interval = intervals[i];
|
||||
|
||||
if (interval.length === 2 && interval[0][2] !== -1 && interval[1][2] === -1) {
|
||||
let lastSnapshot = null;
|
||||
for (let j = interval[1][1]; j > interval[0][1]; j--) {
|
||||
if (allVersions[j].version_type === 'release') {
|
||||
newIntervals.push([
|
||||
interval[0],
|
||||
[
|
||||
allVersions[j].version,
|
||||
j,
|
||||
allReleases.findIndex((x) => x.version === allVersions[j].version),
|
||||
],
|
||||
]);
|
||||
if (interval.length === 2 && interval[0][2] !== -1 && interval[1][2] === -1) {
|
||||
let lastSnapshot = null;
|
||||
for (let j = interval[1][1]; j > interval[0][1]; j--) {
|
||||
if (allVersions[j].version_type === 'release') {
|
||||
newIntervals.push([
|
||||
interval[0],
|
||||
[
|
||||
allVersions[j].version,
|
||||
j,
|
||||
allReleases.findIndex((x) => x.version === allVersions[j].version),
|
||||
],
|
||||
]);
|
||||
|
||||
if (lastSnapshot !== null && lastSnapshot !== j + 1) {
|
||||
newIntervals.push([[allVersions[lastSnapshot].version, lastSnapshot, -1], interval[1]]);
|
||||
} else {
|
||||
newIntervals.push([interval[1]]);
|
||||
}
|
||||
if (lastSnapshot !== null && lastSnapshot !== j + 1) {
|
||||
newIntervals.push([
|
||||
[allVersions[lastSnapshot].version, lastSnapshot, -1],
|
||||
interval[1],
|
||||
]);
|
||||
} else {
|
||||
newIntervals.push([interval[1]]);
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
lastSnapshot = j;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newIntervals.push(interval);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
lastSnapshot = j;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newIntervals.push(interval);
|
||||
}
|
||||
}
|
||||
|
||||
const output = [];
|
||||
const output = [];
|
||||
|
||||
for (const interval of newIntervals) {
|
||||
if (interval.length === 2) {
|
||||
output.push(`${interval[0][0]}—${interval[1][0]}`);
|
||||
} else {
|
||||
output.push(interval[0][0]);
|
||||
}
|
||||
}
|
||||
for (const interval of newIntervals) {
|
||||
if (interval.length === 2) {
|
||||
output.push(`${interval[0][0]}—${interval[1][0]}`);
|
||||
} else {
|
||||
output.push(interval[0][0]);
|
||||
}
|
||||
}
|
||||
|
||||
return output.join(', ');
|
||||
return output.join(', ');
|
||||
}
|
||||
|
||||
export const getPrimary = (files: Version['files']) =>
|
||||
files.find((file) => file.primary) || files[0];
|
||||
files.find((file) => file.primary) || files[0];
|
||||
|
||||
export function downloadUrl(file): string {
|
||||
return import.meta.env.VITE_API_URL + `version_file/${file?.hashes.sha1}/download`;
|
||||
return import.meta.env.VITE_API_URL + `version_file/${file?.hashes.sha1}/download`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user