refactor: move to monorepo (#475)
* init * fix: electron Signed-off-by: Innei <i@innei.in> * update Signed-off-by: Innei <i@innei.in> * fix: build Signed-off-by: Innei <i@innei.in> * fix: lint Signed-off-by: Innei <i@innei.in> * fix: test Signed-off-by: Innei <i@innei.in> --------- Signed-off-by: Innei <i@innei.in>
|
|
@ -1 +1 @@
|
|||
src/hono.ts
|
||||
packages/shared/src/hono.ts
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
export type { RendererHandlers } from "./src/renderer-handlers"
|
||||
export type { Router } from "./src/tipc"
|
||||
export { router } from "./src/tipc"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import "../../types/vite"
|
||||
import "../../types/authjs"
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"name": "@follow/electron-main",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"author": "Follow Team",
|
||||
"license": "GPL-3.0-only",
|
||||
"homepage": "https://github.com/RSSNext",
|
||||
"repository": {
|
||||
"url": "https://github.com/RSSNext/follow",
|
||||
"type": "git"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/export.d.ts",
|
||||
"import": "./dist/export.js"
|
||||
}
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"scripts": {
|
||||
"typecheck": "tsup && tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@egoist/tipc": "0.3.2",
|
||||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/utils": "^3.0.0",
|
||||
"@follow/shared": "workspace:*",
|
||||
"@mozilla/readability": "^0.5.0",
|
||||
"@sentry/electron": "5.4.0",
|
||||
"@yornaath/batshit": "0.10.1",
|
||||
"bufferutil": "4.0.8",
|
||||
"builder-util-runtime": "9.2.5",
|
||||
"dayjs": "1.11.13",
|
||||
"dotenv": "16.4.5",
|
||||
"electron-context-menu": "4.0.4",
|
||||
"electron-log": "5.2.0",
|
||||
"electron-squirrel-startup": "1.0.1",
|
||||
"electron-updater": "^6.3.4",
|
||||
"font-list": "1.5.1",
|
||||
"i18next": "^23.15.1",
|
||||
"i18next-browser-languagedetector": "8.0.0",
|
||||
"idb-keyval": "6.2.1",
|
||||
"linkedom": "^0.18.4",
|
||||
"lodash-es": "4.17.21",
|
||||
"lowdb": "7.0.1",
|
||||
"msedge-tts": "1.3.4",
|
||||
"nanoid": "5.0.7",
|
||||
"ofetch": "1.3.4",
|
||||
"posthog-js": "1.161.5",
|
||||
"posthog-node": "4.2.0",
|
||||
"semver": "7.6.3",
|
||||
"tldts": "6.1.46",
|
||||
"vscode-languagedetection": "npm:@vscode/vscode-languagedetection@^1.0.22",
|
||||
"zod": "3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/generator": "7.25.6",
|
||||
"@hono/node-server": "1.13.0",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "^22.5.5",
|
||||
"drizzle-orm": "0.33.0",
|
||||
"electron": "32.1.0",
|
||||
"electron-devtools-installer": "3.2.0",
|
||||
"hono": "4.6.2",
|
||||
"rimraf": "6.0.1",
|
||||
"tsx": "4.19.1",
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import type { defaultNS, ns } from "./constants"
|
||||
import type { resources } from "./resources"
|
||||
|
||||
declare module "i18next" {
|
||||
interface CustomTypeOptions {
|
||||
ns: typeof ns
|
||||
resources: (typeof resources)["en"]
|
||||
defaultNS: typeof defaultNS
|
||||
// if you see an error like: "Argument of type 'DefaultTFuncReturn' is not assignable to parameter of type xyz"
|
||||
// set returnNull to false (and also in the i18next init options)
|
||||
// returnNull: false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
import { electronApp, optimizer } from "@electron-toolkit/utils"
|
||||
import { APP_PROTOCOL, DEEPLINK_SCHEME } from "@shared/constants"
|
||||
import { extractElectronWindowOptions } from "@shared/electron"
|
||||
// @ts-ignore
|
||||
import { APP_PROTOCOL, DEEPLINK_SCHEME } from "@follow/shared/constants"
|
||||
// @ts-ignore
|
||||
import { extractElectronWindowOptions } from "@follow/shared/electron"
|
||||
// @ts-ignore
|
||||
import { env } from "@follow/shared/env"
|
||||
import { app, BrowserWindow, session } from "electron"
|
||||
import squirrelStartup from "electron-squirrel-startup"
|
||||
|
||||
import { env } from "../env"
|
||||
import { isDev, isMacOS } from "./env"
|
||||
import { initializeApp } from "./init"
|
||||
import { setAuthSessionToken } from "./lib/user"
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import path from "node:path"
|
||||
|
||||
import { registerIpcMain } from "@egoist/tipc/main"
|
||||
import { APP_PROTOCOL } from "@shared/constants"
|
||||
import { APP_PROTOCOL } from "@follow/shared/constants"
|
||||
import { app, nativeTheme, shell } from "electron"
|
||||
import contextMenu from "electron-context-menu"
|
||||
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
import { env } from "@env"
|
||||
import { env } from "@follow/shared/env"
|
||||
import PKG from "@pkg"
|
||||
import { hc } from "hono/client"
|
||||
import { ofetch } from "ofetch"
|
||||
|
||||
import type { AppType } from "../../hono"
|
||||
// @ts-ignore
|
||||
import type { AppType } from "../../../../packages/shared/src/hono"
|
||||
import { logger } from "../logger"
|
||||
import { getAuthSessionToken } from "./user"
|
||||
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
import i18next from "i18next"
|
||||
import { initReactI18next } from "react-i18next"
|
||||
|
||||
import { resources } from "../@types/resources"
|
||||
|
||||
export const defaultNS = "native"
|
||||
|
||||
export const i18n = i18next.createInstance()
|
||||
export const i18n = i18next.createInstance() as typeof i18next
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
i18n.init({
|
||||
fallbackLng: "en",
|
||||
defaultNS,
|
||||
resources,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { env } from "@env"
|
||||
import { env } from "@follow/shared/env"
|
||||
import { PostHog } from "posthog-node"
|
||||
|
||||
import { getUser } from "./user"
|
||||
|
|
@ -3,10 +3,14 @@ import { resolve } from "node:path"
|
|||
import { app } from "electron"
|
||||
import { JSONFileSyncPreset } from "lowdb/node"
|
||||
|
||||
export const db = JSONFileSyncPreset(resolve(app.getPath("userData"), "db.json"), {})
|
||||
const db = JSONFileSyncPreset(resolve(app.getPath("userData"), "db.json"), {}) as {
|
||||
data: Record<string, unknown>
|
||||
write: () => void
|
||||
read: () => void
|
||||
}
|
||||
|
||||
export const store = {
|
||||
get: (key: string) => db.data[key],
|
||||
get: (key: string) => db.data[key] as any,
|
||||
set: (key: string, value: any) => {
|
||||
db.data[key] = value
|
||||
db.write()
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { dispatchEventOnWindow } from "@follow/shared/event"
|
||||
import { name } from "@pkg"
|
||||
import { dispatchEventOnWindow } from "@shared/event"
|
||||
import type { BrowserWindow, MenuItem, MenuItemConstructorOptions } from "electron"
|
||||
import { Menu } from "electron"
|
||||
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
import path from "node:path"
|
||||
|
||||
import { getRendererHandlers } from "@egoist/tipc/main"
|
||||
import { callGlobalContextMethod } from "@shared/bridge"
|
||||
import { callGlobalContextMethod } from "@follow/shared/bridge"
|
||||
import type { BrowserWindow } from "electron"
|
||||
import { app, clipboard, dialog, screen } from "electron"
|
||||
|
||||
import { registerMenuAndContextMenu } from "~/init"
|
||||
|
||||
import { isWindows11 } from "../env"
|
||||
import { registerMenuAndContextMenu } from "../init"
|
||||
import { downloadFile } from "../lib/download"
|
||||
import { i18n } from "../lib/i18n"
|
||||
import { cleanAuthSessionToken, cleanUser } from "../lib/user"
|
||||
|
|
@ -15,10 +15,10 @@ export const trackerRoute = {
|
|||
setUser(user)
|
||||
posthog?.capture({
|
||||
event: "login",
|
||||
distinctId: user.id,
|
||||
distinctId: user.id ?? "",
|
||||
properties: {
|
||||
name: user.name,
|
||||
handle: user.handle,
|
||||
handle: user.handle ?? "",
|
||||
},
|
||||
})
|
||||
}),
|
||||
|
|
@ -2,8 +2,8 @@ import path from "node:path"
|
|||
import { fileURLToPath } from "node:url"
|
||||
|
||||
import { is } from "@electron-toolkit/utils"
|
||||
import { callGlobalContextMethod } from "@shared/bridge"
|
||||
import { imageRefererMatches } from "@shared/image"
|
||||
import { callGlobalContextMethod } from "@follow/shared/bridge"
|
||||
import { imageRefererMatches } from "@follow/shared/image"
|
||||
import type { BrowserWindowConstructorOptions } from "electron"
|
||||
import { BrowserWindow, Menu, shell } from "electron"
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"types": ["electron-vite/node"],
|
||||
"moduleResolution": "Bundler",
|
||||
"noImplicitReturns": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@pkg": ["../../package.json"],
|
||||
"@locales/*": ["../../locales/*"],
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { defineConfig } from "tsup"
|
||||
|
||||
export default defineConfig(() => ({
|
||||
entry: ["./export.ts"],
|
||||
outDir: "dist",
|
||||
format: "esm",
|
||||
clean: true,
|
||||
dts: true,
|
||||
splitting: false,
|
||||
sourcemap: true,
|
||||
skipNodeModulesBundle: true,
|
||||
}))
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import "../../types/authjs"
|
||||
|
||||
import type { ElectronAPI } from "@electron-toolkit/preload"
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electron?: ElectronAPI
|
||||
api?: { canWindowBlur: boolean }
|
||||
platform: NodeJS.Platform
|
||||
}
|
||||
}
|
||||
export {}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
{
|
||||
"name": "@follow/web",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"main": "./dist/main/index.js",
|
||||
"scripts": {
|
||||
"test": "vitest",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@egjs/react-infinitegrid": "4.12.0",
|
||||
"@egoist/tipc": "0.3.2",
|
||||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/utils": "^3.0.0",
|
||||
"@follow/electron-main": "workspace:*",
|
||||
"@follow/shared": "workspace:*",
|
||||
"@fontsource/sn-pro": "5.1.0",
|
||||
"@hono/auth-js": "1.0.10",
|
||||
"@hookform/resolvers": "3.9.0",
|
||||
"@iconify/tools": "4.0.6",
|
||||
"@microflash/remark-callout-directives": "4.3.1",
|
||||
"@mozilla/readability": "^0.5.0",
|
||||
"@radix-ui/react-alert-dialog": "1.1.1",
|
||||
"@radix-ui/react-avatar": "1.1.0",
|
||||
"@radix-ui/react-checkbox": "1.1.1",
|
||||
"@radix-ui/react-context-menu": "2.2.1",
|
||||
"@radix-ui/react-dialog": "1.1.1",
|
||||
"@radix-ui/react-dropdown-menu": "2.1.1",
|
||||
"@radix-ui/react-hover-card": "1.1.1",
|
||||
"@radix-ui/react-label": "2.1.0",
|
||||
"@radix-ui/react-popover": "1.1.1",
|
||||
"@radix-ui/react-radio-group": "1.2.0",
|
||||
"@radix-ui/react-scroll-area": "1.1.0",
|
||||
"@radix-ui/react-select": "2.1.1",
|
||||
"@radix-ui/react-slider": "^1.2.0",
|
||||
"@radix-ui/react-slot": "1.1.0",
|
||||
"@radix-ui/react-switch": "1.1.0",
|
||||
"@radix-ui/react-tabs": "1.1.0",
|
||||
"@radix-ui/react-toast": "1.2.1",
|
||||
"@radix-ui/react-tooltip": "1.1.2",
|
||||
"@sentry/react": "8.30.0",
|
||||
"@sentry/vite-plugin": "2.22.4",
|
||||
"@shikijs/transformers": "1.17.7",
|
||||
"@t3-oss/env-core": "^0.11.1",
|
||||
"@tanstack/query-sync-storage-persister": "5.56.2",
|
||||
"@tanstack/react-query": "5.56.2",
|
||||
"@tanstack/react-query-devtools": "5.56.2",
|
||||
"@tanstack/react-query-persist-client": "5.56.2",
|
||||
"@use-gesture/react": "10.3.1",
|
||||
"@yornaath/batshit": "0.10.1",
|
||||
"bufferutil": "4.0.8",
|
||||
"builder-util-runtime": "9.2.5",
|
||||
"class-variance-authority": "0.7.0",
|
||||
"click-to-react-component": "1.1.0",
|
||||
"clsx": "2.1.1",
|
||||
"cmdk": "1.0.0",
|
||||
"dayjs": "1.11.13",
|
||||
"dexie": "4.0.8",
|
||||
"dnum": "^2.13.1",
|
||||
"dotenv": "16.4.5",
|
||||
"electron-log": "5.2.0",
|
||||
"foxact": "0.2.38",
|
||||
"framer-motion": "11.5.4",
|
||||
"franc-min": "6.2.0",
|
||||
"fuse.js": "7.0.0",
|
||||
"hast-util-to-jsx-runtime": "2.3.0",
|
||||
"hast-util-to-text": "4.0.2",
|
||||
"i18next": "^23.15.1",
|
||||
"i18next-browser-languagedetector": "8.0.0",
|
||||
"idb-keyval": "6.2.1",
|
||||
"immer": "10.1.1",
|
||||
"jotai": "2.9.3",
|
||||
"lethargy": "1.0.9",
|
||||
"linkedom": "^0.18.4",
|
||||
"lodash-es": "4.17.21",
|
||||
"msedge-tts": "1.3.4",
|
||||
"nanoid": "5.0.7",
|
||||
"ofetch": "1.3.4",
|
||||
"path-to-regexp": "8.1.0",
|
||||
"posthog-js": "1.161.5",
|
||||
"re-resizable": "6.9.18",
|
||||
"react-error-boundary": "4.0.13",
|
||||
"react-fast-marquee": "1.6.5",
|
||||
"react-hook-form": "7.53.0",
|
||||
"react-hotkeys-hook": "4.5.1",
|
||||
"react-i18next": "^15.0.2",
|
||||
"react-intersection-observer": "9.13.1",
|
||||
"react-resizable-layout": "npm:@innei/react-resizable-layout@0.7.3-fork.1",
|
||||
"react-router-dom": "6.26.2",
|
||||
"react-selecto": "1.26.3",
|
||||
"react-shadow": "20.5.0",
|
||||
"react-virtuoso": "4.10.4",
|
||||
"rehype-infer-description-meta": "2.0.0",
|
||||
"rehype-parse": "9.0.0",
|
||||
"rehype-sanitize": "6.0.0",
|
||||
"rehype-stringify": "10.0.0",
|
||||
"remark-directive": "3.0.0",
|
||||
"remark-gfm": "4.0.0",
|
||||
"remark-gh-alerts": "0.0.3",
|
||||
"remark-parse": "11.0.0",
|
||||
"remark-rehype": "11.1.0",
|
||||
"semver": "7.6.3",
|
||||
"shiki": "1.17.7",
|
||||
"sonner": "^1.5.0",
|
||||
"swiper": "11.1.14",
|
||||
"tailwind-merge": "2.5.2",
|
||||
"tldts": "6.1.46",
|
||||
"unified": "11.0.5",
|
||||
"use-context-selector": "2.0.0",
|
||||
"usehooks-ts": "3.1.0",
|
||||
"utf-8-validate": "6.0.4",
|
||||
"vfile": "6.0.3",
|
||||
"zod": "3.23.8",
|
||||
"zustand": "4.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/generator": "7.25.6",
|
||||
"@hono/node-server": "1.13.0",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/react": "^18.3.7",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"fake-indexeddb": "6.0.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
|
@ -0,0 +1,56 @@
|
|||
import en from "../../../../locales/app/en.json"
|
||||
import common_ardz from "../../../../locales/common/ar-DZ.json"
|
||||
import common_arma from "../../../../locales/common/ar-MA.json"
|
||||
import common_arsa from "../../../../locales/common/ar-SA.json"
|
||||
import common_en from "../../../../locales/common/en.json"
|
||||
import common_es from "../../../../locales/common/es.json"
|
||||
import common_fr from "../../../../locales/common/fr.json"
|
||||
import common_ja from "../../../../locales/common/ja.json"
|
||||
import common_pt from "../../../../locales/common/pt.json"
|
||||
import common_zhCN from "../../../../locales/common/zh-CN.json"
|
||||
import common_zhTW from "../../../../locales/common/zh-TW.json"
|
||||
import external_en from "../../../../locales/external/en.json"
|
||||
import lang_ardz from "../../../../locales/lang/ar-DZ.json"
|
||||
import lang_arma from "../../../../locales/lang/ar-MA.json"
|
||||
import lang_arsa from "../../../../locales/lang/ar-SA.json"
|
||||
import lang_en from "../../../../locales/lang/en.json"
|
||||
import lang_es from "../../../../locales/lang/es.json"
|
||||
import lang_fr from "../../../../locales/lang/fr.json"
|
||||
import lang_ja from "../../../../locales/lang/ja.json"
|
||||
import lang_pt from "../../../../locales/lang/pt.json"
|
||||
import lang_zhCN from "../../../../locales/lang/zh-CN.json"
|
||||
import lang_zhTW from "../../../../locales/lang/zh-TW.json"
|
||||
import settings_en from "../../../../locales/settings/en.json"
|
||||
import shortcuts_en from "../../../../locales/shortcuts/en.json"
|
||||
/**
|
||||
* This file is the language resource that is loaded in full when the app is initialized.
|
||||
* When switching languages, the app will automatically download the required language resources,
|
||||
* we will not load all the language resources to minimize the first screen loading time of the app.
|
||||
* Generally, we only load english resources synchronously by default.
|
||||
* In addition, we attach common resources for other languages, and the size of the common resources must be controlled.
|
||||
*/
|
||||
export const defaultResources = {
|
||||
en: {
|
||||
app: en,
|
||||
lang: lang_en,
|
||||
common: common_en,
|
||||
external: external_en,
|
||||
settings: settings_en,
|
||||
shortcuts: shortcuts_en,
|
||||
},
|
||||
"zh-CN": {
|
||||
lang: lang_zhCN,
|
||||
common: common_zhCN,
|
||||
},
|
||||
ja: {
|
||||
lang: lang_ja,
|
||||
common: common_ja,
|
||||
},
|
||||
"ar-DZ": { lang: lang_ardz, common: common_ardz },
|
||||
"ar-SA": { lang: lang_arsa, common: common_arsa },
|
||||
"ar-MA": { lang: lang_arma, common: common_arma },
|
||||
"zh-TW": { lang: lang_zhTW, common: common_zhTW },
|
||||
es: { lang: lang_es, common: common_es },
|
||||
fr: { lang: lang_fr, common: common_fr },
|
||||
pt: { lang: lang_pt, common: common_pt },
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import type { defaultNS, ns } from "./constants"
|
||||
import type { resources } from "./resources"
|
||||
import type { defaultResources as resources } from "./default-resource"
|
||||
|
||||
declare module "i18next" {
|
||||
interface CustomTypeOptions {
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { env } from "@follow/shared/env"
|
||||
import { queryClient } from "@renderer/lib/query-client"
|
||||
import { useEffect, useLayoutEffect } from "react"
|
||||
import { Outlet } from "react-router-dom"
|
||||
|
||||
import { env } from "../../env.js"
|
||||
import { useAppIsReady } from "./atoms/app"
|
||||
import { useUISettingKey } from "./atoms/settings/ui"
|
||||
import { applyAfterReadyCallbacks } from "./initialize/queue.js"
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import type { GeneralSettings } from "@follow/shared/interface/settings"
|
||||
import { jotaiStore } from "@renderer/lib/jotai"
|
||||
import type { GeneralSettings } from "@shared/interface/settings"
|
||||
|
||||
import { createSettingAtom } from "./helper"
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import type { IntegrationSettings } from "@shared/interface/settings"
|
||||
import type { IntegrationSettings } from "@follow/shared/interface/settings"
|
||||
|
||||
import { createSettingAtom } from "./helper"
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import type { UISettings } from "@shared/interface/settings"
|
||||
import type { UISettings } from "@follow/shared/interface/settings"
|
||||
|
||||
import { createSettingAtom } from "./helper"
|
||||
|
||||