Skip to content

Commit

Permalink
Switch to React Router 7 (Beta)
Browse files Browse the repository at this point in the history
  • Loading branch information
patdx committed Jan 4, 2025
1 parent 30d5f26 commit 0c2d8ea
Show file tree
Hide file tree
Showing 57 changed files with 3,122 additions and 1,375 deletions.
16 changes: 9 additions & 7 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
indent_style = tab
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
insert_final_newline = true
charset = utf-8
indent_style = tab
indent_size = 2

# YAML doesn't support hard tabs 🙃
# Templates that will be weird with hard tabs in the website editor
[{**.yml,**.yaml,**.md,**.rs,**.mdx,justfile,**.json}]
indent_style = space
18 changes: 9 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
node_modules
dist
.DS_Store
/node_modules/

.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# React Router
/.react-router/
/build/

# Cloudflare
.mf
.wrangler
7 changes: 0 additions & 7 deletions .gitpod.yml

This file was deleted.

1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
save-prefix=
7 changes: 3 additions & 4 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.yarn
dist
node_modules
pnpm-lock.yaml
/pnpm-lock.yaml
/build/**/*
/auto-imports.d.ts
4 changes: 1 addition & 3 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
{
"singleQuote": true,
"semi": false,
"tabWidth": 2,
"useTabs": true
"semi": false
}
11 changes: 0 additions & 11 deletions .vscode/settings.json

This file was deleted.

81 changes: 73 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,80 @@
# subtitle-app
# patdx-remix-template

## Access here: https://subtitle-app.vercel.app/
## Create a new project from this template

This is an open-source application to play a subtitle file as if it were a video.
This will copy the code in `main` branch to a new directory.

It supports SRT files or ZIP archives with SRT files inside.
```
npx degit patdx/patdx-remix-template
```

It can be useful to enjoy content in a second subtitle language.
## Summary

There are similar tools for computers such as [Language Reactor](https://www.languagereactor.com/) extension but I could not find any good tool that can be used with your TV.
This is a template for React Router 7 (Remix) apps with the following features already set up:

With this app, you can play the main content via the regular streaming app on your TV, then open up Subtitle App on any old phone/table, queue up the subtitles file and place it next to the TV.
- Cloudflare Pages Functions deployment using wrangler.toml
- React 19
- Auto import plugin with React imports set up
- Tailwind CSS

I have used it to watch some K-dramas with my partner as both of us have different preferred languages for watching TV, and neither of us know Korean.
It is largely based on the [React Router 7 Cloudflare D1 Template](https://github.com/remix-run/react-router-templates/tree/main/cloudflare-d1) but using Cloudflare Pages instead of the new Cloudflare Worker Assets feature, and a different plugin to use Worker Proxy mode instead of the Vite Environments API.

## Adding Node-targeted modules

If you need to use a module that is targeted for Node, try adding `nodejs_compat` to the wrangler.json:

```json
{
"compatibility_flags": ["nodejs_compat"]
}
```

And add the module to the SSR externals list in vite.config.ts:

```diff
ssr: {
external: [
'node:async_hooks',
+ 'nodemailer',
],
},
```

## Development

Run the dev server:

```sh
pnpm dev
```

To run Wrangler:

```sh
pnpm build
pnpm start
```

## Deployment

> [!WARNING]
> Cloudflare does _not_ use `wrangler.toml` to configure deployment bindings.
> You **MUST** [configure deployment bindings manually in the Cloudflare dashboard][bindings].
First, build your app for production:

```sh
pnpm build
```

Then, deploy your app to Cloudflare Pages:

```sh
pnpm run deploy
```

[bindings]: https://developers.cloudflare.com/pages/functions/bindings/

## Styling

This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever css framework you prefer. See the [Vite docs on css](https://vitejs.dev/guide/features.html#css) for more information.
25 changes: 25 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
- restore favicon, etc
- syncing between devices
- use evolu or one(?) that crsqlite related thing
- switch to remix?
- disable unnecessary text highlighting
- eg when clicking the next button
- and double click triggering highlight instead of another click?
- refer to ionic css: https://github.com/ionic-team/ionic-framework/blob/1b11b82eaaa0982f98547f2854563517174c865c/core/src/css/structure.scss#L75
- better ui for navigating time
- like +10s -10s
- or a dial
- or tapping text in the transcript view
- fix background for black player page
- track time for each episode separately
- remember last time for each episode
- next episode button
- transcript view
- markup support
- have it fade out after a few seconds
- only show full screen button on platforms that support it (not iOS)
- add padding
- add more options to change the font size
- auto shrink large text if it does not fit
- Fix untappable buttons in PwA mode
- fix theme color/background color
24 changes: 24 additions & 0 deletions app/.server/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { AsyncLocalStorage } from 'node:async_hooks'

export interface MyCloudflareEnvironment {
VALUE_FROM_CLOUDFLARE: string
}

export interface MyAppLoadContext {
request: Request
env: MyCloudflareEnvironment
executionCtx: ExecutionContext
[key: string]: unknown
}

declare module 'react-router' {
interface AppLoadContext extends MyAppLoadContext {}
}

export const MyAppLoadContext = new AsyncLocalStorage<MyAppLoadContext>()

export function getMyAppLoadContext() {
const ctx = MyAppLoadContext.getStore()
if (!ctx) throw new Error('MyAppLoadContext not found')
return ctx
}
27 changes: 27 additions & 0 deletions app/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
user-select: none;

/* Should we use any of the properties set here? https://github.com/ionic-team/ionic-framework/blob/1b11b82eaaa0982f98547f2854563517174c865c/core/src/css/structure.scss#L75 */
/* transform: translateZ(0);
text-rendering: optimizeLegibility;
overflow: hidden;
touch-action: manipulation;
-webkit-user-drag: none;
-ms-content-zooming: none;
word-wrap: break-word;
overscroll-behavior-y: none;
-webkit-text-size-adjust: none;
text-size-adjust: none; */
}
File renamed without changes.
File renamed without changes.
87 changes: 87 additions & 0 deletions app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import * as konsta from 'konsta/react'
import {
isRouteErrorResponse,
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from 'react-router'
import type { Route } from './+types/root'
import stylesheet from './app.css?url'

export const links: Route.LinksFunction = () => [
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{
rel: 'preconnect',
href: 'https://fonts.gstatic.com',
crossOrigin: 'anonymous',
},
{
rel: 'stylesheet',
href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
},
{ rel: 'stylesheet', href: stylesheet },
]

// Create a client
const queryClient = new QueryClient()

export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover"
/>
<Meta />
<Links />
</head>
<body>
<QueryClientProvider client={queryClient}>
<konsta.App id="app" safeAreas theme="ios">
{children}
</konsta.App>
</QueryClientProvider>
<ScrollRestoration />
<Scripts />
</body>
</html>
)
}

export default function App() {
return <Outlet />
}

export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
let message = 'Oops!'
let details = 'An unexpected error occurred.'
let stack: string | undefined

if (isRouteErrorResponse(error)) {
message = error.status === 404 ? '404' : 'Error'
details =
error.status === 404
? 'The requested page could not be found.'
: error.statusText || details
} else if (import.meta.env.DEV && error && error instanceof Error) {
details = error.message
stack = error.stack
}

return (
<main className="pt-16 p-4 container mx-auto">
<h1>{message}</h1>
<p>{details}</p>
{stack && (
<pre className="w-full p-4 overflow-x-auto">
<code>{stack}</code>
</pre>
)}
</main>
)
}
4 changes: 4 additions & 0 deletions app/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { RouteConfig } from '@react-router/dev/routes'
import { flatRoutes } from '@react-router/fs-routes'

export default flatRoutes() satisfies RouteConfig
Loading

0 comments on commit 0c2d8ea

Please sign in to comment.