Skip to content

Commit d58184b

Browse files
committed
feat: Generic purpose LeftSidebar component
feat: Add BrowsePageDisplayList, LeftSidebar and StateWrapper to ext components feat: Add useLocation hook for ext fix: Use react-router-dom typings for useLocation and useNavigate feat: Add StateWrapper around Activity, to prevent preloading of components but still keep state when hidden. Prevents perf cost of never seen Activity components feat: Add typings for TaskState and LogsState for ext RootState
1 parent 47e2f79 commit d58184b

File tree

12 files changed

+193
-60
lines changed

12 files changed

+193
-60
lines changed

src/back/extensions/ApiImplementation.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,15 @@ import { BackOut } from '@shared/back/types';
2626
import { CURATIONS_FOLDER_WORKING } from '@shared/constants';
2727
import { CurationMeta } from '@shared/curate/types';
2828
import { getContentFolderByKey } from '@shared/curate/util';
29-
import { Task } from '@shared/interfaces';
3029
import { langTemplate } from '@shared/lang';
3130
import { PreferencesFile } from '@shared/preferences/PreferencesFile';
3231
import { overwritePreferenceData } from '@shared/preferences/util';
3332
import { formatString } from '@shared/utils/StringFormatter';
3433
import * as flashpoint from 'flashpoint-launcher';
35-
import { CurationTemplate, Game, IExtensionManifest } from 'flashpoint-launcher';
36-
import * as fs from 'node:fs';
34+
import { CurationTemplate, Game, IExtensionManifest, Task } from 'flashpoint-launcher';
3735
import * as fsExtra from 'fs-extra';
3836
import { extractFull } from 'node-7z';
37+
import * as fs from 'node:fs';
3938
import * as path from 'node:path';
4039
import * as stream from 'stream';
4140
import uuid from 'uuid';

src/renderer/components/ActivityRoutes.tsx

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Paths } from '@shared/Paths';
2-
import { CustomRoute } from 'flashpoint-launcher-renderer';
3-
import { Activity, ReactNode } from 'react';
2+
import { CustomRoute, StateWrapperProps } from 'flashpoint-launcher-renderer';
3+
import { Activity, ReactNode, useState } from 'react';
44
import { useLocation } from 'react-router-dom';
55
import { DynamicComponent } from './DynamicComponent';
66
import { CuratePage } from './pages/CuratePage';
@@ -58,7 +58,25 @@ function ActivityRoute({ path, children, exact }: ActivityRouteProps) {
5858
pathname.startsWith(path);
5959

6060
return (
61-
<Activity mode={showChildren ? 'visible' : 'hidden'}>
61+
<StateWrapper show={showChildren}>
62+
{children}
63+
</StateWrapper>
64+
);
65+
}
66+
67+
export function StateWrapper({ show, children }: StateWrapperProps) {
68+
const [shownOnce, setShownOnce] = useState(false);
69+
70+
if (!shownOnce && !show) {
71+
return <></>;
72+
}
73+
74+
if (!shownOnce && show) {
75+
setShownOnce(true);
76+
}
77+
78+
return (
79+
<Activity mode={show ? 'visible' : 'hidden'}>
6280
{children}
6381
</Activity>
6482
);
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { LeftSidebarItem, LeftSidebarProps } from 'flashpoint-launcher-renderer';
2+
import { List, RowComponentProps } from 'react-window';
3+
import { InputField } from './InputField';
4+
import { SizeProvider } from './SizeProvider';
5+
6+
export function LeftSidebar({ items, selected, onSelect, rowHeight }: LeftSidebarProps) {
7+
return (
8+
<div className='leftsidebar'>
9+
<SizeProvider height={rowHeight}>
10+
<List
11+
rowComponent={LeftSidebarRow}
12+
rowCount={items.length}
13+
rowProps={{
14+
items,
15+
selected,
16+
onSelect
17+
}}
18+
rowHeight={rowHeight}
19+
overscanCount={10}/>
20+
</SizeProvider>
21+
</div>
22+
);
23+
}
24+
25+
type LeftSidebarRowProps = {
26+
items: LeftSidebarItem[];
27+
selected?: string;
28+
onSelect?: (key: string) => void;
29+
}
30+
31+
function LeftSidebarRow({ items, selected, onSelect, index, style }: RowComponentProps<LeftSidebarRowProps>) {
32+
const { key, title, icon } = items[index];
33+
let className = 'leftsidebar-item';
34+
if (key === selected) { className += ' leftsidebar-item--selected'; }
35+
let titleClassName = 'leftsidebar-item-title';
36+
if (key === selected) { titleClassName += ' leftsidebar-item-title--selected'; }
37+
38+
return (
39+
<>
40+
<div
41+
className={className}
42+
style={style}>
43+
{/* Drag Overlay */}
44+
<div className='playlist-list-item__drag-overlay' />
45+
{/* Head */}
46+
<div
47+
className='playlist-list-item__head'
48+
onClick={() => onSelect && onSelect(key)}>
49+
{/* Icon */}
50+
{icon}
51+
{/* Title */}
52+
<div className='playlist-list-item__title simple-center'>
53+
<InputField
54+
text={title}
55+
className={titleClassName}/>
56+
</div>
57+
</div>
58+
</div>
59+
</>
60+
);
61+
}

src/renderer/components/app.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
3232
import { toast, ToastContainer } from 'react-toastify';
3333
import { axios } from '../Util';
3434
import { LangContext } from '../util/lang';
35-
import { ActivityRoutes } from './ActivityRoutes';
36-
import { BrowsePageDisplayGrid } from './BrowsePageDisplay';
35+
import { ActivityRoutes, StateWrapper } from './ActivityRoutes';
36+
import { BrowsePageDisplayGrid, BrowsePageDisplayList } from './BrowsePageDisplay';
3737
import { Dialog } from './Dialog';
3838
import { GameComponentDropdownSelectField, GameComponentInputField } from './DisplayComponent';
3939
import { DynamicComponent } from './DynamicComponent';
@@ -44,6 +44,7 @@ import { Footer } from './Footer';
4444
import { SortableColumn } from './GameListHeader';
4545
import { Header } from './Header';
4646
import { HomePageBox } from './HomePageBox';
47+
import { LeftSidebar } from './LeftSidebar';
4748
import { AboutPage } from './pages/AboutPage';
4849
import { BrowsePage } from './pages/BrowsePage';
4950
import { ConfigPage } from './pages/ConfigPage';
@@ -439,10 +440,14 @@ function addExtIntercepts() {
439440
SizeProvider,
440441
RandomGames,
441442
BrowsePageDisplayGrid,
443+
BrowsePageDisplayList,
444+
LeftSidebar,
445+
StateWrapper,
442446
} satisfies typeof import('flashpoint-launcher-renderer-ext/components');
443447

444448
(window as any)['flashpoint-launcher-renderer-ext/hooks'] = {
445449
useNavigate,
450+
useLocation,
446451
useAppDispatch,
447452
useAppSelector,
448453
useContextMenu,

src/renderer/components/pages/CuratePage.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ import { axios, getCurationPostURL, getPlatformIconURL, openUrlInWindow } from '
88
import { BackIn } from '@shared/back/types';
99
import { EditCurationMeta } from '@shared/curate/OLD_types';
1010
import { eventResponseDebouncerFactory } from '@shared/eventResponseDebouncer';
11-
import { Task } from '@shared/interfaces';
1211
import { getFileServerURL } from '@shared/Util';
1312
import { formatString } from '@shared/utils/StringFormatter';
1413
import { uuid } from '@shared/utils/uuid';
15-
import { AppPreferencesData, CurationState, GameLaunchOverride, TagSuggestion } from 'flashpoint-launcher';
14+
import { AppPreferencesData, CurationState, GameLaunchOverride, TagSuggestion, Task } from 'flashpoint-launcher';
1615
import * as path from 'node:path';
1716
import * as React from 'react';
1817
import { useShortcut } from 'react-keybind';

src/renderer/containers/withLogs.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useAppSelector } from '@renderer/hooks/useAppSelector';
2-
import { logsActions, LogsState } from '@renderer/store/logs/slice';
2+
import { logsActions } from '@renderer/store/logs/slice';
33
import { Subtract } from '@shared/interfaces';
4+
import { LogsState } from 'flashpoint-launcher-renderer';
45
import { useDispatch } from 'react-redux';
56
import { bindActionCreators, Dispatch } from 'redux';
67

src/renderer/store/logs/slice.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
22
import { ILogEntry } from 'flashpoint-launcher';
3-
4-
export type LogsState = {
5-
offset: number;
6-
longestSource: number;
7-
entries: ILogEntry[];
8-
}
3+
import { LogsState } from 'flashpoint-launcher-renderer';
94

105
const initialState: LogsState = {
116
offset: 0,

src/renderer/store/tasks/slice.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
import { Task } from '@shared/interfaces';
21
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
3-
4-
type TaskState = {
5-
tasks: Task[];
6-
taskBarOpen: boolean;
7-
}
2+
import { Task } from 'flashpoint-launcher';
3+
import { TaskState } from 'flashpoint-launcher-renderer';
84

95
const initialState: TaskState = {
106
tasks: [],

src/shared/interfaces.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,3 @@ export type SuggestionProps = (
146146
export type GamePropSuggestions = {
147147
[P in SuggestionProps]: string[];
148148
}
149-
150-
export type Task = {
151-
id: string;
152-
name: string;
153-
status: string;
154-
finished: boolean;
155-
error?: string;
156-
progress?: number;
157-
}

static/window/styles/core.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,6 +2179,12 @@ body {
21792179
margin: 0 auto;
21802180
}
21812181

2182+
/* --- Left Sidebar --- */
2183+
.leftsidebar {
2184+
height: 100%;
2185+
display: flex;
2186+
flex-direction: column;
2187+
}
21822188

21832189
/* ------ Playlist ------ */
21842190
.playlist-list__message {

0 commit comments

Comments
 (0)