mirror of
https://github.com/pawelmalak/flame.git
synced 2026-03-11 14:53:55 +08:00
Merge branch 'feature' into v1.7.0
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
.SettingsSection {
|
||||
color: var(--color-primary);
|
||||
padding-bottom: 3px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
border-bottom: 2px solid var(--color-accent);
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -13,20 +13,16 @@ import {
|
||||
import {
|
||||
GlobalState,
|
||||
NewNotification,
|
||||
Query,
|
||||
SettingsForm,
|
||||
} from '../../../interfaces';
|
||||
|
||||
// UI
|
||||
import InputGroup from '../../UI/Forms/InputGroup/InputGroup';
|
||||
import Button from '../../UI/Buttons/Button/Button';
|
||||
|
||||
// CSS
|
||||
import classes from './OtherSettings.module.css';
|
||||
import SettingsHeadline from '../../UI/Headlines/SettingsHeadline/SettingsHeadline';
|
||||
|
||||
// Utils
|
||||
import { searchConfig } from '../../../utility';
|
||||
import { queries } from '../../../utility/searchQueries.json';
|
||||
|
||||
interface ComponentProps {
|
||||
createNotification: (notification: NewNotification) => void;
|
||||
@@ -45,12 +41,9 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
||||
hideHeader: 0,
|
||||
hideApps: 0,
|
||||
hideCategories: 0,
|
||||
hideSearch: 0,
|
||||
defaultSearchProvider: 'd',
|
||||
useOrdering: 'createdAt',
|
||||
appsSameTab: 0,
|
||||
bookmarksSameTab: 0,
|
||||
searchSameTab: 0,
|
||||
dockerApps: 1,
|
||||
dockerHost: 'localhost',
|
||||
kubernetesApps: 1,
|
||||
@@ -66,12 +59,9 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
||||
hideHeader: searchConfig('hideHeader', 0),
|
||||
hideApps: searchConfig('hideApps', 0),
|
||||
hideCategories: searchConfig('hideCategories', 0),
|
||||
hideSearch: searchConfig('hideSearch', 0),
|
||||
defaultSearchProvider: searchConfig('defaultSearchProvider', 'd'),
|
||||
useOrdering: searchConfig('useOrdering', 'createdAt'),
|
||||
appsSameTab: searchConfig('appsSameTab', 0),
|
||||
bookmarksSameTab: searchConfig('bookmarksSameTab', 0),
|
||||
searchSameTab: searchConfig('searchSameTab', 0),
|
||||
dockerApps: searchConfig('dockerApps', 0),
|
||||
dockerHost: searchConfig('dockerHost', 'localhost'),
|
||||
kubernetesApps: searchConfig('kubernetesApps', 0),
|
||||
@@ -114,7 +104,7 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
||||
return (
|
||||
<form onSubmit={(e) => formSubmitHandler(e)}>
|
||||
{/* OTHER OPTIONS */}
|
||||
<h2 className={classes.SettingsSection}>Miscellaneous</h2>
|
||||
<SettingsHeadline text="Miscellaneous" />
|
||||
<InputGroup>
|
||||
<label htmlFor="customTitle">Custom page title</label>
|
||||
<input
|
||||
@@ -128,7 +118,7 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
||||
</InputGroup>
|
||||
|
||||
{/* BEAHVIOR OPTIONS */}
|
||||
<h2 className={classes.SettingsSection}>App Behavior</h2>
|
||||
<SettingsHeadline text="App Behavior" />
|
||||
<InputGroup>
|
||||
<label htmlFor="pinAppsByDefault">
|
||||
Pin new applications by default
|
||||
@@ -170,35 +160,6 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
||||
<option value="orderId">Custom order</option>
|
||||
</select>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="defaultSearchProvider">Default Search Provider</label>
|
||||
<select
|
||||
id="defaultSearchProvider"
|
||||
name="defaultSearchProvider"
|
||||
value={formData.defaultSearchProvider}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
>
|
||||
{queries.map((query: Query, idx) => (
|
||||
<option key={idx} value={query.prefix}>
|
||||
{query.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="searchSameTab">
|
||||
Open search results in the same tab
|
||||
</label>
|
||||
<select
|
||||
id="searchSameTab"
|
||||
name="searchSameTab"
|
||||
value={formData.searchSameTab}
|
||||
onChange={(e) => inputChangeHandler(e, true)}
|
||||
>
|
||||
<option value={1}>True</option>
|
||||
<option value={0}>False</option>
|
||||
</select>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="appsSameTab">Open applications in the same tab</label>
|
||||
<select
|
||||
@@ -225,19 +186,7 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
||||
</InputGroup>
|
||||
|
||||
{/* MODULES OPTIONS */}
|
||||
<h2 className={classes.SettingsSection}>Modules</h2>
|
||||
<InputGroup>
|
||||
<label htmlFor="hideSearch">Hide search bar</label>
|
||||
<select
|
||||
id="hideSearch"
|
||||
name="hideSearch"
|
||||
value={formData.hideSearch}
|
||||
onChange={(e) => inputChangeHandler(e, true)}
|
||||
>
|
||||
<option value={1}>True</option>
|
||||
<option value={0}>False</option>
|
||||
</select>
|
||||
</InputGroup>
|
||||
<SettingsHeadline text="Modules" />
|
||||
<InputGroup>
|
||||
<label htmlFor="hideHeader">Hide greeting and date</label>
|
||||
<select
|
||||
@@ -276,7 +225,7 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
||||
</InputGroup>
|
||||
|
||||
{/* DOCKER SETTINGS */}
|
||||
<h2 className={classes.SettingsSection}>Docker</h2>
|
||||
<SettingsHeadline text="Docker" />
|
||||
<InputGroup>
|
||||
<label htmlFor="dockerHost">Docker Host</label>
|
||||
<input
|
||||
@@ -316,7 +265,7 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
||||
</InputGroup>
|
||||
|
||||
{/* KUBERNETES SETTINGS */}
|
||||
<h2 className={classes.SettingsSection}>Kubernetes</h2>
|
||||
<SettingsHeadline text="Kubernetes" />
|
||||
<InputGroup>
|
||||
<label htmlFor="kubernetesApps">Use Kubernetes Ingress API</label>
|
||||
<select
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
.QueriesGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.QueriesGrid span {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.QueriesGrid span:last-child {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.ActionIcons {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.ActionIcons svg {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.ActionIcons svg:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Separator {
|
||||
grid-column: 1 / 4;
|
||||
border-bottom: 1px solid var(--color-primary);
|
||||
margin: 10px 0;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import { Fragment, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import classes from './CustomQueries.module.css';
|
||||
|
||||
import Modal from '../../../UI/Modal/Modal';
|
||||
import Icon from '../../../UI/Icons/Icon/Icon';
|
||||
import { GlobalState, NewNotification, Query } from '../../../../interfaces';
|
||||
import QueriesForm from './QueriesForm';
|
||||
import { deleteQuery, createNotification } from '../../../../store/actions';
|
||||
import Button from '../../../UI/Buttons/Button/Button';
|
||||
import { searchConfig } from '../../../../utility';
|
||||
|
||||
interface Props {
|
||||
customQueries: Query[];
|
||||
deleteQuery: (prefix: string) => {};
|
||||
createNotification: (notification: NewNotification) => void;
|
||||
}
|
||||
|
||||
const CustomQueries = (props: Props): JSX.Element => {
|
||||
const { customQueries, deleteQuery, createNotification } = props;
|
||||
|
||||
const [modalIsOpen, setModalIsOpen] = useState(false);
|
||||
const [editableQuery, setEditableQuery] = useState<Query | null>(null);
|
||||
|
||||
const updateHandler = (query: Query) => {
|
||||
setEditableQuery(query);
|
||||
setModalIsOpen(true);
|
||||
};
|
||||
|
||||
const deleteHandler = (query: Query) => {
|
||||
const currentProvider = searchConfig('defaultSearchProvider', 'l');
|
||||
const isCurrent = currentProvider === query.prefix;
|
||||
|
||||
if (isCurrent) {
|
||||
createNotification({
|
||||
title: 'Error',
|
||||
message: 'Cannot delete active provider',
|
||||
});
|
||||
} else if (
|
||||
window.confirm(`Are you sure you want to delete this provider?`)
|
||||
) {
|
||||
deleteQuery(query.prefix);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Modal
|
||||
isOpen={modalIsOpen}
|
||||
setIsOpen={() => setModalIsOpen(!modalIsOpen)}
|
||||
>
|
||||
{editableQuery ? (
|
||||
<QueriesForm
|
||||
modalHandler={() => setModalIsOpen(!modalIsOpen)}
|
||||
query={editableQuery}
|
||||
/>
|
||||
) : (
|
||||
<QueriesForm modalHandler={() => setModalIsOpen(!modalIsOpen)} />
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
<div>
|
||||
<div className={classes.QueriesGrid}>
|
||||
{customQueries.length > 0 && (
|
||||
<Fragment>
|
||||
<span>Name</span>
|
||||
<span>Prefix</span>
|
||||
<span>Actions</span>
|
||||
|
||||
<div className={classes.Separator}></div>
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
{customQueries.map((q: Query, idx) => (
|
||||
<Fragment key={idx}>
|
||||
<span>{q.name}</span>
|
||||
<span>{q.prefix}</span>
|
||||
<span className={classes.ActionIcons}>
|
||||
<span onClick={() => updateHandler(q)}>
|
||||
<Icon icon="mdiPencil" />
|
||||
</span>
|
||||
<span onClick={() => deleteHandler(q)}>
|
||||
<Icon icon="mdiDelete" />
|
||||
</span>
|
||||
</span>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
click={() => {
|
||||
setEditableQuery(null);
|
||||
setModalIsOpen(true);
|
||||
}}
|
||||
>
|
||||
Add new search provider
|
||||
</Button>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: GlobalState) => {
|
||||
return {
|
||||
customQueries: state.config.customQueries,
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, { deleteQuery, createNotification })(
|
||||
CustomQueries
|
||||
);
|
||||
@@ -0,0 +1,109 @@
|
||||
import { ChangeEvent, FormEvent, useState, useEffect } from 'react';
|
||||
import { Query } from '../../../../interfaces';
|
||||
import Button from '../../../UI/Buttons/Button/Button';
|
||||
import InputGroup from '../../../UI/Forms/InputGroup/InputGroup';
|
||||
import ModalForm from '../../../UI/Forms/ModalForm/ModalForm';
|
||||
import { connect } from 'react-redux';
|
||||
import { addQuery, updateQuery } from '../../../../store/actions';
|
||||
|
||||
interface Props {
|
||||
modalHandler: () => void;
|
||||
addQuery: (query: Query) => {};
|
||||
updateQuery: (query: Query, Oldprefix: string) => {};
|
||||
query?: Query;
|
||||
}
|
||||
|
||||
const QueriesForm = (props: Props): JSX.Element => {
|
||||
const { modalHandler, addQuery, updateQuery, query } = props;
|
||||
|
||||
const [formData, setFormData] = useState<Query>({
|
||||
name: '',
|
||||
prefix: '',
|
||||
template: '',
|
||||
});
|
||||
|
||||
const inputChangeHandler = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
setFormData({
|
||||
...formData,
|
||||
[name]: value,
|
||||
});
|
||||
};
|
||||
|
||||
const formHandler = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (query) {
|
||||
updateQuery(formData, query.prefix);
|
||||
} else {
|
||||
addQuery(formData);
|
||||
}
|
||||
|
||||
// close modal
|
||||
modalHandler();
|
||||
|
||||
// clear form
|
||||
setFormData({
|
||||
name: '',
|
||||
prefix: '',
|
||||
template: '',
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (query) {
|
||||
setFormData(query);
|
||||
} else {
|
||||
setFormData({
|
||||
name: '',
|
||||
prefix: '',
|
||||
template: '',
|
||||
});
|
||||
}
|
||||
}, [query]);
|
||||
|
||||
return (
|
||||
<ModalForm modalHandler={modalHandler} formHandler={formHandler}>
|
||||
<InputGroup>
|
||||
<label htmlFor="name">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder="Google"
|
||||
required
|
||||
value={formData.name}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
/>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="name">Prefix</label>
|
||||
<input
|
||||
type="text"
|
||||
name="prefix"
|
||||
id="prefix"
|
||||
placeholder="g"
|
||||
required
|
||||
value={formData.prefix}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
/>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="name">Query Template</label>
|
||||
<input
|
||||
type="text"
|
||||
name="template"
|
||||
id="template"
|
||||
placeholder="https://www.google.com/search?q="
|
||||
required
|
||||
value={formData.template}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
/>
|
||||
</InputGroup>
|
||||
{query ? <Button>Update provider</Button> : <Button>Add provider</Button>}
|
||||
</ModalForm>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(null, { addQuery, updateQuery })(QueriesForm);
|
||||
154
client/src/components/Settings/SearchSettings/SearchSettings.tsx
Normal file
154
client/src/components/Settings/SearchSettings/SearchSettings.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
// React
|
||||
import { useState, useEffect, FormEvent, ChangeEvent, Fragment } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
// State
|
||||
import { createNotification, updateConfig } from '../../../store/actions';
|
||||
|
||||
// Typescript
|
||||
import {
|
||||
GlobalState,
|
||||
NewNotification,
|
||||
Query,
|
||||
SearchForm,
|
||||
} from '../../../interfaces';
|
||||
|
||||
// Components
|
||||
import CustomQueries from './CustomQueries/CustomQueries';
|
||||
|
||||
// UI
|
||||
import Button from '../../UI/Buttons/Button/Button';
|
||||
import SettingsHeadline from '../../UI/Headlines/SettingsHeadline/SettingsHeadline';
|
||||
import InputGroup from '../../UI/Forms/InputGroup/InputGroup';
|
||||
|
||||
// Utils
|
||||
import { searchConfig } from '../../../utility';
|
||||
|
||||
// Data
|
||||
import { queries } from '../../../utility/searchQueries.json';
|
||||
|
||||
interface Props {
|
||||
createNotification: (notification: NewNotification) => void;
|
||||
updateConfig: (formData: SearchForm) => void;
|
||||
loading: boolean;
|
||||
customQueries: Query[];
|
||||
}
|
||||
|
||||
const SearchSettings = (props: Props): JSX.Element => {
|
||||
// Initial state
|
||||
const [formData, setFormData] = useState<SearchForm>({
|
||||
hideSearch: 0,
|
||||
defaultSearchProvider: 'l',
|
||||
searchSameTab: 0,
|
||||
});
|
||||
|
||||
// Get config
|
||||
useEffect(() => {
|
||||
setFormData({
|
||||
hideSearch: searchConfig('hideSearch', 0),
|
||||
defaultSearchProvider: searchConfig('defaultSearchProvider', 'd'),
|
||||
searchSameTab: searchConfig('searchSameTab', 0),
|
||||
});
|
||||
}, [props.loading]);
|
||||
|
||||
// Form handler
|
||||
const formSubmitHandler = async (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Save settings
|
||||
await props.updateConfig(formData);
|
||||
};
|
||||
|
||||
// Input handler
|
||||
const inputChangeHandler = (
|
||||
e: ChangeEvent<HTMLInputElement | HTMLSelectElement>,
|
||||
isNumber?: boolean
|
||||
) => {
|
||||
let value: string | number = e.target.value;
|
||||
|
||||
if (isNumber) {
|
||||
value = parseFloat(value);
|
||||
}
|
||||
|
||||
setFormData({
|
||||
...formData,
|
||||
[e.target.name]: value,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{/* GENERAL SETTINGS */}
|
||||
<form
|
||||
onSubmit={(e) => formSubmitHandler(e)}
|
||||
style={{ marginBottom: '30px' }}
|
||||
>
|
||||
<SettingsHeadline text="General" />
|
||||
<InputGroup>
|
||||
<label htmlFor="defaultSearchProvider">Default Search Provider</label>
|
||||
<select
|
||||
id="defaultSearchProvider"
|
||||
name="defaultSearchProvider"
|
||||
value={formData.defaultSearchProvider}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
>
|
||||
{[...queries, ...props.customQueries].map((query: Query, idx) => {
|
||||
const isCustom = idx >= queries.length;
|
||||
|
||||
return (
|
||||
<option key={idx} value={query.prefix}>
|
||||
{isCustom && '+'} {query.name}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="searchSameTab">
|
||||
Open search results in the same tab
|
||||
</label>
|
||||
<select
|
||||
id="searchSameTab"
|
||||
name="searchSameTab"
|
||||
value={formData.searchSameTab}
|
||||
onChange={(e) => inputChangeHandler(e, true)}
|
||||
>
|
||||
<option value={1}>True</option>
|
||||
<option value={0}>False</option>
|
||||
</select>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="hideSearch">Hide search bar</label>
|
||||
<select
|
||||
id="hideSearch"
|
||||
name="hideSearch"
|
||||
value={formData.hideSearch}
|
||||
onChange={(e) => inputChangeHandler(e, true)}
|
||||
>
|
||||
<option value={1}>True</option>
|
||||
<option value={0}>False</option>
|
||||
</select>
|
||||
</InputGroup>
|
||||
<Button>Save changes</Button>
|
||||
</form>
|
||||
|
||||
{/* CUSTOM QUERIES */}
|
||||
<SettingsHeadline text="Custom search providers" />
|
||||
<CustomQueries />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: GlobalState) => {
|
||||
return {
|
||||
loading: state.config.loading,
|
||||
customQueries: state.config.customQueries,
|
||||
};
|
||||
};
|
||||
|
||||
const actions = {
|
||||
createNotification,
|
||||
updateConfig,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, actions)(SearchSettings);
|
||||
@@ -1,73 +1,61 @@
|
||||
//
|
||||
import { NavLink, Link, Switch, Route } from 'react-router-dom';
|
||||
|
||||
// Typescript
|
||||
import { Route as SettingsRoute } from '../../interfaces';
|
||||
|
||||
// CSS
|
||||
import classes from './Settings.module.css';
|
||||
|
||||
import { Container } from '../UI/Layout/Layout';
|
||||
import Headline from '../UI/Headlines/Headline/Headline';
|
||||
|
||||
// Components
|
||||
import Themer from '../Themer/Themer';
|
||||
import WeatherSettings from './WeatherSettings/WeatherSettings';
|
||||
import OtherSettings from './OtherSettings/OtherSettings';
|
||||
import AppDetails from './AppDetails/AppDetails';
|
||||
import StyleSettings from './StyleSettings/StyleSettings';
|
||||
import SearchSettings from './SearchSettings/SearchSettings';
|
||||
|
||||
// UI
|
||||
import { Container } from '../UI/Layout/Layout';
|
||||
import Headline from '../UI/Headlines/Headline/Headline';
|
||||
|
||||
// Data
|
||||
import { routes } from './settings.json';
|
||||
|
||||
const Settings = (): JSX.Element => {
|
||||
return (
|
||||
<Container>
|
||||
<Headline
|
||||
title='Settings'
|
||||
subtitle={<Link to='/'>Go back</Link>}
|
||||
/>
|
||||
<Headline title="Settings" subtitle={<Link to="/">Go back</Link>} />
|
||||
<div className={classes.Settings}>
|
||||
{/* NAVIGATION MENU */}
|
||||
<nav className={classes.SettingsNav}>
|
||||
<NavLink
|
||||
className={classes.SettingsNavLink}
|
||||
activeClassName={classes.SettingsNavLinkActive}
|
||||
exact
|
||||
to='/settings'>
|
||||
Theme
|
||||
</NavLink>
|
||||
<NavLink
|
||||
className={classes.SettingsNavLink}
|
||||
activeClassName={classes.SettingsNavLinkActive}
|
||||
exact
|
||||
to='/settings/weather'>
|
||||
Weather
|
||||
</NavLink>
|
||||
<NavLink
|
||||
className={classes.SettingsNavLink}
|
||||
activeClassName={classes.SettingsNavLinkActive}
|
||||
exact
|
||||
to='/settings/other'>
|
||||
Other
|
||||
</NavLink>
|
||||
<NavLink
|
||||
className={classes.SettingsNavLink}
|
||||
activeClassName={classes.SettingsNavLinkActive}
|
||||
exact
|
||||
to='/settings/css'>
|
||||
CSS
|
||||
</NavLink>
|
||||
<NavLink
|
||||
className={classes.SettingsNavLink}
|
||||
activeClassName={classes.SettingsNavLinkActive}
|
||||
exact
|
||||
to='/settings/app'>
|
||||
App
|
||||
</NavLink>
|
||||
{routes.map(({ name, dest }: SettingsRoute, idx) => (
|
||||
<NavLink
|
||||
className={classes.SettingsNavLink}
|
||||
activeClassName={classes.SettingsNavLinkActive}
|
||||
exact
|
||||
to={dest}
|
||||
key={idx}
|
||||
>
|
||||
{name}
|
||||
</NavLink>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* ROUTES */}
|
||||
<section className={classes.SettingsContent}>
|
||||
<Switch>
|
||||
<Route exact path='/settings' component={Themer} />
|
||||
<Route path='/settings/weather' component={WeatherSettings} />
|
||||
<Route path='/settings/other' component={OtherSettings} />
|
||||
<Route path='/settings/css' component={StyleSettings} />
|
||||
<Route path='/settings/app' component={AppDetails} />
|
||||
<Route exact path="/settings" component={Themer} />
|
||||
<Route path="/settings/weather" component={WeatherSettings} />
|
||||
<Route path="/settings/search" component={SearchSettings} />
|
||||
<Route path="/settings/other" component={OtherSettings} />
|
||||
<Route path="/settings/css" component={StyleSettings} />
|
||||
<Route path="/settings/app" component={AppDetails} />
|
||||
</Switch>
|
||||
</section>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
export default Settings;
|
||||
|
||||
28
client/src/components/Settings/settings.json
Normal file
28
client/src/components/Settings/settings.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
"name": "Theme",
|
||||
"dest": "/settings"
|
||||
},
|
||||
{
|
||||
"name": "Weather",
|
||||
"dest": "/settings/weather"
|
||||
},
|
||||
{
|
||||
"name": "Search",
|
||||
"dest": "/settings/search"
|
||||
},
|
||||
{
|
||||
"name": "Other",
|
||||
"dest": "/settings/other"
|
||||
},
|
||||
{
|
||||
"name": "CSS",
|
||||
"dest": "/settings/css"
|
||||
},
|
||||
{
|
||||
"name": "App",
|
||||
"dest": "/settings/app"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user