beginDrag(event, element)}
onclick={() => triggerInteraction(element, 'click')}
onpointerenter={() => {
triggerInteraction(element, 'hover');
showGroupHover(element);
}}
onpointerleave={() => {
triggerInteraction(element, 'leave');
if (interactive) scheduleHoverHide();
}}
oncontextmenu={(event) => {
if (!interactive) return;
// Let the event bubble so the editor's ContextMenu.Trigger can open.
oncontext?.(element.id, event);
}}
ondblclick={(event) => {
if (!interactive || !element.groupId) return;
event.preventDefault();
event.stopPropagation();
onselectgroup?.(element.groupId);
}}
onkeydown={(event) => {
if (interactive && (event.key === 'Enter' || event.key === ' ')) {
event.preventDefault();
selectElement(element.id, modifierPressed(event));
} else if (
!interactive &&
element.interactive &&
(event.key === 'Enter' || event.key === ' ')
) {
event.preventDefault();
triggerInteraction(element, 'click');
}
}}
>
{#if element.type === 'text' || element.type === 'data'}
{@const content =
element.type === 'data'
? dataValue(element)
: interpolateThemeText(element.text, variables)}
{#if isMorphEnabled(element)}
{:else}
{content}
{/if}
{:else if element.type === 'image'}
{#if element.tint}
{:else}
{/if}
{:else if element.type === 'video'}
{:else if element.type === 'svelte'}
{:else if element.type === 'shape'}
{#if element.shape === 'arc'}
{@const arc = arcGeometry(element)}
{@const gradientVector = themeSvgGradientVector(element.gradientAngle ?? 135)}
{#if element.fillMode === 'gradient'}
{/if}
{:else}
{/if}
{:else if element.type === 'icon'}
{:else if element.type === 'repeater'}
{#each Array(repeaterTiles(element).total) as _, index (index)}
{#if element.source === 'image' && element.src}
{:else}
{/if}
{/each}
{:else if element.type === 'gauge'}
{#if element.mode === 'ring'}
{#if gaugeLabel(element)}
{@const label = gaugeLabel(element)}
{#if isMorphEnabled(element)}
{:else}
{label}
{/if}
{/if}
{:else}
{#if gaugeLabel(element)}
{@const label = gaugeLabel(element)}
{#if isMorphEnabled(element)}
{:else}
{label}
{/if}
{/if}
{/if}
{:else if element.type === 'ticker'}
{#each [0, 1] as copy (copy)}
{#if isMorphEnabled(element)}
{:else}
{interpolateThemeText(element.text, variables)}
{/if}
{/each}
{:else if element.type === 'lottie'}
{#key element.src}
{/key}
{:else if element.type === 'button'}
{@const isActionLaunch = element.action?.type === 'launch'}
{
if (interactive) {
if (event.shiftKey || event.ctrlKey || event.metaKey) {
event.stopPropagation();
onbuttonaction?.(element.action);
}
return;
}
if (isActionLaunch && (launchDisabled || isLaunching)) return;
event.stopPropagation();
triggerInteraction(element, 'click');
onbuttonaction?.(element.action);
}}
>
{#if isActionLaunch && isLaunching}
{#if launchProgress >= 0}
{Math.round(launchProgress)}%
{:else}
{/if}
{:else if element.icon}
{/if}
{#if isActionLaunch && isLaunching}
{launchProgress >= 0
? `${launchText} (${Math.round(launchProgress)}%)`
: launchText}
{#if launchSubtext}
{launchSubtext}
{/if}
{:else if isMorphEnabled(element)}
{:else}
{interpolateThemeText(element.label, variables)}
{/if}
{:else if element.type === 'path'}
{@const gradientVector = themeSvgGradientVector(element.gradientAngle ?? 135)}
{#if element.fillMode === 'gradient'}
{/if}
{:else if element.type === 'particles'}
{#each themeParticleSeeds(element) as seed, index (index)}
{/each}
{:else if element.type === 'clock'}
{@const now = clockNow}
{#if element.mode === 'analog'}
{@const hands = analogHands(now)}
{#each Array(12) as _, index (index)}
{/each}
{#if element.showSeconds !== false}
{/if}
{:else}
{#if element.label}
{element.label}
{/if}
{#if isMorphEnabled(element)}
{:else}
{themeClockTime(element, now)}
{/if}
{#if element.showDate}
{#if isMorphEnabled(element)}
{:else}
{themeClockDate(now)}
{/if}
{/if}
{/if}
{:else if element.type === 'countdown'}
{#if isMorphEnabled(element)}
{:else}
{themeCountdownText(element, clockNow)}
{/if}
{:else if element.type === 'widget'}
{#if element.widget === 'launch-button'}
{#if element.variant === 'icon-only' || element.variant === 'minimal'}
{@const btnRadius = Math.max(
12,
Math.round(Math.min(element.width, element.height) / 2) - 6
)}
{@const btnCircumference = 2 * Math.PI * btnRadius}
{@const strokeOffset =
launchProgress < 0
? btnCircumference * 0.7
: btnCircumference -
(Math.max(0, Math.min(100, launchProgress)) / 100) * btnCircumference}
{
e.stopPropagation();
if (!launchDisabled && !isLaunching) {
onbuttonaction?.({ type: 'launch' });
}
}}
title={isLaunching
? launchSubtext
? `${launchText} - ${launchSubtext}`
: launchText
: 'Launch osu!'}
>
{#if isLaunching}
{#if launchProgress >= 0}
{Math.round(launchProgress)}%
{:else}
{/if}
{:else}
{/if}
{:else if element.variant === 'compact'}
{
e.stopPropagation();
if (!launchDisabled && !isLaunching) {
onbuttonaction?.({ type: 'launch' });
}
}}
title={isLaunching
? launchSubtext
? `${launchText} - ${launchSubtext}`
: launchText
: 'Launch osu!'}
>
{#if isLaunching}
{#if launchProgress >= 0}
{Math.round(launchProgress)}%
{:else}
{/if}
{launchText}
{#if launchSubtext}
{launchSubtext}
{/if}
{:else}
Launch
{/if}
{:else}
{
if (interactive) return;
if (!launchDisabled && !isLaunching) {
onbuttonaction?.({ type: 'launch' });
}
}}
/>
{/if}
{:else if element.widget === 'player-card'}
{@const playerStats =
$currentUserInfo?.stats?.['0'] ?? $themeGlobalData?.user?.stats?.osu}
{@const accuracyVal =
playerStats && 'acc' in playerStats
? playerStats.acc
: playerStats && 'accuracy' in playerStats
? playerStats.accuracy
: 98.3}
{@const playerId = $currentUser?.id ?? $currentUserInfo?.info?.id ?? 0}
{@const playerName = $currentUser?.name ?? 'Player'}
{@const country = $currentUserInfo?.info?.country}
{@const levelVal = playerStats && 'level' in playerStats ? playerStats.level : 1}
{@const levelProgress =
playerStats && 'level_progress' in playerStats ? playerStats.level_progress : 75}
{@const rankVal = playerStats?.rank ? playerStats.rank : 102}
{@const countryRankVal =
playerStats && 'country_rank' in playerStats ? playerStats.country_rank : undefined}
{@const ppVal = playerStats?.pp ? playerStats.pp : 4521}
{@const playsVal = playerStats?.plays
? Number(playerStats.plays).toLocaleString()
: '11,813'}
{#if element.variant === 'minimal'}
{#if country}
{countryCodeToEmoji(country)}
{/if}
{playerName}
#{rankVal} · {ppVal}pp
Lv.{levelVal}
{:else if element.variant === 'compact'}
{#if country}
{countryCodeToEmoji(country)}
{/if}
{playerName}
Lv.{levelVal}
#{rankVal} · {ppVal}pp
Accuracy
{accuracyVal.toFixed(1)}%
Plays
{playsVal}
{:else if element.variant === 'banner' || element.showStats === false || element.height < 140}
{#if country}
{countryCodeToEmoji(country)}
{/if}
{playerName}
Lv.{levelVal}
{levelProgress}%
{:else}
{#if country}
{countryCodeToEmoji(country)}
{/if}
{playerName}
Lv.{levelVal}
{levelProgress}%
Rank
{#if countryRankVal}
#{countryRankVal}
{/if}
#{rankVal}
Performance
{ppVal}pp
Accuracy
{accuracyVal.toFixed(1)}%
Plays
{playsVal}
{/if}
{:else if element.widget === 'recent-activity'}
{@const event = $currentUserInfo?.events?.[0]}
{#if element.variant === 'minimal'}
{#if event?.setId}
{:else}
{/if}
{event?.title ?? 'Space Pirates'}
{event?.artist ?? 'Waterflame'} · {event
? formatRelativeTime(event.time)
: '5d ago'}
{event?.grade ?? 'S'}
{:else if element.variant === 'compact'}
{#if event?.setId}
{/if}
Recent Activity
{event?.grade ?? 'S'}
{event?.title ?? 'Space Pirates'}
[{event?.version ?? 'Galactic Thieves'}]
Rank #{event?.rank ?? 1}
{:else}
{#if event?.setId}
{/if}
Recent Activity
{event?.grade ?? 'S'}
{event?.title ?? 'Space Pirates'}
{event?.artist ?? 'Waterflame'}
[{event?.version ?? 'Galactic Thieves'}]
Rank #{event?.rank ?? 1}
{event ? formatRelativeTime(event.time) : '5d ago'}
ez-pp.farm
{/if}
{:else if element.widget === 'telemetry'}
{$themeGlobalData?.server?.ping ?? 19}ms
{$themeGlobalData?.osu?.stream ?? 'stable'}
{:else if element.widget === 'header'}
{#if element.variant === 'minimal'}
EZPPLauncher
{:else if element.variant === 'compact'}
EZPPLauncher
{timeGreeting},
{$currentUser?.name ?? 'Guest'} !
{:else}
EZPPLauncher
{timeGreeting},
{$currentUser?.name ?? 'Guest'} !
{/if}
{:else if element.widget === 'avatar'}
{@const shapeClass =
element.variant === 'rounded'
? 'rounded-2xl'
: element.variant === 'square'
? 'rounded-md'
: 'rounded-full'}
{@const playerId = $currentUser?.id ?? $currentUserInfo?.info?.id ?? 0}
{@const playerName = $currentUser?.name ?? 'Player'}
{@const country = $currentUserInfo?.info?.country}
{@const level = $currentUserInfo?.stats?.['0']?.level}
{
if (!interactive && playerId) {
e.stopPropagation();
void openURL(`https://ez-pp.farm/u/${playerId}`);
}
}}
onkeydown={(e) => {
if (!interactive && playerId && (e.key === 'Enter' || e.key === ' ')) {
e.preventDefault();
e.stopPropagation();
void openURL(`https://ez-pp.farm/u/${playerId}`);
}
}}
title={playerName}
>
{#if element.showOnlineRing !== false}
{/if}
{#if element.showCountry !== false && country}
{countryCodeToEmoji(country)}
{/if}
{#if element.showLevel && level !== undefined}
Lv.{level}
{/if}
{/if}
{/if}