Added new setting to determine default display mode for tags

This commit is contained in:
Alejandro Celaya
2021-09-25 08:20:56 +02:00
parent 01f6f11ee2
commit 1da7119c5c
9 changed files with 84 additions and 28 deletions

View File

@@ -1,9 +1,12 @@
import { FC } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSun, faMoon } from '@fortawesome/free-solid-svg-icons';
import { FormGroup } from 'reactstrap';
import { SimpleCard } from '../utils/SimpleCard';
import ToggleSwitch from '../utils/ToggleSwitch';
import { changeThemeInMarkup, Theme } from '../utils/theme';
import { TagsModeDropdown } from '../tags/TagsModeDropdown';
import { capitalize } from '../utils/utils';
import { Settings, UiSettings } from './reducers/settings';
import './UserInterface.scss';
@@ -14,17 +17,28 @@ interface UserInterfaceProps {
export const UserInterface: FC<UserInterfaceProps> = ({ settings: { ui }, setUiSettings }) => (
<SimpleCard title="User interface" className="h-100">
<FontAwesomeIcon icon={ui?.theme === 'dark' ? faMoon : faSun} className="user-interface__theme-icon" />
<ToggleSwitch
checked={ui?.theme === 'dark'}
onChange={(useDarkTheme) => {
const theme: Theme = useDarkTheme ? 'dark' : 'light';
<FormGroup>
<FontAwesomeIcon icon={ui?.theme === 'dark' ? faMoon : faSun} className="user-interface__theme-icon" />
<ToggleSwitch
checked={ui?.theme === 'dark'}
onChange={(useDarkTheme) => {
const theme: Theme = useDarkTheme ? 'dark' : 'light';
setUiSettings({ theme });
changeThemeInMarkup(theme);
}}
>
Use dark theme.
</ToggleSwitch>
setUiSettings({ ...ui, theme });
changeThemeInMarkup(theme);
}}
>
Use dark theme.
</ToggleSwitch>
</FormGroup>
<FormGroup className="mb-0">
<label>Default display mode when managing tags:</label>
<TagsModeDropdown
mode={ui?.tagsMode ?? 'cards'}
renderTitle={(tagsMode) => capitalize(tagsMode)}
onChange={(tagsMode) => setUiSettings({ ...ui ?? { theme: 'light' }, tagsMode })}
/>
<small className="form-text text-muted">Tags will be displayed as <b>{ui?.tagsMode ?? 'cards'}</b>.</small>
</FormGroup>
</SimpleCard>
);

View File

@@ -24,8 +24,11 @@ export interface ShortUrlCreationSettings {
tagFilteringMode?: TagFilteringMode;
}
export type TagsMode = 'cards' | 'list';
export interface UiSettings {
theme: Theme;
tagsMode?: TagsMode;
}
export interface VisitsSettings {

View File

@@ -7,21 +7,23 @@ import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
import { Result } from '../utils/Result';
import { ShlinkApiError } from '../api/ShlinkApiError';
import { Topics } from '../mercure/helpers/Topics';
import { Settings, TagsMode } from '../settings/reducers/settings';
import { TagsList as TagsListState } from './reducers/tagsList';
import { TagsListChildrenProps } from './data/TagsListChildrenProps';
import { TagsMode, TagsModeDropdown } from './TagsModeDropdown';
import { TagsModeDropdown } from './TagsModeDropdown';
export interface TagsListProps {
filterTags: (searchTerm: string) => void;
forceListTags: Function;
tagsList: TagsListState;
selectedServer: SelectedServer;
settings: Settings;
}
const TagsList = (TagsCards: FC<TagsListChildrenProps>, TagsTable: FC<TagsListChildrenProps>) => boundToMercureHub((
{ filterTags, forceListTags, tagsList, selectedServer }: TagsListProps,
{ filterTags, forceListTags, tagsList, selectedServer, settings }: TagsListProps,
) => {
const [ mode, setMode ] = useState<TagsMode>('cards');
const [ mode, setMode ] = useState<TagsMode>(settings.ui?.tagsMode ?? 'cards');
useEffect(() => {
forceListTags();

View File

@@ -3,16 +3,16 @@ import { DropdownItem } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBars as listIcon, faThLarge as cardsIcon } from '@fortawesome/free-solid-svg-icons';
import { DropdownBtn } from '../utils/DropdownBtn';
import { TagsMode } from '../settings/reducers/settings';
interface TagsModeDropdownProps {
mode: TagsMode;
onChange: (newMode: TagsMode) => void;
renderTitle?: (mode: TagsMode) => string;
}
export type TagsMode = 'cards' | 'list';
export const TagsModeDropdown: FC<TagsModeDropdownProps> = ({ mode, onChange }) => (
<DropdownBtn text={`Display mode: ${mode}`}>
export const TagsModeDropdown: FC<TagsModeDropdownProps> = ({ mode, onChange, renderTitle }) => (
<DropdownBtn text={renderTitle?.(mode) ?? `Display mode: ${mode}`}>
<DropdownItem outline active={mode === 'cards'} onClick={() => onChange('cards')}>
<FontAwesomeIcon icon={cardsIcon} fixedWidth className="mr-1" /> Cards
</DropdownItem>

View File

@@ -38,7 +38,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.serviceFactory('TagsList', TagsList, 'TagsCards', 'TagsTable');
bottle.decorator('TagsList', connect(
[ 'tagsList', 'selectedServer', 'mercureInfo' ],
[ 'tagsList', 'selectedServer', 'mercureInfo', 'settings' ],
[ 'forceListTags', 'filterTags', 'createNewVisits', 'loadMercureInfo' ],
));

View File

@@ -45,3 +45,5 @@ export type RecursivePartial<T> = {
};
export const nonEmptyValueOrNull = <T>(value: T): T | null => isEmpty(value) ? null : value;
export const capitalize = <T extends string>(value: T): string => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;