Add emoji confetti bursts and component playground.

Support app.relay.emoji_confetti on jumbo emoji clicks with canvas physics,
per-emoji particle profiles, and a fixed overlay that does not affect scroll.
Also add a Vite playground for live component previews and theme hover preview.
This commit is contained in:
2026-07-29 20:40:36 +10:00
parent ea7642f0bb
commit 0da4f0d6cb
48 changed files with 3689 additions and 46 deletions

View File

@@ -1,4 +1,5 @@
import { lightTheme } from 'folds';
import { atom, useAtomValue } from 'jotai';
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { onDarkFontWeight, onLightFontWeight } from '../../config.css';
import { butterTheme, catppuccinMochaTheme, darkTheme, discordTheme, discordDarkerTheme, mochaTheme, silverTheme, stationeryDarkTheme, stationeryTheme, twilightTheme } from '../../colors.css';
@@ -6,6 +7,9 @@ import { settingsAtom } from '../state/settings';
import { useSetting } from '../state/hooks/settings';
import { pluginRegistry } from '../features/settings/plugins/PluginAPI';
/** Ephemeral theme id while hovering theme options in settings (not persisted). */
export const themePreviewIdAtom = atom<string | undefined>(undefined);
export enum ThemeKind {
Light = 'light',
Dark = 'dark',
@@ -190,6 +194,16 @@ export const useActiveTheme = (): Theme => {
return selectedTheme;
};
/** Active theme, or hover-preview theme when browsing the theme menu. */
export const useDisplayTheme = (): Theme => {
const activeTheme = useActiveTheme();
const themes = useThemes();
const previewId = useAtomValue(themePreviewIdAtom);
if (!previewId) return activeTheme;
return themes.find((theme) => theme.id === previewId) ?? activeTheme;
};
const ThemeContext = createContext<Theme | null>(null);
export const ThemeContextProvider = ThemeContext.Provider;