feat: add discord rich presence editor window and interactive embed preview
This commit is contained in:
1 parent
e3abea8d83
commit
386c829455
30 files changed
+4102
-263
No files matched your search
+129
-28
@@ -82,12 +82,12 @@ export const themeGlobalData = derived(
|
||||
}
|
||||
);
|
||||
|
||||
const formatInteger = (value: number) => Math.round(value).toLocaleString('en-US');
|
||||
export const formatInteger = (value: number) => Math.round(value).toLocaleString('en-US');
|
||||
|
||||
const formatAccuracy = (value: number) =>
|
||||
export const formatAccuracy = (value: number) =>
|
||||
`${value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%`;
|
||||
|
||||
const formatPlaytime = (seconds: number) => {
|
||||
export const formatPlaytime = (seconds: number) => {
|
||||
const totalMinutes = Math.max(0, Math.round(seconds / 60));
|
||||
const hours = Math.floor(totalMinutes / 60);
|
||||
const minutes = totalMinutes % 60;
|
||||
@@ -95,54 +95,155 @@ const formatPlaytime = (seconds: number) => {
|
||||
return `${minutes}m`;
|
||||
};
|
||||
|
||||
const formatDate = (date: Date) =>
|
||||
export const formatDate = (date: Date) =>
|
||||
new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(date);
|
||||
|
||||
/** Current value for a data layer field. Missing values render as an empty string. */
|
||||
export const resolveThemeDataValue = (field: ThemeV2DataField, context: ThemeDataContext) => {
|
||||
const { global, theme, screen, mode = 'osu', now = new Date() } = context;
|
||||
const stats = global.user.stats[mode];
|
||||
|
||||
/**
|
||||
* Realistic sample values displayed in the theme editor and preview thumbnails
|
||||
* when live launcher data is empty or unavailable (e.g. logged out or offline).
|
||||
*/
|
||||
export const getThemeDataSampleValue = (
|
||||
field: ThemeV2DataField,
|
||||
mode: ThemeV2DataMode = 'osu'
|
||||
): string => {
|
||||
switch (field) {
|
||||
case 'user.name':
|
||||
return global.user.name;
|
||||
return 'Player';
|
||||
case 'user.country':
|
||||
return global.user.country.toUpperCase();
|
||||
return 'US';
|
||||
case 'user.pp':
|
||||
return stats ? formatInteger(stats.pp) : '';
|
||||
return mode === 'catch'
|
||||
? '6,280'
|
||||
: mode === 'taiko'
|
||||
? '5,140'
|
||||
: mode === 'mania'
|
||||
? '8,920'
|
||||
: '7,420';
|
||||
case 'user.rank':
|
||||
return stats && stats.rank > 0 ? formatInteger(stats.rank) : '';
|
||||
return mode === 'catch'
|
||||
? '840'
|
||||
: mode === 'taiko'
|
||||
? '2,150'
|
||||
: mode === 'mania'
|
||||
? '412'
|
||||
: '1,337';
|
||||
case 'user.plays':
|
||||
return stats ? formatInteger(stats.plays) : '';
|
||||
return mode === 'catch'
|
||||
? '18,500'
|
||||
: mode === 'taiko'
|
||||
? '12,300'
|
||||
: mode === 'mania'
|
||||
? '35,800'
|
||||
: '42,100';
|
||||
case 'user.accuracy':
|
||||
return stats ? formatAccuracy(stats.accuracy) : '';
|
||||
return '98.75%';
|
||||
case 'user.playtime':
|
||||
return stats ? formatPlaytime(stats.playtime) : '';
|
||||
return '124h 30m';
|
||||
case 'launcher.version':
|
||||
return global.launcher.version;
|
||||
return '';
|
||||
case 'server.friends':
|
||||
return global.launcher.friends === undefined ? '' : formatInteger(global.launcher.friends);
|
||||
return '12';
|
||||
case 'osu.build':
|
||||
return global.osu.build ?? '';
|
||||
return 'b20241030';
|
||||
case 'osu.stream':
|
||||
return global.osu.stream ?? '';
|
||||
return 'Stable40';
|
||||
case 'server.ping':
|
||||
return global.server.ping === undefined ? '' : `${Math.round(global.server.ping)} ms`;
|
||||
return '24 ms';
|
||||
case 'theme.name':
|
||||
return theme.name;
|
||||
return 'Sample Theme';
|
||||
case 'theme.author':
|
||||
return theme.author;
|
||||
return 'Theme Creator';
|
||||
case 'theme.version':
|
||||
return theme.version;
|
||||
return '1.0.0';
|
||||
case 'screen':
|
||||
return screen ? screen.charAt(0).toUpperCase() + screen.slice(1) : '';
|
||||
return 'Home';
|
||||
case 'clock.time':
|
||||
return String(themeClockValues(now).time ?? '');
|
||||
return '14:30:00';
|
||||
case 'clock.time12':
|
||||
return String(themeClockValues(now).time12 ?? '');
|
||||
return '2:30:00 PM';
|
||||
case 'clock.date':
|
||||
return formatDate(now);
|
||||
return formatDate(new Date());
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
/** Current value for a data layer field. Missing values render as an empty string. */
|
||||
export const resolveThemeDataValue = (
|
||||
field: ThemeV2DataField,
|
||||
context: ThemeDataContext,
|
||||
options?: { preview?: boolean }
|
||||
) => {
|
||||
const { global, theme, screen, mode = 'osu', now = new Date() } = context;
|
||||
const stats = global.user.stats[mode];
|
||||
|
||||
let value = '';
|
||||
switch (field) {
|
||||
case 'user.name':
|
||||
value = global.user.name;
|
||||
break;
|
||||
case 'user.country':
|
||||
value = global.user.country ? global.user.country.toUpperCase() : '';
|
||||
break;
|
||||
case 'user.pp':
|
||||
value = stats ? formatInteger(stats.pp) : '';
|
||||
break;
|
||||
case 'user.rank':
|
||||
value = stats && stats.rank > 0 ? formatInteger(stats.rank) : '';
|
||||
break;
|
||||
case 'user.plays':
|
||||
value = stats ? formatInteger(stats.plays) : '';
|
||||
break;
|
||||
case 'user.accuracy':
|
||||
value = stats ? formatAccuracy(stats.accuracy) : '';
|
||||
break;
|
||||
case 'user.playtime':
|
||||
value = stats ? formatPlaytime(stats.playtime) : '';
|
||||
break;
|
||||
case 'launcher.version':
|
||||
value = global.launcher.version;
|
||||
break;
|
||||
case 'server.friends':
|
||||
value = global.launcher.friends === undefined ? '' : formatInteger(global.launcher.friends);
|
||||
break;
|
||||
case 'osu.build':
|
||||
value = global.osu.build ?? '';
|
||||
break;
|
||||
case 'osu.stream':
|
||||
value = global.osu.stream ?? '';
|
||||
break;
|
||||
case 'server.ping':
|
||||
value = global.server.ping === undefined ? '' : `${Math.round(global.server.ping)} ms`;
|
||||
break;
|
||||
case 'theme.name':
|
||||
value = theme.name;
|
||||
break;
|
||||
case 'theme.author':
|
||||
value = theme.author;
|
||||
break;
|
||||
case 'theme.version':
|
||||
value = theme.version;
|
||||
break;
|
||||
case 'screen':
|
||||
value = screen ? screen.charAt(0).toUpperCase() + screen.slice(1) : '';
|
||||
break;
|
||||
case 'clock.time':
|
||||
value = String(themeClockValues(now).time ?? '');
|
||||
break;
|
||||
case 'clock.time12':
|
||||
value = String(themeClockValues(now).time12 ?? '');
|
||||
break;
|
||||
case 'clock.date':
|
||||
value = formatDate(now);
|
||||
break;
|
||||
default:
|
||||
value = '';
|
||||
break;
|
||||
}
|
||||
|
||||
if (options?.preview && (!value || value.trim() === '')) {
|
||||
return getThemeDataSampleValue(field, mode);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
Reference in new issue
Block a user