feat: GIF search (Klipy), stickers, emoji picker, and bug fixes

- Add GIF search powered by Klipy API with correct response mapping
  (file.sm/hd tiers, not flat files structure)
- Add sticker system: packs, upload with auto-downscale, send in messages
- Add tabbed InputPopover with emoji, GIF, and sticker pickers
- Fix GIF API key migration race condition (column-add loop vs rename)
- Fix masked API key corruption on settings save (server + client guards)
- Fix sticker packs 403 (reversed isMember parameter order)
- Fix emoji picker not filling popover width (perLine 8→9, CSS 100%)
- Add error logging for Klipy API failures
This commit is contained in:
Jannis Braun
2026-03-15 02:04:37 +01:00
parent 7113f47b17
commit 3de6e4a668
26 changed files with 2160 additions and 50 deletions
+12
View File
@@ -6,10 +6,12 @@ interface SettingsState {
streamingLimits: InstanceStreamingLimits | null;
instanceSettings: InstanceAdminSettings | null;
isAdmin: boolean;
gifEnabled: boolean;
fetchStreamingLimits: () => Promise<void>;
updateStreamingLimits: (limits: Partial<InstanceStreamingLimits>) => Promise<void>;
fetchInstanceSettings: () => Promise<void>;
updateInstanceSettings: (data: Partial<InstanceAdminSettings>) => Promise<void>;
fetchGifEnabled: () => Promise<void>;
setIsAdmin: (isAdmin: boolean) => void;
}
@@ -32,6 +34,7 @@ export const useSettingsStore = create<SettingsState>((set) => ({
streamingLimits: null,
instanceSettings: null,
isAdmin: false,
gifEnabled: false,
fetchStreamingLimits: async () => {
try {
@@ -70,5 +73,14 @@ export const useSettingsStore = create<SettingsState>((set) => ({
}
},
fetchGifEnabled: async () => {
try {
const { enabled } = await api.gif.enabled();
set({ gifEnabled: enabled });
} catch {
set({ gifEnabled: false });
}
},
setIsAdmin: (isAdmin: boolean) => set({ isAdmin }),
}));