diff --git a/src/taskpane/components/App.tsx b/src/taskpane/components/App.tsx
index 6887a506..27c39695 100644
--- a/src/taskpane/components/App.tsx
+++ b/src/taskpane/components/App.tsx
@@ -7,14 +7,17 @@ import ProtectedRoutes from '../../utils/ProtectedRoutes';
import { CitationStoreProvider } from '../contexts/CitationStoreContext';
import { CiteSupportProvider } from '../contexts/CiteSupportContext';
import Wrapper from './Wrapper';
+import { ThemeContextProvider } from '../contexts/ThemeContext';
+import { Theme } from '../../../types';
export interface AppProps {
title: string;
+ theme: Theme;
isOfficeInitialized: boolean;
}
function App(props: AppProps): ReactElement {
- const { isOfficeInitialized, title } = props;
+ const { isOfficeInitialized, title, theme } = props;
if (!isOfficeInitialized) {
return (
@@ -23,20 +26,22 @@ function App(props: AppProps): ReactElement {
}
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
export default App;
diff --git a/src/taskpane/components/Footer.tsx b/src/taskpane/components/Footer.tsx
index bc10bb4e..658d402a 100644
--- a/src/taskpane/components/Footer.tsx
+++ b/src/taskpane/components/Footer.tsx
@@ -1,7 +1,10 @@
import { Stack, ActionButton } from '@fluentui/react';
import React, { ReactElement } from 'react';
+import { Theme } from '../../../types';
import {
+ light,
+ dark,
Signout,
SyncBib,
imageProps,
@@ -13,9 +16,11 @@ import {
interface FooterProps {
onSyncBibliography: () => void;
onLogout: () => void;
+ onThemeChange: () => void;
+ theme: Theme;
}
-function Footer({ onSyncBibliography, onLogout }: FooterProps): ReactElement {
+function Footer({ onSyncBibliography, onLogout, onThemeChange, theme }: FooterProps): ReactElement {
return (
+
void;
+}
+
+const ThemeContext = createContext(null);
+
+const getTheme = (theme: Theme) => (theme === Theme.DARK ? darkTheme : lightTheme);
+
+export function ThemeContextProvider({ children, initTheme }: ThemeContextProps): JSX.Element {
+ const [theme, setThemeValue] = React.useState(initTheme);
+ const changeTheme = () => {
+ setThemeValue((prevVal) => {
+ const newVal = prevVal === Theme.DARK ? Theme.LIGHT : Theme.DARK;
+ UserPreferences.setTheme(newVal);
+ UserPreferences.syncPreferences();
+ return newVal;
+ });
+ };
+ const value = { theme, changeTheme };
+ return (
+
+ {children}
+
+ );
+}
+
+export const useTheme = (): ThemeContextInterface => {
+ const context = React.useContext(ThemeContext);
+ if (!context) {
+ throw new Error(
+ 'useTheme must be used within a ThemeContextProvider. Wrap a parent component in to fix this error.'
+ );
+ }
+ return context;
+};
+
+export default ThemeContext;
diff --git a/src/taskpane/index.tsx b/src/taskpane/index.tsx
index a1fcc2e9..4313d0fe 100644
--- a/src/taskpane/index.tsx
+++ b/src/taskpane/index.tsx
@@ -14,11 +14,13 @@ import { initializeIcons, ThemeProvider } from '@fluentui/react';
import { HashRouter as Router } from 'react-router-dom';
import App from './components/App';
import client from '../plugins/apollo/apolloClient';
+import { Theme } from '../../types';
+import UserPreferences from '../utils/UserPreferences';
initializeIcons();
+let theme: Theme;
let isOfficeInitialized = false;
-
const title = 'JabRef Task Pane Add-in';
const render = (Component) => {
@@ -27,7 +29,7 @@ const render = (Component) => {
-
+
@@ -40,6 +42,7 @@ const render = (Component) => {
// eslint-disable-next-line no-void
void Office.onReady(() => {
isOfficeInitialized = true;
+ theme = UserPreferences.getTheme();
render(App);
});
diff --git a/src/taskpane/layout/Layout.tsx b/src/taskpane/layout/Layout.tsx
index 190ac154..6d9cffa8 100644
--- a/src/taskpane/layout/Layout.tsx
+++ b/src/taskpane/layout/Layout.tsx
@@ -7,6 +7,7 @@ import { pivotStyle, scrollableStack } from './Layout.style';
import { useCiteSupport } from '../contexts/CiteSupportContext';
import { useLogoutMutation } from '../../generated/graphql';
import client from '../../plugins/apollo/apolloClient';
+import { useTheme } from '../contexts/ThemeContext';
type pivotItem = 'citationStyle' | 'dashboard';
@@ -15,6 +16,8 @@ const getTabId = (itemKey: string) => {
};
function Layout(): JSX.Element {
+ const { theme, changeTheme } = useTheme();
+
const [selectedKey, setSelectedKey] = useState('dashboard');
const handleLinkClick = (item?: PivotItem) => {
@@ -51,7 +54,12 @@ function Layout(): JSX.Element {
{selectedKey === 'dashboard' ? : }
-
+
);
diff --git a/src/taskpane/pages/Dashboard.tsx b/src/taskpane/pages/Dashboard.tsx
index fb6fb146..ae9a3f96 100644
--- a/src/taskpane/pages/Dashboard.tsx
+++ b/src/taskpane/pages/Dashboard.tsx
@@ -8,6 +8,7 @@ import { useCiteSupport } from '../contexts/CiteSupportContext';
import ReferenceList from '../components/ReferenceList';
import ButtonGroup from '../components/ButtonGroup';
import { scrollableStack } from '../layout/Layout.style';
+import { Mode } from '../../../types';
const buttonLabel = (length: number) =>
length > 0
@@ -27,6 +28,7 @@ function containsSearchTerm(keyword: string) {
function Dashboard(): ReactElement {
const originalItems = data; // TODO: Replace with getData hooK
const citeSupport = useCiteSupport();
+ const [mode, setMode] = useState(Mode.REST);
const { selectedCitations, dispatch } = useCitationStore();
const [referenceList, setReferenceList] = useState>(originalItems);
const [citationItems, _setCitationItems] = useState>([]);
@@ -74,6 +76,16 @@ function Dashboard(): ReactElement {
return () => citeSupport.wordApi.removeEventListener();
}, [citeSupport.wordApi, getSelectedCitation]);
+ useEffect(() => {
+ if (selectedCitations.length && !itemsInSelectedCitation.current.length) {
+ setMode(Mode.CITE);
+ } else if (itemsInSelectedCitation.current.length) {
+ setMode(Mode.EDIT);
+ } else {
+ setMode(Mode.REST);
+ }
+ }, [selectedCitations, itemsInSelectedCitation.current.length, setMode]);
+
return (
@@ -82,7 +94,7 @@ function Dashboard(): ReactElement {
- {selectedCitations.length && !itemsInSelectedCitation.current.length ? (
+ {mode === Mode.CITE ? (
) : null}
- {itemsInSelectedCitation.current.length ? (
+ {mode === Mode.EDIT ? (