diff --git a/apps/mobile/web-app/html-renderer/package.json b/apps/mobile/web-app/html-renderer/package.json
index a431ac732..c2329e882 100644
--- a/apps/mobile/web-app/html-renderer/package.json
+++ b/apps/mobile/web-app/html-renderer/package.json
@@ -12,12 +12,29 @@
"@emotion/is-prop-valid": "1.3.1",
"@follow/components": "workspace:*",
"@follow/configs": "workspace:*",
+ "@follow/hooks": "workspace:*",
+ "@follow/shared": "workspace:*",
"@follow/types": "workspace:*",
+ "@follow/utils": "workspace:*",
+ "@shikijs/transformers": "3.22.0",
"clsx": "2.1.1",
"foxact": "0.2.52",
"jotai": "2.17.1",
+ "katex": "0.16.28",
"motion": "12.34.0",
"react": "19.0.0",
- "react-blurhash": "0.3.0"
+ "react-blurhash": "0.3.0",
+ "react-dom": "19.0.0",
+ "shiki": "3.22.0",
+ "usehooks-ts": "3.1.1"
+ },
+ "devDependencies": {
+ "@types/hast": "3.0.4",
+ "@vitejs/plugin-react": "5.1.4",
+ "hast-util-to-jsx-runtime": "2.3.6",
+ "pathe": "2.0.3",
+ "typescript": "catalog:",
+ "vite": "7.3.1",
+ "vitest": "3.2.4"
}
}
diff --git a/apps/mobile/web-app/html-renderer/src/parser.tsx b/apps/mobile/web-app/html-renderer/src/parser.tsx
index b20560a66..6178290ca 100644
--- a/apps/mobile/web-app/html-renderer/src/parser.tsx
+++ b/apps/mobile/web-app/html-renderer/src/parser.tsx
@@ -90,14 +90,14 @@ export const parseHtml = (
hr: ({ node, ...props }) =>
createElement("hr", {
...props,
- className: tw`scale-x-50`,
+ className: "scale-x-50",
}),
input: ({ node, ...props }) => {
if (props.type === "checkbox") {
return createElement(Checkbox, {
...props,
disabled: false,
- className: tw`pointer-events-none mr-2`,
+ className: "pointer-events-none mr-2",
})
}
return createElement("input", props)
@@ -170,7 +170,7 @@ export const parseHtml = (
createElement("table", {
...props,
- className: tw`w-full my-0`,
+ className: "w-full my-0",
}),
),
video: ({ node, ...props }) =>
diff --git a/apps/mobile/web-app/html-renderer/vite.config.mts b/apps/mobile/web-app/html-renderer/vite.config.mts
index d457e98bb..8071376f9 100644
--- a/apps/mobile/web-app/html-renderer/vite.config.mts
+++ b/apps/mobile/web-app/html-renderer/vite.config.mts
@@ -2,11 +2,7 @@ import react from "@vitejs/plugin-react"
import path from "pathe"
import { defineConfig } from "vite"
-import { viteRenderBaseConfig } from "../../../desktop/configs/vite.render.config"
-import { astPlugin } from "../../../desktop/plugins/vite/ast"
-
export default defineConfig({
- ...viteRenderBaseConfig,
base: "",
build: {
outDir: path.resolve(import.meta.dirname, "../../../../out/rn-web/html-renderer"),
@@ -19,6 +15,5 @@ export default defineConfig({
define: {
ELECTRON: "false",
},
-
- plugins: [react({}), astPlugin],
+ plugins: [react({})],
})
diff --git a/apps/mobile/web-app/package.json b/apps/mobile/web-app/package.json
index de8271a6a..f5d1ffeb7 100644
--- a/apps/mobile/web-app/package.json
+++ b/apps/mobile/web-app/package.json
@@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"scripts": {
- "build": "cd html-renderer && vite build",
- "typecheck": "cd html-renderer && tsc --noEmit"
+ "build": "pnpm --dir html-renderer build",
+ "typecheck": "pnpm --dir html-renderer typecheck"
}
}
diff --git a/package.json b/package.json
index 446b48b3d..c9a9d136a 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"@babel/parser": "7.29.0",
"@babel/traverse": "7.29.0",
"@babel/types": "7.29.0",
+ "@electron-toolkit/tsconfig": "2.0.0",
"@eslint/compat": "1.4.1",
"@tsslint/cli": "2.0.7",
"@tsslint/config": "2.0.7",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 776cc2c0a..cd124a7ee 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -93,6 +93,9 @@ importers:
'@babel/types':
specifier: 7.29.0
version: 7.29.0
+ '@electron-toolkit/tsconfig':
+ specifier: 2.0.0
+ version: 2.0.0(@types/node@25.2.3)
'@eslint/compat':
specifier: 1.4.1
version: 1.4.1(eslint@9.39.1(jiti@2.6.1))
@@ -679,7 +682,7 @@ importers:
version: 2.1.2
motion:
specifier: 12.34.0
- version: 12.34.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ version: 12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
nanoid:
specifier: 5.1.6
version: 5.1.6
@@ -893,7 +896,7 @@ importers:
version: 3.0.5
motion:
specifier: 12.23.24
- version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ version: 12.23.24(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
next-intl:
specifier: 4.4.0
version: 4.4.0(next@16.0.11(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
@@ -1469,6 +1472,85 @@ importers:
apps/mobile/web-app: {}
+ apps/mobile/web-app/html-renderer:
+ dependencies:
+ '@emotion/is-prop-valid':
+ specifier: 1.3.1
+ version: 1.3.1
+ '@follow/components':
+ specifier: workspace:*
+ version: link:../../../../packages/internal/components
+ '@follow/configs':
+ specifier: workspace:*
+ version: link:../../../../packages/configs
+ '@follow/hooks':
+ specifier: workspace:*
+ version: link:../../../../packages/internal/hooks
+ '@follow/shared':
+ specifier: workspace:*
+ version: link:../../../../packages/internal/shared
+ '@follow/types':
+ specifier: workspace:*
+ version: link:../../../../packages/internal/types
+ '@follow/utils':
+ specifier: workspace:*
+ version: link:../../../../packages/internal/utils
+ '@shikijs/transformers':
+ specifier: 3.22.0
+ version: 3.22.0
+ clsx:
+ specifier: 2.1.1
+ version: 2.1.1
+ foxact:
+ specifier: 0.2.52
+ version: 0.2.52(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ jotai:
+ specifier: 2.17.1
+ version: 2.17.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.0)
+ katex:
+ specifier: 0.16.28
+ version: 0.16.28
+ motion:
+ specifier: 12.34.0
+ version: 12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react:
+ specifier: 19.2.0
+ version: 19.2.0
+ react-blurhash:
+ specifier: 0.3.0
+ version: 0.3.0(blurhash@2.0.5)(react@19.2.0)
+ react-dom:
+ specifier: 19.2.0
+ version: 19.2.0(react@19.2.0)
+ shiki:
+ specifier: 3.22.0
+ version: 3.22.0
+ usehooks-ts:
+ specifier: 3.1.1
+ version: 3.1.1(react@19.2.0)
+ devDependencies:
+ '@types/hast':
+ specifier: 3.0.4
+ version: 3.0.4
+ '@vitejs/plugin-react':
+ specifier: 5.1.4
+ version: 5.1.4(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
+ hast-util-to-jsx-runtime:
+ specifier: 2.3.6
+ version: 2.3.6
+ pathe:
+ specifier: 2.0.3
+ version: 2.0.3
+ typescript:
+ specifier: 'catalog:'
+ version: 5.9.3
+ vite:
+ specifier: 7.3.1
+ version: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
+ vitest:
+ specifier: 3.2.4
+ version: 3.2.4(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@25.2.3)(happy-dom@20.6.1(bufferutil@4.1.0))(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
+
apps/ota:
dependencies:
fzstd:
@@ -1555,13 +1637,13 @@ importers:
version: 0.18.12
motion:
specifier: 12.34.0
- version: 12.34.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ version: 12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
ofetch:
specifier: 1.5.1
version: 1.5.1
rc-modal-sheet:
specifier: 1.0.2
- version: 1.0.2(@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(clsx@2.1.1)(motion@12.34.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(tailwind-merge@3.4.0)(vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))
+ version: 1.0.2(@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(clsx@2.1.1)(motion@12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(tailwind-merge@3.4.0)(vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))
react:
specifier: 19.2.0
version: 19.2.0
@@ -1947,7 +2029,7 @@ importers:
version: 4.1.0(react@19.2.0)
motion:
specifier: 12.34.0
- version: 12.34.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ version: 12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
react-blurhash:
specifier: 0.3.0
version: 0.3.0(blurhash@2.0.5)(react@19.2.0)
@@ -2309,7 +2391,7 @@ importers:
version: 2.17.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.0)
motion:
specifier: 12.34.0
- version: 12.34.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ version: 12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
nanoid:
specifier: 5.1.6
version: 5.1.6
@@ -3742,6 +3824,12 @@ packages:
'@emnapi/wasi-threads@1.1.0':
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
+ '@emotion/is-prop-valid@1.3.1':
+ resolution: {integrity: sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==}
+
+ '@emotion/memoize@0.9.0':
+ resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
+
'@eneris/push-receiver@4.3.0':
resolution: {integrity: sha512-COn7fZIh1P+3FYEpE87E2KoACW/gYTxwURykYqQ1lKMO1O/vdfrWP4ECsew/Kto9Mec34J46hvD5I/2nNa8kfA==}
engines: {node: '>=20'}
@@ -19801,6 +19889,12 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@emotion/is-prop-valid@1.3.1':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+
+ '@emotion/memoize@0.9.0': {}
+
'@eneris/push-receiver@4.3.0':
dependencies:
http_ece: 1.2.1
@@ -29931,12 +30025,13 @@ snapshots:
fraction.js@5.3.4: {}
- framer-motion@12.34.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
+ framer-motion@12.34.2(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
dependencies:
motion-dom: 12.34.2
motion-utils: 12.29.2
tslib: 2.8.1
optionalDependencies:
+ '@emotion/is-prop-valid': 1.3.1
react: 19.2.0
react-dom: 19.2.0(react@19.2.0)
@@ -32448,19 +32543,21 @@ snapshots:
motion-utils@12.29.2: {}
- motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
+ motion@12.23.24(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
dependencies:
- framer-motion: 12.34.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ framer-motion: 12.34.2(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
tslib: 2.8.1
optionalDependencies:
+ '@emotion/is-prop-valid': 1.3.1
react: 19.2.0
react-dom: 19.2.0(react@19.2.0)
- motion@12.34.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
+ motion@12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
dependencies:
- framer-motion: 12.34.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ framer-motion: 12.34.2(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
tslib: 2.8.1
optionalDependencies:
+ '@emotion/is-prop-valid': 1.3.1
react: 19.2.0
react-dom: 19.2.0(react@19.2.0)
@@ -33729,11 +33826,11 @@ snapshots:
iconv-lite: 0.7.2
unpipe: 1.0.0
- rc-modal-sheet@1.0.2(@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(clsx@2.1.1)(motion@12.34.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(tailwind-merge@3.4.0)(vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)):
+ rc-modal-sheet@1.0.2(@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(clsx@2.1.1)(motion@12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(tailwind-merge@3.4.0)(vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)):
dependencies:
'@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
clsx: 2.1.1
- motion: 12.34.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ motion: 12.34.0(@emotion/is-prop-valid@1.3.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
tailwind-merge: 3.4.0
vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 21bc47fb2..42938d056 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -4,6 +4,7 @@ packages:
- apps/desktop/layer/*
- "!apps/mobile/native/example"
- apps/mobile/web-app
+ - apps/mobile/web-app/html-renderer
- "!**/example"
- "!**/example/**"