feat(settings): add sub-section handling for settings navigation and deep linking

This commit is contained in:
alexsparkes
2026-01-24 16:24:26 +00:00
parent 8cbb5a5c92
commit 819057ed8b
20 changed files with 170 additions and 70 deletions

View File

@@ -15,7 +15,7 @@ import NavigationCard from './sections/NavigationCard';
import { getBackgroundOptionItems } from './optionTypes';
const BackgroundOptions = memo(() => {
const BackgroundOptions = memo(({ currentSubSection, onSubSectionChange, sectionName }) => {
const [backgroundType, setBackgroundType] = useState(
localStorage.getItem('backgroundType') || 'api',
);
@@ -28,21 +28,18 @@ const BackgroundOptions = memo(() => {
const [backgroundCategoriesOG, setBackgroundCategoriesOG] = useState([]);
const [backgroundAPI, setBackgroundAPI] = useState(localStorage.getItem('backgroundAPI') || 'mue');
const [marketplaceEnabled] = useState(localStorage.getItem('photo_packs'));
const [effects, setEffects] = useState(false);
// Auto-show source section for types without effects/display settings
const shouldShowSourceByDefault = ['colour', 'random_colour', 'random_gradient'].includes(backgroundType);
const [backgroundSettingsSection, setBackgroundSettingsSection] = useState(shouldShowSourceByDefault);
const controllerRef = useRef(null);
// Auto-navigate to source section when switching to colour/random types
useEffect(() => {
if (shouldShowSourceByDefault) {
setBackgroundSettingsSection(true);
setEffects(false);
if (shouldShowSourceByDefault && currentSubSection !== 'source') {
onSubSectionChange('source', sectionName);
}
}, [shouldShowSourceByDefault]);
}, [shouldShowSourceByDefault, currentSubSection, onSubSectionChange, sectionName]);
const getBackgroundCategories = useCallback(async () => {
const data = await (
@@ -139,26 +136,26 @@ const BackgroundOptions = memo(() => {
const showEffects = backgroundType === 'api' || backgroundType === 'custom' || marketplaceEnabled;
const getHeader = () => {
if (effects) {
if (currentSubSection === 'effects') {
return (
<Header
title={variables.getMessage('modals.main.settings.sections.background.title')}
secondaryTitle={variables.getMessage(
'modals.main.settings.sections.background.effects.title',
)}
goBack={() => setEffects(false)}
goBack={() => onSubSectionChange(null, sectionName)}
/>
);
}
if (backgroundSettingsSection) {
if (currentSubSection === 'source') {
return (
<Header
title={variables.getMessage('modals.main.settings.sections.background.title')}
secondaryTitle={variables.getMessage(
'modals.main.settings.sections.background.source.title',
)}
goBack={() => setBackgroundSettingsSection(false)}
goBack={() => onSubSectionChange(null, sectionName)}
/>
);
}
@@ -177,7 +174,7 @@ const BackgroundOptions = memo(() => {
<>
{getHeader()}
{!backgroundSettingsSection && !effects && (
{!currentSubSection && (
<>
<NavigationCard
icon={MdSource}
@@ -185,7 +182,7 @@ const BackgroundOptions = memo(() => {
subtitle={variables.getMessage(
'modals.main.settings.sections.background.source.subtitle',
)}
onClick={() => setBackgroundSettingsSection(true)}
onClick={() => onSubSectionChange('source', sectionName)}
action={
<Dropdown
label={variables.getMessage('modals.main.settings.sections.background.type.title')}
@@ -210,17 +207,17 @@ const BackgroundOptions = memo(() => {
subtitle={variables.getMessage(
'modals.main.settings.sections.background.effects.subtitle',
)}
onClick={() => setEffects(true)}
onClick={() => onSubSectionChange('effects', sectionName)}
/>
)}
</>
)}
{!backgroundSettingsSection && !effects && showEffects && (
{!currentSubSection && showEffects && (
<DisplaySettings usingImage={usingImage} />
)}
{backgroundSettingsSection && (
{currentSubSection === 'source' && (
<>
<SourceSection
backgroundType={backgroundType}
@@ -235,7 +232,7 @@ const BackgroundOptions = memo(() => {
</>
)}
{showEffects && effects && (
{showEffects && currentSubSection === 'effects' && (
<EffectsSettings
backgroundFilter={backgroundFilter}
onFilterChange={(value) => setBackgroundFilter(value)}

View File

@@ -18,11 +18,10 @@ import defaultEvents from '../events.json';
import { MdEventNote, MdAdd, MdCancel, MdRefresh } from 'react-icons/md';
const GreetingOptions = () => {
const GreetingOptions = ({ currentSubSection, onSubSectionChange, sectionName }) => {
const [customEvents, setCustomEvents] = useState(
JSON.parse(localStorage.getItem('customEvents')) || [],
);
const [events, setEvents] = useState(false);
const [birthday, setBirthday] = useState(() => {
const stored = localStorage.getItem('birthday');
@@ -266,13 +265,15 @@ const GreetingOptions = () => {
);
};
const isEventsSection = currentSubSection === 'events';
let header;
if (events) {
if (isEventsSection) {
header = (
<Header
title={variables.getMessage(`${GREETING_SECTION}.title`)}
secondaryTitle="Events"
goBack={() => setEvents(false)}
secondaryTitle={variables.getMessage(`${GREETING_SECTION}.events.title`)}
goBack={() => onSubSectionChange(null, sectionName)}
report={false}
/>
);
@@ -292,7 +293,7 @@ const GreetingOptions = () => {
return (
<>
{header}
{events ? (
{isEventsSection ? (
<>
<Row>
<Content
@@ -324,7 +325,7 @@ const GreetingOptions = () => {
<Section
title={variables.getMessage(`${GREETING_SECTION}.events`)}
subtitle={variables.getMessage(`${GREETING_SECTION}.events_description`)}
onClick={() => setEvents(true)}
onClick={() => onSubSectionChange('events', sectionName)}
icon={<MdEventNote />}
/>
</PreferencesWrapper>

View File

@@ -18,9 +18,8 @@ import { Header, Section, Row, Content, Action } from 'components/Layout/Setting
import time_zones from 'features/time/timezones.json';
function AdvancedOptions() {
function AdvancedOptions({ currentSubSection, onSubSectionChange, sectionName }) {
const [resetModal, setResetModal] = useState(false);
const [data, setData] = useState(false);
const ADVANCED_SECTION = 'modals.main.settings.sections.advanced';
const Data = () => {
@@ -76,13 +75,15 @@ function AdvancedOptions() {
);
};
const isDataSection = currentSubSection === 'data';
let header;
if (data) {
if (isDataSection) {
header = (
<Header
title={variables.getMessage(`${ADVANCED_SECTION}.title`)}
secondaryTitle={variables.getMessage(`${ADVANCED_SECTION}.data`)}
goBack={() => setData(false)}
goBack={() => onSubSectionChange(null, sectionName)}
report={false}
/>
);
@@ -93,7 +94,7 @@ function AdvancedOptions() {
return (
<>
{header}
{data ? (
{isDataSection ? (
<>
<Data />
<Modal
@@ -112,7 +113,7 @@ function AdvancedOptions() {
<Section
title={variables.getMessage(`${ADVANCED_SECTION}.data`)}
subtitle={variables.getMessage(`${ADVANCED_SECTION}.data_subtitle`)}
onClick={() => setData(true)}
onClick={() => onSubSectionChange('data', sectionName)}
icon={<MdDataUsage />}
/>
<Row>

View File

@@ -9,8 +9,7 @@ import { MdAccessibility } from 'react-icons/md';
import values from 'utils/data/slider_values.json';
function AppearanceOptions() {
const [accessibility, setAccessibility] = useState(false);
function AppearanceOptions({ currentSubSection, onSubSectionChange, sectionName }) {
const ThemeSelection = () => {
return (
@@ -239,15 +238,17 @@ function AppearanceOptions() {
);
};
const isAccessibilitySection = currentSubSection === 'accessibility';
let header;
if (accessibility) {
if (isAccessibilitySection) {
header = (
<Header
title={variables.getMessage('modals.main.settings.sections.appearance.title')}
secondaryTitle={variables.getMessage(
'modals.main.settings.sections.appearance.accessibility.title',
)}
goBack={() => setAccessibility(false)}
goBack={() => onSubSectionChange(null, sectionName)}
report={false}
/>
);
@@ -262,7 +263,7 @@ function AppearanceOptions() {
return (
<>
{header}
{accessibility ? (
{isAccessibilitySection ? (
<AccessibilityOptions />
) : (
<>
@@ -274,7 +275,7 @@ function AppearanceOptions() {
'modals.main.settings.sections.appearance.accessibility.description',
)}
icon={<MdAccessibility />}
onClick={() => setAccessibility(true)}
onClick={() => onSubSectionChange('accessibility', sectionName)}
/>
<ThemeSelection />
<FontOptions />

View File

@@ -95,13 +95,19 @@ function Settings(props) {
current="settings"
currentTab={props.currentTab}
onSectionChange={props.onSectionChange}
onSubSectionChange={props.onSubSectionChange}
currentSubSection={props.currentSubSection}
deepLinkData={props.deepLinkData}
navigationTrigger={props.navigationTrigger}
sections={sections}
>
{sections.map(({ label, name, component: Component }) => (
<div key={name} label={variables.getMessage(label)} name={name}>
<Component />
<Component
currentSubSection={props.currentSubSection}
onSubSectionChange={props.onSubSectionChange}
sectionName={name}
/>
</div>
))}
</Tabs>

View File

@@ -14,7 +14,7 @@ import {
import { Checkbox, Dropdown } from 'components/Form/Settings';
import { Button } from 'components/Elements';
const QuoteOptions = () => {
const QuoteOptions = ({ currentSubSection, onSubSectionChange, sectionName }) => {
const getCustom = () => {
let data = JSON.parse(localStorage.getItem('customQuote'));
if (data === null) {
@@ -25,7 +25,6 @@ const QuoteOptions = () => {
const [quoteType, setQuoteType] = useState(localStorage.getItem('quoteType') || 'api');
const [customQuote, setCustomQuote] = useState(getCustom());
const [sourceSection, setSourceSection] = useState(false);
const handleCustomQuote = (e, text, index, type) => {
const result = text === true ? e.target.value : e.target.result;
@@ -134,8 +133,10 @@ const QuoteOptions = () => {
);
};
const isSourceSection = currentSubSection === 'source';
let customSettings;
if (quoteType === 'custom' && sourceSection === true) {
if (quoteType === 'custom' && isSourceSection) {
customSettings = (
<>
<Row final={true}>
@@ -221,13 +222,13 @@ const QuoteOptions = () => {
return (
<>
{sourceSection ? (
{isSourceSection ? (
<Header
title={variables.getMessage(`${QUOTE_SECTION}.title`)}
secondaryTitle={variables.getMessage(
'modals.main.settings.sections.background.source.title',
)}
goBack={() => setSourceSection(false)}
goBack={() => onSubSectionChange(null, sectionName)}
report={false}
/>
) : (
@@ -240,7 +241,7 @@ const QuoteOptions = () => {
visibilityToggle={true}
/>
)}
{sourceSection && (
{isSourceSection && (
<Row final={true}>
<Content
title={variables.getMessage('modals.main.settings.sections.background.source.title')}
@@ -251,7 +252,7 @@ const QuoteOptions = () => {
</Action>
</Row>
)}
{!sourceSection && (
{!isSourceSection && (
<PreferencesWrapper
setting="quote"
zoomSetting="zoomQuote"
@@ -262,7 +263,7 @@ const QuoteOptions = () => {
icon={<MdSource />}
title={variables.getMessage('modals.main.settings.sections.background.source.title')}
subtitle={variables.getMessage(`${QUOTE_SECTION}.source_subtitle`)}
onClick={() => setSourceSection(true)}
onClick={() => onSubSectionChange('source', sectionName)}
>
<SourceDropdown />
</Section>