UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

94 lines (93 loc) 3.45 kB
/* * Copyright 2025 The Kubernetes Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { createSlice } from '@reduxjs/toolkit'; import { useSelector } from 'react-redux'; import { getThemeName, setTheme as setAppTheme } from '../../lib/themes'; import defaultAppThemes from './defaultAppThemes'; export const initialState = { logo: null, name: getThemeName(), appThemes: defaultAppThemes, }; const themeSlice = createSlice({ name: 'theme', initialState, reducers: { /** * Sets the logo component to use for the app. */ setBrandingAppLogoComponent(state, action) { state.logo = action.payload; }, /** * Sets the theme name of the application. */ setTheme(state, action) { state.name = action.payload; setAppTheme(state.name); }, addCustomAppTheme(state, action) { state.appThemes = state.appThemes.filter(it => it.name !== action.payload.name); state.appThemes.push(action.payload); }, /** Checks if the selected theme name doesn't exist anymore and sets a fallback */ ensureValidThemeName(state) { const existingTheme = state.appThemes.find(it => it.name === state.name); if (!existingTheme) { // Remove cached theme name so that getThemeName returns theme that // preferred by OS and not the cached name setAppTheme(''); const defaultThemeName = getThemeName(); state.name = defaultThemeName; setAppTheme(defaultThemeName); } }, }, }); export const useAppThemes = () => { return useSelector((state) => state.theme.appThemes); }; const currentThemeCacheKey = 'cached-current-theme'; export const useCurrentAppTheme = () => { let themeName = useSelector((state) => state.theme.name); if (!themeName) { themeName = getThemeName(); } const allThemes = useAppThemes(); let currentTheme = allThemes.find(it => it.name === themeName); if (currentTheme) { localStorage.setItem(currentThemeCacheKey, JSON.stringify(currentTheme)); } else { // Try to load cached theme const cachedThemeRaw = localStorage.getItem(currentThemeCacheKey); if (cachedThemeRaw) { try { const cachedTheme = JSON.parse(cachedThemeRaw); if (cachedTheme && cachedTheme?.name === themeName) { currentTheme = cachedTheme; } } catch (e) { console.debug('Failed to parse cached theme from localStorage:', e); } } } return currentTheme ?? defaultAppThemes[0]; }; export const { setBrandingAppLogoComponent, setTheme } = themeSlice.actions; export { themeSlice }; export default themeSlice.reducer;