Skip to content

Commit

Permalink
feat(front): add tab position config
Browse files Browse the repository at this point in the history
  • Loading branch information
SARDONYX-sard committed Oct 20, 2024
1 parent 9d93c0b commit bd70b06
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useTranslation } from '@/components/hooks/useTranslation';
import { SelectWithLabel } from '@/components/molecules/SelectWithLabel';
import { useTabContext } from '@/components/providers/TabProvider';

import type { SelectChangeEvent } from '@mui/material/Select/Select';

export const TabPositionList = () => {
const { t } = useTranslation();
const { tabPos, setTabPos } = useTabContext();

const handleChange = ({ target }: SelectChangeEvent) => setTabPos(target.value);

const menuItems = [
{ value: 'top', label: t('tab-list-position-top') },
{ value: 'bottom', label: t('tab-list-position-bottom') },
] as const;

return (
<SelectWithLabel
label={t('tab-list-position-label')}
menuItems={menuItems}
onChange={handleChange}
value={tabPos}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { TabPositionList } from './TabPositionList';
9 changes: 8 additions & 1 deletion gui/frontend/src/components/organisms/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import { CssList } from '@/components/organisms/CssList';
import { EditorList } from '@/components/organisms/EditorList/EditorList';
import { I18nList } from '@/components/organisms/I18nList';
import { NotifyList } from '@/components/organisms/NotifyList';
import { TabPositionList } from '@/components/organisms/TabPositionList';
import { PUB_CACHE_OBJ } from '@/lib/storage/cacheKeys';

import type { SyntheticEvent } from 'react';

export const Tabs = () => {
const [selectedTab, setSelectedTab] = useStorageState('settings-tab-select', 'editor');
const [selectedTab, setSelectedTab] = useStorageState(PUB_CACHE_OBJ.settingsTabSelect, 'editor');
const { t } = useTranslation();

const handleChange = (_event: SyntheticEvent, tabId: string) => setSelectedTab(tabId);
Expand All @@ -37,6 +39,7 @@ export const Tabs = () => {
<Tab label={t('tab-label-editor')} value='editor' />
<Tab label={t('tab-label-notice')} value='notice' />
<Tab label={t('tab-label-lang')} value='lang' />
<Tab label={t('tab-label-tab')} value='tab' />
<Tab label={t('tab-label-backup')} value='backup' />
</TabList>
</Box>
Expand All @@ -56,6 +59,10 @@ export const Tabs = () => {
<I18nList />
</TabPanel>

<TabPanel value='tab'>
<TabPositionList />
</TabPanel>

<TabPanel value='backup'>
<BackupImportButton />
<BackupExportButton />
Expand Down
41 changes: 41 additions & 0 deletions gui/frontend/src/components/providers/TabProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { type ReactNode, createContext, useContext, useState } from 'react';

import { STORAGE } from '@/lib/storage';
import { PUB_CACHE_OBJ } from '@/lib/storage/cacheKeys';

type TabPosition = 'top' | 'bottom';
type ContextType = {
tabPos: TabPosition;
setTabPos: (value?: string) => void;
};
const Context = createContext<ContextType | undefined>(undefined);

const normalize = (value: string | null) => (value === 'bottom' ? 'bottom' : 'top');

type Props = { children: ReactNode };
export const TabProvider = ({ children }: Props) => {
const [tabPos, setTabPos] = useState<TabPosition>(normalize(STORAGE.get(PUB_CACHE_OBJ.settingsTabPosition)));

const setHook = (value?: string) => {
if (value) {
const validValue = normalize(value);
setTabPos(validValue);
STORAGE.set(PUB_CACHE_OBJ.settingsTabPosition, validValue);
} else {
STORAGE.remove(PUB_CACHE_OBJ.settingsTabPosition);
}
};

return <Context.Provider value={{ tabPos, setTabPos: setHook }}>{children}</Context.Provider>;
};

/**
* @throws `useTabContext must be used within a TabProvider`
*/
export const useTabContext = () => {
const context = useContext(Context);
if (!context) {
throw new Error('useJsContext must be used within a TabProvider');
}
return context;
};
19 changes: 11 additions & 8 deletions gui/frontend/src/components/providers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { EditorModeProvider } from '@/components/providers/EditorModeProvider';
import { JsProvider } from '@/components/providers/JsProvider';
import { LogLevelProvider } from '@/components/providers/LogLevelProvider';
import NotifyProvider from '@/components/providers/NotifyProvider';
import { TabProvider } from '@/components/providers/TabProvider';

import type { ComponentProps, ReactNode } from 'react';

Expand Down Expand Up @@ -37,14 +38,16 @@ export const GlobalProvider = ({ children }: Props) => {
<ThemeProvider theme={darkTheme}>
<NotifyProvider />
<LogLevelProvider>
<EditorModeProvider>
<JsProvider>
<CssProvider>
<CssBaseline />
{children}
</CssProvider>
</JsProvider>
</EditorModeProvider>
<TabProvider>
<EditorModeProvider>
<JsProvider>
<CssProvider>
<CssBaseline />
{children}
</CssProvider>
</JsProvider>
</EditorModeProvider>
</TabProvider>
</LogLevelProvider>
</ThemeProvider>
);
Expand Down
38 changes: 27 additions & 11 deletions gui/frontend/src/components/templates/Settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Help } from '@/components/atoms/Help';
import { useInjectJs } from '@/components/hooks/useInjectJs';
import { CodeEditor } from '@/components/organisms/CodeEditor';
import { Tabs } from '@/components/organisms/Tabs';
import { useTabContext } from '@/components/providers/TabProvider';
import { start } from '@/services/api/shell';

import packageJson from '@/../../package.json';
Expand All @@ -23,23 +24,38 @@ const sx: SxProps<Theme> = {

export const Settings = () => {
useInjectJs();
const { tabPos } = useTabContext();

return (
<Box component='main' sx={sx}>
{tabPos === 'top' ? (
<>
<TabsMenu />
<CodeEditor />
</>
) : (
<>
<CodeEditor />
<TabsMenu />
</>
)}
</Box>
);
};

const TabsMenu = () => {
const handleHelpClick: MouseEventHandler<HTMLButtonElement> = (_event) => {
start(packageJson.homepage); // jump by backend api
};

return (
<Box component='main' sx={sx}>
<CodeEditor />

<Grid container={true} sx={{ width: '95%' }}>
<Grid size={8} sx={{ overflowX: 'auto' }}>
<Tabs />
</Grid>
<Grid size={4} sx={{ overflowX: 'auto' }}>
<Help onClick={handleHelpClick} version={packageJson.version} />
</Grid>
<Grid container={true} sx={{ width: '95%' }}>
<Grid size={8} sx={{ overflowX: 'auto' }}>
<Tabs />
</Grid>
</Box>
<Grid size={4} sx={{ overflowX: 'auto' }}>
<Help onClick={handleHelpClick} version={packageJson.version} />
</Grid>
</Grid>
);
};
7 changes: 6 additions & 1 deletion gui/frontend/src/lib/storage/cacheKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const PUB_CACHE_KEYS_OBJ = {
editorTabSelect: 'editor-tab-select',
locale: 'locale',
settingsTabSelect: 'settings-tab-select',
settingsTabPosition: 'settings-tab-position',
snackbarLimit: 'snackbar-limit',
snackbarPosition: 'snackbar-position',
} as const;
Expand All @@ -50,14 +51,18 @@ export const PRIVATE_CACHE_OBJ = {
...PRIVATE_CACHE_KEYS_OBJ,
} as const;

export const HIDDEN_CACHE_OBJ = {
runScript: 'run-script',
} as const;

/** Public cache keys that are available and exposed for standard use in the application. */
export const PUB_CACHE_KEYS = [...OBJECT.values(PUB_CACHE_OBJ)] as const;

/** Private cache keys that are internal to the application and may involve sensitive data or paths. */
const PRIVATE_CACHE_KEYS = [...OBJECT.values(PRIVATE_CACHE_OBJ)] as const;

/** Hidden cache keys, typically used for restricted data like permissions for running scripts. */
export const HIDDEN_CACHE_KEYS = ['run-script'] as const;
export const HIDDEN_CACHE_KEYS = [...OBJECT.values(HIDDEN_CACHE_OBJ)] as const;

/** Aggregated list of both public and private cache keys. */
export const CACHE_KEYS = [...PUB_CACHE_KEYS, ...PRIVATE_CACHE_KEYS] as const;
4 changes: 4 additions & 0 deletions locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
"tab-label-editor": "Editor / Preset",
"tab-label-lang": "Language",
"tab-label-notice": "Notice",
"tab-label-tab": "Tab",
"tab-list-position-bottom": "Bottom",
"tab-list-position-label": "Tab Position",
"tab-list-position-top": "Top",
"unhide-dar-btn": "Unhide DAR",
"unhide-dar-btn-tooltip": "Unhide DAR files hidden by \"Hide DAR\".(For MO2 user)",
"unhide-dar-failed": "Could not find files with \".mohidden\" extension",
Expand Down
4 changes: 4 additions & 0 deletions locales/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
"tab-label-editor": "エディタ・プリセット",
"tab-label-lang": "言語",
"tab-label-notice": "通知",
"tab-label-tab": "タブ",
"tab-list-position-bottom": "",
"tab-list-position-label": "タブの位置",
"tab-list-position-top": "",
"unhide-dar-btn": "DAR再表示",
"unhide-dar-btn-tooltip": "「DARを非表示」による非表示化の解除(MO2ユーザ向け)",
"unhide-dar-failed": "拡張子「.mohidden」のついたファイルが見つかりません",
Expand Down

0 comments on commit bd70b06

Please sign in to comment.