Skip to content

Commit

Permalink
feat: move to @tanstack/router's file-based routing
Browse files Browse the repository at this point in the history
  • Loading branch information
Harjot1Singh committed Aug 31, 2024
1 parent 5cabf99 commit a6b30d4
Show file tree
Hide file tree
Showing 85 changed files with 1,540 additions and 1,254 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ dist/
build/
.nyc_output/
coverage/
!.vscode/extensions.json
!.vscode/extensions.json
6 changes: 5 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [x] Get clear on paths
- [x] ESLint root package dependency usage
- [x] Move themes to `packages/themes`
- [ ] Separated server vs client settings + interface (new events?)

## Backend

Expand All @@ -35,8 +36,11 @@
- [x] Move off CRA to Vite
- [ ] Separate out line jump into per file
- [x] Convert to TS
- [ ] Refactor routing to be centralised (per feature)
- [ ] Sort out `react-hotkeys` usage (error regarding no `parentId`)
- [ ] Use new events from BE
- [ ] Refactor into concept of `content`
- [ ] Render navigator's bar extra icons in controller
- [ ] Better settings management via hooks

## Electron

Expand Down
8 changes: 8 additions & 0 deletions apps/frontend/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,12 @@ module.exports = {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
overrides: [ {
// Targeting route files
files: [ '**/*/app/**/*.ts?(x)' ],
rules: {
// Referencing the exported route leads to a use before define in components, but it's fine
'@typescript-eslint/no-use-before-define': 'off',
},
} ],
}
10 changes: 6 additions & 4 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"@mui/material": "^5.16.6",
"@presenter/themes": "*",
"@sentry/browser": "^6.19.7",
"@tanstack/react-router": "^1.49.2",
"@tanstack/router-zod-adapter": "^1.51.6",
"classnames": "^2.3.1",
"copy-to-clipboard": "^3.3.1",
"detect-browser": "^5.3.0",
Expand All @@ -31,21 +33,21 @@
"lodash": "^4.17.21",
"memoizee": "^0.4.17",
"notistack": "^3.0.1",
"qs": "^6.13.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hotkeys": "^2.0.0",
"react-idle-timer": "^5.7.2",
"react-router-dom": "^6.26.0",
"react-transition-group": "^4.4.5",
"reconnecting-websocket": "^4.4.0",
"scroll-into-view": "^1.16.0"
"scroll-into-view": "^1.16.0",
"zod": "^3.8.2-alpha.6"
},
"devDependencies": {
"@presenter/contract": "*",
"@tanstack/router-devtools": "^1.49.2",
"@tanstack/router-plugin": "^1.49.3",
"@types/lodash": "^4.17.7",
"@types/memoizee": "^0.4.11",
"@types/qs": "^6.9.15",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/scroll-into-view": "^1.16.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import url('./fonts/noto-sans/index.css');
@import url('./fonts/OpenGurbaniAkhar/index.css');
@import url('./fonts/OpenAnmolUni/index.css');
@import url('../fonts/noto-sans/index.css');
@import url('../fonts/OpenGurbaniAkhar/index.css');
@import url('../fonts/OpenAnmolUni/index.css');
@import url('@fontsource/roboto');

/* Shared CSS constants */
Expand Down
74 changes: 29 additions & 45 deletions apps/frontend/src/App.tsx → apps/frontend/src/app/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import './App.css'
import './__root.css'

import { RecommendedSources, Shabad, Writer } from '@presenter/contract'
import { createRootRoute, Navigate, Outlet } from '@tanstack/react-router'
import classNames from 'classnames'
import { SnackbarProvider } from 'notistack'
import { ElementType, lazy, PureComponent, ReactNode, Suspense } from 'react'
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'
import { PureComponent, Suspense } from 'react'

import Loader from '~/components/Loader'
import Overlay from '~/features/overlay'
import { BACKEND_URL, isDesktop, isMobile, isTablet, OVERLAY_URL, PRESENTER_URL, SCREEN_READER_URL, SETTINGS_URL } from '~/helpers/consts'
import { API_URL, isDesktop, isMobile, isTablet } from '~/helpers/consts'
import {
BookmarksContext,
ContentContext,
Expand All @@ -22,20 +21,9 @@ import { DEFAULT_OPTIONS } from '~/helpers/options'
import { merge } from '~/helpers/utils'
import controller from '~/services/controller'

const ScreenReader = lazy( () => import( '~/features/screen-reader' ) )
const Presenter = lazy( () => import( '~/features/presenter' ) )
const Settings = lazy( () => import( '~/features/settings' ) )

const loadSettings = () => merge( { local: controller.readSettings() }, DEFAULT_OPTIONS )

class App extends PureComponent {
components = [
[ Overlay, OVERLAY_URL ],
[ ScreenReader, SCREEN_READER_URL ],
[ Settings, SETTINGS_URL ],
[ Presenter, PRESENTER_URL ],
] as const

state = {
connected: false,
connectedAt: null,
Expand Down Expand Up @@ -72,7 +60,7 @@ class App extends PureComponent {
controller.on( 'settings', this.onSettings )

// Get recommended sources and set as settings, if there are none
void fetch( `${BACKEND_URL}/sources` )
void fetch( `${API_URL}/sources` )
.then( ( res ) => res.json() )
.then( ( { recommendedSources }: { recommendedSources: RecommendedSources['recommendedSources'] } ) => {
//* Update default options and settings with fetched recommended sources
Expand All @@ -82,7 +70,7 @@ class App extends PureComponent {
} )

// Get writers
void fetch( `${BACKEND_URL}/writers` )
void fetch( `${API_URL}/writers` )
.then( ( res ) => res.json() )
.then( ( { writers }: { writers: Writer[] } ) => this.setState( { writers } ) )
}
Expand Down Expand Up @@ -172,37 +160,33 @@ class App extends PureComponent {
settings,
} = this.state

// Generate a context wrapper function
const withContexts = ( [
[ StatusContext.Provider, { connected, connectedAt, status } ],
[ SettingsContext.Provider, settings ],
[ HistoryContext.Provider, { viewedLines, transitionHistory, latestLines } ],
[ BookmarksContext.Provider, banis ],
[ WritersContext.Provider, writers ],
[ RecommendedSourcesContext.Provider, recommendedSources ],
[ ContentContext.Provider, { bani, shabad, lineId, mainLineId, nextLineId } ],
[ SnackbarProvider ],
] as [ElementType, any][] )
.reduce( ( withContexts, [ Provider, value ] ) => ( children ) => withContexts(
<Provider value={value}>
{children}
</Provider>,
), ( context: ReactNode ) => context )

return withContexts(
return (
<div className={classNames( { mobile: isMobile, tablet: isTablet, desktop: isDesktop }, 'app' )}>
<Suspense fallback={<Loader />}>
<Router>
<Routes>
{this.components.map( ( [ Component, path ] ) => (
<Route key={path} path={path} element={<Component />} />
) )}
</Routes>
</Router>
<StatusContext.Provider value={{ connected, connectedAt, status }}>
<SettingsContext.Provider value={settings}>
<HistoryContext.Provider value={{ viewedLines, transitionHistory, latestLines }}>
<BookmarksContext.Provider value={banis}>
<WritersContext.Provider value={writers}>
<RecommendedSourcesContext.Provider value={recommendedSources}>
<ContentContext.Provider value={{ bani, shabad, lineId, mainLineId, nextLineId }}>
<SnackbarProvider>
<Outlet />
</SnackbarProvider>
</ContentContext.Provider>
</RecommendedSourcesContext.Provider>
</WritersContext.Provider>
</BookmarksContext.Provider>
</HistoryContext.Provider>
</SettingsContext.Provider>
</StatusContext.Provider>
</Suspense>
</div>,
</div>
)
}
}

export default App
export const Route = createRootRoute( {
component: App,
notFoundComponent: () => <Navigate to="/presenter" />,
} )
5 changes: 5 additions & 0 deletions apps/frontend/src/app/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createFileRoute, redirect } from '@tanstack/react-router'

export const Route = createFileRoute( '/' )( {
beforeLoad: () => redirect( { to: '/presenter', throw: true } ),
} )
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react/no-array-index-key */
import './Line.css'
import './index.css'

import classNames from 'classnames'

Expand All @@ -14,12 +14,9 @@ type LineProps = {
larivaarGurbani?: boolean,
larivaarAssist?: boolean,
}
/**
* Overlay Line Component.
* Renders the various aspects of a single line.
*/

const Line = ( {
className = '',
className,
gurmukhi,
larivaarGurbani: larivaar = false,
larivaarAssist = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { useContext } from 'react'

import { OVERLAY_THEMES_URL } from '~/helpers/consts'
import { API_URL } from '~/helpers/consts'
import { StatusContext } from '~/helpers/contexts'

const OVERLAY_THEMES_URL = `${API_URL}/themes/overlay`

type ThemeLoaderProps = { name: string }

/**
* Component to load a theme using a `<link>` tag.
* @param name The name of the CSS theme to load from the server.
* @constructor
*/
const ThemeLoader = ( { name }: ThemeLoaderProps ) => {
const { connectedAt } = useContext( StatusContext )

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import './index.css'

import { createLazyFileRoute } from '@tanstack/react-router'
import classNames from 'classnames'
import { mapValues } from 'lodash'
import { useContext } from 'react'
Expand All @@ -10,8 +9,8 @@ import { customiseLine, getTransliterators } from '~/helpers/line'
import { filterFalsyValues } from '~/helpers/utils'
import { useCurrentLine, useTranslations } from '~/hooks'

import Line from './Line'
import ThemeLoader from './ThemeLoader'
import Line from './-components/Line'
import ThemeLoader from './-components/ThemeLoader'

const Overlay = () => {
const settings = useContext( SettingsContext )
Expand Down Expand Up @@ -60,4 +59,6 @@ const Overlay = () => {
)
}

export default Overlay
export const Route = createLazyFileRoute( '/overlay/' )( {
component: Overlay,
} )
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import './Display.css'
import './index.css'

import classNames from 'classnames'
import { mapValues } from 'lodash'
Expand All @@ -9,18 +9,12 @@ import { ClientSettings } from '~/helpers/options'
import { filterFalsyValues } from '~/helpers/utils'
import { useCurrentLine, useCurrentLines, useTranslations } from '~/hooks'

import Line from './Line'
import Line from '../Line'

type DisplayProps = {
settings: Pick<ClientSettings, 'layout' | 'display' | 'vishraams' | 'theme'>,
}

/**
* Display Component.
* Displays the current Shabad, with visual settings.
* @param shabad The Shabad to render.
* @param lineId The current line in the Shabad.
*/
const Display = ( { settings }: DisplayProps ) => {
const {
layout,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react/no-array-index-key */
import './Line.css'
import './index.css'

import classNames from 'classnames'
import { countSyllables, toSyllabicSymbols } from 'gurmukhi-utils'
Expand Down Expand Up @@ -77,32 +77,6 @@ const {
theme: { simpleGraphics },
} = DEFAULT_OPTIONS.local

/**
* Line Component.
* Renders the various aspects of a single line.
* @param {string} className An optional class name to append.
* @param {string} gurmukhi The Gurmukhi of the line to render.
* @param {string} translations The Punjabi translation of the line to render.
* @param {string} transliterators The Punjabi translation of the line to render.
* @param {string} spacing The justify content value for spacing between the lines.
* @param {boolean} centerText Whether to center text.
* @param {boolean} justifyText Whether to justify (edge to edge) wrapped text (2+ lines long).
* @param {number} presenterFontSize The global font size of presenter lines.
* @param {number} relativeGurmukhiFontSize Relative size for gurmukhi ascii font.
* @param {number} relativeEnglishFontSize Relative size for latin scripts (english/spanish).
* @param {number} relativePunjabiFontSize Relative size for punjabi unicode font.
* @param {number} relativeHindiFontSize Relative font size for hindi unicode font.
* @param {number} relativeUrduFontSize Relative font size for urdu unicode font.
* @param {boolean} larivaarGurbani Whether Gurbani should be continuous or not.
* @param {boolean} larivaarAssist If `larivaarGurbani`, whether alternate words should be coloured.
* @param {boolean} vishraamColors Enables colors for vishraams.
* @param {boolean} vishraamCharacters Enables display of vishraam characters.
* @param {boolean} vishraamLight Enables colors for light vishraams.
* @param {boolean} vishraamMedium Enables colors for medium vishraams.
* @param {boolean} vishraamHeavy Enables colors for heavy vishraams.
* @param {boolean} splitOnVishraam If the line is too long, split it on the vishraam word.
* @param {boolean} simpleGraphics Disables transitions and other intensive effects.
*/
const Line = ( {
className = undefined,
gurmukhi,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import './StatusToast.css'
import './index.css'

import { faInfoCircle } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import createUseLocationHistory from '~/hooks/use-location-history'

export const {
Provider: ControllerLocationHistoryProvider,
useLocationHistory: useControllerLocationHistory,
} = createUseLocationHistory(
'/presenter/controller/search',
{ filter: ( href ) => !!href.match( '/presenter/controller/.*' ) }
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,17 @@ type ToolbarButtonProps = {
onClick?: () => void,
onMouseEnter?: () => void,
onMouseLeave?: () => void,
flip?: 'horizontal' | 'vertical',
}

/**
* Renders an individual icon button, setting the state with the name on hover and click.
* @param {string} name The human-readable name of the icon.
* @param {string} icon The font-awesome icon.
* @param {Function} onClick Optional click handler.
* @param {Function} onMouseEnter MouseEnter click handler.
* @param {Function} onMouseLeave MouseLeave click handler.
* @param {string} className Optional classname.
*/
const ToolbarButton = ( {
name,
icon,
onClick,
onMouseEnter,
onMouseLeave,
className,
flip,
}: ToolbarButtonProps ) => (
<IconButton
key={name}
Expand All @@ -37,7 +30,7 @@ const ToolbarButton = ( {
onClick={onClick}
size="large"
>
<FontAwesomeIcon icon={icon} />
<FontAwesomeIcon icon={icon} flip={flip} />
</IconButton>
)

Expand Down
Loading

0 comments on commit a6b30d4

Please sign in to comment.