perf: reduce startup work and fix grade analytics bar chart animation

Batch settings storage writes, tier plugin startup, lazy-load heavy UI
chunks, and optimize global search indexing. Stop tweening bar height in
grade analytics to prevent invalid negative SVG rect values.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-17 10:50:26 +09:30
parent 62ed702e64
commit d10fca6c0f
41 changed files with 919 additions and 537 deletions
+39 -21
View File
@@ -1,7 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte'
import ColourPicker from './ColourPicker.tsx';
import ReactAdapter from './utils/ReactAdapter.svelte';
import type { Component } from 'svelte'
import { animate } from 'motion';
import { delay } from '@/seqta/utils/delay.ts'
@@ -15,6 +14,19 @@
let background = $state<HTMLDivElement | null>(null);
let content = $state<HTMLDivElement | null>(null);
let ReactAdapter = $state<Component | null>(null);
let ColourPickerEl = $state<unknown>(null);
let pickerReady = $state(false);
const loadPicker = async () => {
const [adapterMod, pickerMod] = await Promise.all([
import('./utils/ReactAdapter.svelte'),
import('./ColourPicker.tsx'),
]);
ReactAdapter = adapterMod.default;
ColourPickerEl = pickerMod.default;
pickerReady = true;
};
const closePicker = async () => {
if (standalone) return;
@@ -37,28 +49,30 @@
);
await delay(400);
hidePicker();
hidePicker?.();
}
onMount(() => {
if (standalone) return;
if (!background || !content) return;
void loadPicker().then(() => {
if (standalone) return;
if (!background || !content) return;
animate(
background,
{ opacity: [0, 1] },
{ duration: 0.3, ease: [0.4, 0, 0.2, 1] }
);
animate(
background,
{ opacity: [0, 1] },
{ duration: 0.3, ease: [0.4, 0, 0.2, 1] }
);
animate(
content,
{ scale: [0.4, 1], opacity: [0, 1] },
{
type: 'spring',
stiffness: 400,
damping: 30
}
);
animate(
content,
{ scale: [0.4, 1], opacity: [0, 1] },
{
type: 'spring',
stiffness: 400,
damping: 30
}
);
});
const handleEscapeKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
@@ -82,7 +96,9 @@
{#if standalone}
<div class="h-auto overflow-clip rounded-xl">
<ReactAdapter customOnChange={customOnChange} customState={customState} savePresets={savePresets} el={ColourPicker} />
{#if pickerReady && ReactAdapter && ColourPickerEl}
<ReactAdapter customOnChange={customOnChange} customState={customState} savePresets={savePresets} el={ColourPickerEl} />
{/if}
</div>
{:else}
<!-- svelte-ignore a11y_no_static_element_interactions -->
@@ -96,7 +112,9 @@
bind:this={content}
class="p-4 h-auto bg-white rounded-xl border shadow-lg cursor-auto dark:bg-zinc-800 border-zinc-100 dark:border-zinc-700"
>
<ReactAdapter customOnChange={customOnChange} customState={customState} savePresets={savePresets} el={ColourPicker} />
{#if pickerReady && ReactAdapter && ColourPickerEl}
<ReactAdapter customOnChange={customOnChange} customState={customState} savePresets={savePresets} el={ColourPickerEl} />
{/if}
</div>
</div>
{/if}
@@ -59,23 +59,16 @@
</div>
</div>
<div class="overflow-hidden px-4 h-full">
<MotionDiv
class="h-full"
animate={{ x: `${-activeTab * 100}%` }}
transition={springTransition}
>
<div class="flex">
{#each tabs as { Content, props }, index}
{#each tabs as { Content, props }, index (index)}
{#if activeTab === index}
<div
role="tabpanel"
aria-hidden={activeTab !== index}
class="absolute focus:outline-none w-full pt-2 transition-opacity duration-300 overflow-y-scroll no-scrollbar pb-2 h-full tab {activeTab === index ? 'opacity-100 active' : 'opacity-0'}"
style="left: {index * 100}%;">
<div style="left: {index * 100}%;" class="fixed top-0 w-full h-8 bg-gradient-to-b to-transparent pointer-events-none z-[100] from-white dark:from-zinc-800 dark:to-transparent"></div>
<Content {...props} />
</div>
{/each}
</div>
</MotionDiv>
class="focus:outline-none w-full pt-2 overflow-y-scroll no-scrollbar pb-2 h-full tab active"
>
<div class="fixed top-0 w-full h-8 bg-gradient-to-b to-transparent pointer-events-none z-[100] from-white dark:from-zinc-800 dark:to-transparent"></div>
<Content {...props} />
</div>
{/if}
{/each}
</div>
</div>
+5 -2
View File
@@ -1,10 +1,13 @@
<script lang="ts">
import logo from '@/resources/icons/betterseqta-dark-full.png';
import logoDark from '@/resources/icons/betterseqta-light-full.png';
import { closeStore } from '@/seqta/ui/renderStore'
import browser from 'webextension-polyfill';
import CloudHeader from './CloudHeader.svelte';
const handleCloseStore = () => {
void import('@/seqta/ui/renderStore').then((module) => module.closeStore());
};
// Props
let { searchTerm, setSearchTerm, darkMode, activeTab, setActiveTab } = $props<{
searchTerm: string,
@@ -64,7 +67,7 @@
<!-- Close Button -->
<button
onclick={closeStore}
onclick={handleCloseStore}
class="p-1 px-3"
>
<span class="text-2xl font-IconFamily">&#xed8a;</span>
@@ -2,8 +2,6 @@
import type { CustomTheme, ThemeList } from '@/types/CustomThemes'
import { onDestroy, onMount } from 'svelte'
import browser from 'webextension-polyfill'
import { OpenThemeCreator } from '@/plugins/built-in/themes/ThemeCreator'
import { OpenStorePage } from '@/seqta/ui/renderStore'
import { themeUpdates } from '@/interface/hooks/ThemeUpdates'
import { closeExtensionPopup } from '@/seqta/utils/Closers/closeExtensionPopup'
import { ThemeManager } from '@/plugins/built-in/themes/theme-manager'
@@ -127,6 +125,17 @@
}
}
const openStorePage = async () => {
const { OpenStorePage } = await import('@/seqta/ui/renderStore')
OpenStorePage()
}
const openThemeCreator = async (themeId?: string) => {
const { OpenThemeCreator } = await import('@/plugins/built-in/themes/ThemeCreator')
OpenThemeCreator(themeId)
closeExtensionPopup()
}
const handleToggleFavorite = async (theme: CustomTheme, e: MouseEvent) => {
e.stopPropagation();
if (!cloudLoggedIn) {
@@ -212,8 +221,8 @@
</div>
<div
class="absolute z-20 flex w-8 h-8 p-2 text-white transition-all rounded-full delay-[20ms] opacity-0 top-1/4 right-2 bg-black/50 place-items-center group-hover:opacity-100 group-hover:top-1/2 -translate-y-1/2"
onclick={(event) => { event.stopPropagation(); OpenThemeCreator(theme.id); closeExtensionPopup() }}
onkeydown={(event) => { if (event.key === 'Enter' || event.key === ' ') OpenThemeCreator(theme.id); closeExtensionPopup() }}
onclick={(event) => { event.stopPropagation(); void openThemeCreator(theme.id) }}
onkeydown={(event) => { if (event.key === 'Enter' || event.key === ' ') void openThemeCreator(theme.id) }}
role="button"
tabindex="-1"
>
@@ -261,7 +270,7 @@
{/if}
<button
onclick={() => OpenStorePage()}
onclick={() => void openStorePage()}
class="flex justify-center items-center w-full rounded-xl transition aspect-theme bg-zinc-100 dark:bg-zinc-900 dark:text-white"
>
<span class="text-xl font-IconFamily">&#xecc5;</span>
@@ -269,7 +278,7 @@
</button>
<button
onclick={() => { OpenThemeCreator(); closeExtensionPopup() }}
onclick={() => void openThemeCreator()}
class="flex justify-center items-center w-full rounded-xl transition aspect-theme bg-zinc-100 dark:bg-zinc-900 dark:text-white"
>
<span class="text-xl font-IconFamily">&#xec60;</span>
+1 -53
View File
@@ -1,53 +1 @@
type SettingsPopupCallback = () => void;
/**
* This is a singleton that triggers an update when the settings popup is closed.
* This is used to close the colour picker.
* Usage:
* settingsPopup.addListener(() => {
* console.log('Settings popup closed');
* });
*/
class SettingsPopup {
private static instance: SettingsPopup;
private listeners: Set<SettingsPopupCallback> = new Set();
private constructor() {}
public static getInstance(): SettingsPopup {
if (!SettingsPopup.instance) {
SettingsPopup.instance = new SettingsPopup();
}
return SettingsPopup.instance;
}
/**
* Registers a callback function to be invoked when the settings popup is closed.
*
* @param {SettingsPopupCallback} callback The function to call when the settings popup closes.
* This callback takes no arguments and returns void.
*/
public addListener(callback: SettingsPopupCallback): void {
this.listeners.add(callback);
}
/**
* Unregisters a previously added callback function.
* After calling this method, the provided callback will no longer be invoked when the settings popup closes.
*
* @param {SettingsPopupCallback} callback The callback function to remove from the listeners.
*/
public removeListener(callback: SettingsPopupCallback): void {
this.listeners.delete(callback);
}
/**
* Invokes all registered listener callbacks.
* This method should be called when the settings popup is closed to notify all subscribed components or services.
*/
public triggerClose(): void {
this.listeners.forEach((callback) => callback());
}
}
export const settingsPopup = SettingsPopup.getInstance();
export { settingsPopup } from "@/seqta/utils/settingsPopup";
+10 -5
View File
@@ -14,11 +14,11 @@
import { OpenWhatsNewPopup } from "@/seqta/utils/Openers/OpenWhatsNewPopup";
//import { OpenMinecraftServerPopup } from "@/seqta/utils/Openers/OpenMinecraftServerPopup";
import ColourPicker from "../components/ColourPicker.svelte";
import type { Component } from "svelte";
import FontPickerModal from "../components/FontPickerModal.svelte";
import CloudPanel from "../components/CloudPanel.svelte";
import DisclaimerModal from "../components/DisclaimerModal.svelte";
import { settingsPopup } from "../hooks/SettingsPopup";
import { settingsPopup } from "@/seqta/utils/settingsPopup";
import {
checkGithubReleaseUpdate,
dismissNightlyUpdate,
@@ -64,7 +64,12 @@
}, 10000);
};
const openColourPicker = () => {
let ColourPickerComponent = $state<Component | null>(null);
const openColourPicker = async () => {
if (!ColourPickerComponent) {
ColourPickerComponent = (await import("../components/ColourPicker.svelte")).default;
}
showColourPicker = true;
};
@@ -363,8 +368,8 @@
/>
</div>
{#if showColourPicker}
<ColourPicker
{#if showColourPicker && ColourPickerComponent}
<ColourPickerComponent
hidePicker={() => {
showColourPicker = false;
}}