From 152aa51a2821816eaabb232ba7316286f7c86435 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 15 May 2020 01:03:56 +0200 Subject: [PATCH] packages/core: added localStorage support for AppThemeSelector --- .../AppThemeSelector/AppThemeSelector.test.ts | 37 +++++++++++++++++++ .../AppThemeSelector/AppThemeSelector.ts | 28 ++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/packages/core/src/api/apis/implementations/AppThemeSelector/AppThemeSelector.test.ts b/packages/core/src/api/apis/implementations/AppThemeSelector/AppThemeSelector.test.ts index 6c6c9774bd..0c23fe5219 100644 --- a/packages/core/src/api/apis/implementations/AppThemeSelector/AppThemeSelector.test.ts +++ b/packages/core/src/api/apis/implementations/AppThemeSelector/AppThemeSelector.test.ts @@ -45,4 +45,41 @@ describe('AppThemeSelector', () => { expect(selector.getInstalledThemes()).toEqual(themes); expect(selector.getInstalledThemes()).not.toBe(themes); }); + + it('should store theme in local storage', async () => { + expect(AppThemeSelector.createWithStorage([]).getActiveThemeId()).toBe( + undefined, + ); + localStorage.setItem('theme', 'x'); + expect(AppThemeSelector.createWithStorage([]).getActiveThemeId()).toBe('x'); + localStorage.removeItem('theme'); + expect(AppThemeSelector.createWithStorage([]).getActiveThemeId()).toBe( + undefined, + ); + + const addListenerSpy = jest.spyOn(window, 'addEventListener'); + const selector = AppThemeSelector.createWithStorage([]); + + expect(addListenerSpy).toHaveBeenCalledTimes(1); + expect(addListenerSpy).toHaveBeenCalledWith( + 'storage', + expect.any(Function), + ); + + selector.setActiveThemeId('y'); + await 'wait a tick'; + expect(localStorage.getItem('theme')).toBe('y'); + + selector.setActiveThemeId(undefined); + await 'wait a tick'; + expect(localStorage.getItem('theme')).toBe(null); + + localStorage.setItem('theme', 'z'); + expect(selector.getActiveThemeId()).toBe(undefined); + + const listener = addListenerSpy.mock.calls[0][1] as EventListener; + listener({ key: 'theme' } as StorageEvent); + + expect(selector.getActiveThemeId()).toBe('z'); + }); }); diff --git a/packages/core/src/api/apis/implementations/AppThemeSelector/AppThemeSelector.ts b/packages/core/src/api/apis/implementations/AppThemeSelector/AppThemeSelector.ts index 97343f8d1b..59bc746c41 100644 --- a/packages/core/src/api/apis/implementations/AppThemeSelector/AppThemeSelector.ts +++ b/packages/core/src/api/apis/implementations/AppThemeSelector/AppThemeSelector.ts @@ -17,7 +17,35 @@ import Observable from 'zen-observable'; import { AppThemeApi, AppTheme } from '../../definitions'; +const STORAGE_KEY = 'theme'; + export class AppThemeSelector implements AppThemeApi { + static createWithStorage(themes: AppTheme[]) { + const selector = new AppThemeSelector(themes); + + const initialThemeId = + window?.localStorage.getItem(STORAGE_KEY) ?? undefined; + + selector.setActiveThemeId(initialThemeId); + + selector.activeThemeId$().subscribe((themeId) => { + if (themeId) { + window?.localStorage.setItem(STORAGE_KEY, themeId); + } else { + window?.localStorage.removeItem(STORAGE_KEY); + } + }); + + window.addEventListener('storage', (event) => { + if (event.key === STORAGE_KEY) { + const themeId = localStorage.getItem(STORAGE_KEY) ?? undefined; + selector.setActiveThemeId(themeId); + } + }); + + return selector; + } + private readonly themes: AppTheme[]; private activeThemeId: string | undefined;