mirror of
https://github.com/codeforreal1/compressO
synced 2026-04-21 15:47:56 +00:00
feat: migrate frontend from Next.js to Vite+TanStack Router
This commit is contained in:
parent
54fbac3a68
commit
fd5107f518
43 changed files with 3637 additions and 2477 deletions
|
|
@ -5,13 +5,7 @@
|
|||
"es2021": true
|
||||
},
|
||||
"plugins": ["@typescript-eslint", "prettier", "unused-imports"],
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"airbnb-typescript",
|
||||
"airbnb/hooks",
|
||||
"prettier",
|
||||
"next/core-web-vitals"
|
||||
],
|
||||
"extends": ["airbnb", "airbnb-typescript", "airbnb/hooks", "prettier"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
|
|
@ -72,6 +66,23 @@
|
|||
"ignoreCase": false
|
||||
}
|
||||
],
|
||||
"no-nested-ternary": "off"
|
||||
"no-nested-ternary": "off",
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": ["**/vite.config.*", "**/*.test.*", "**/*.spec.*"]
|
||||
}
|
||||
],
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
{
|
||||
"": "never",
|
||||
"js": "never",
|
||||
"jsx": "never",
|
||||
"ts": "never",
|
||||
"tsx": "never"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -9,13 +9,10 @@
|
|||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
/dist/
|
||||
|
||||
# production
|
||||
/build
|
||||
/out/
|
||||
/dist/
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
|
@ -34,7 +31,6 @@ yarn-error.log*
|
|||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
|
||||
/**/.env
|
||||
|
|
|
|||
|
|
@ -2,5 +2,7 @@
|
|||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": false
|
||||
"semi": false,
|
||||
"plugins": ["prettier-plugin-organize-imports"],
|
||||
"organizeImportsSkipDestructiveCodeActions": true
|
||||
}
|
||||
|
|
|
|||
34
index.html
Normal file
34
index.html
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<meta name="HandheldFriendly" content="true" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||
<meta name="msapplication-TileColor" content="#da532c" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<title>CompressO</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #000000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="portal"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script src="/scripts/accessibility-only-when-focused.js"></script>
|
||||
<script src="/scripts/disable-context-menu.js"></script>
|
||||
<script src="/scripts/disable-zoom.js"></script>
|
||||
<script src="/scripts/disable-reload.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
|
||||
import analyzeBundle from '@next/bundle-analyzer'
|
||||
|
||||
const packageJSON = await import('./package.json', {
|
||||
assert: { type: 'json' },
|
||||
})
|
||||
|
||||
const withBundleAnalyzer = analyzeBundle({
|
||||
enabled: process.env.ANALYZE === 'true',
|
||||
})
|
||||
|
||||
const nextConfig = withBundleAnalyzer({
|
||||
output: 'export',
|
||||
distDir: './dist',
|
||||
cleanDistDir: true,
|
||||
reactStrictMode: false,
|
||||
webpack(config, { webpack }) {
|
||||
config.module.rules.push({
|
||||
test: /\.svg$/,
|
||||
use: ['@svgr/webpack'],
|
||||
})
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'globalThis.__DEV__': false,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
return config
|
||||
},
|
||||
env: {
|
||||
version: packageJSON?.default?.version,
|
||||
},
|
||||
})
|
||||
|
||||
export default nextConfig
|
||||
27
package.json
27
package.json
|
|
@ -7,10 +7,12 @@
|
|||
"url": "https://www.threads.net/@codeforreal"
|
||||
},
|
||||
"license": "AGPL-3.0-only",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"next:dev": "next dev",
|
||||
"next:build": "next build",
|
||||
"next:start": "next start",
|
||||
"vite:dev": "vite --port=3001",
|
||||
"vite:build": "vite build",
|
||||
"vite:preview": "vite preview",
|
||||
"vite:start": "vite",
|
||||
"tauri:dev": "tauri dev",
|
||||
"tauri:build": "tauri build",
|
||||
"tauri:build:debug": "tauri build --debug",
|
||||
|
|
@ -35,16 +37,17 @@
|
|||
"@heroui/tabs": "2.2.8",
|
||||
"@heroui/theme": "2.4.6",
|
||||
"@heroui/tooltip": "2.2.8",
|
||||
"@heroui/use-theme": "^2.1.2",
|
||||
"@tanstack/react-router": "^1.97.21",
|
||||
"@tanstack/router-devtools": "^1.97.21",
|
||||
"@tauri-apps/api": ">=2.0.0-beta.0",
|
||||
"@tauri-apps/plugin-dialog": "2.0.0-beta.3",
|
||||
"@tauri-apps/plugin-fs": "2.0.0-beta.3",
|
||||
"@tauri-apps/plugin-os": "2.0.0-beta.5",
|
||||
"@tauri-apps/plugin-shell": "2.0.0-beta.3",
|
||||
"clsx": "^2.0.0",
|
||||
"framer-motion": "^10.16.4",
|
||||
"framer-motion": "11.18.2",
|
||||
"lodash": "^4.17.21",
|
||||
"next": "14.0.2",
|
||||
"next-themes": "^0.2.1",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
|
|
@ -54,9 +57,8 @@
|
|||
"vaul": "^0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^14.0.3",
|
||||
"@next/eslint-plugin-next": "^12.1.0",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@tanstack/router-plugin": "^1.97.22",
|
||||
"@tauri-apps/cli": ">=2.0.0-beta.0",
|
||||
"@types/lodash": "^4.17.4",
|
||||
"@types/node": "^20",
|
||||
|
|
@ -64,11 +66,11 @@
|
|||
"@types/react-dom": "^18",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"eslint": "8.9.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-next": "^14.1.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-import-resolver-typescript": "^2.5.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
|
|
@ -76,14 +78,17 @@
|
|||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"eslint-plugin-unused-imports": "^3.0.0",
|
||||
"husky": "^8.0.1",
|
||||
"lint-staged": "^13.2.3",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^3.2.5",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"typescript": "^5",
|
||||
"husky": "^8.0.1"
|
||||
"vite": "^6.0.3",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-plugin-svgr": "^4.3.0",
|
||||
"prettier-plugin-organize-imports": "^4.1.0"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
|
|
|||
5275
pnpm-lock.yaml
5275
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +0,0 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
6
postcss.config.ts
Normal file
6
postcss.config.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
|
@ -4,9 +4,9 @@
|
|||
"version": "1.2.0",
|
||||
"identifier": "com.compresso.app",
|
||||
"build": {
|
||||
"beforeBuildCommand": "pnpm next:build",
|
||||
"beforeBuildCommand": "pnpm vite:build",
|
||||
"frontendDist": "../dist",
|
||||
"devUrl": "http://localhost:3000"
|
||||
"devUrl": "http://localhost:3001"
|
||||
},
|
||||
"bundle": {
|
||||
"longDescription": "Compress any video file to a tiny size.",
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
import React from "react";
|
||||
|
||||
function Head() {
|
||||
return (
|
||||
<head>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<meta name="HandheldFriendly" content="true" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||
<meta name="msapplication-TileColor" content="#da532c" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
</head>
|
||||
);
|
||||
}
|
||||
|
||||
export default Head;
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import Script from 'next/script'
|
||||
|
||||
import './globals.css'
|
||||
|
||||
import { Toaster } from '@/components/Toast'
|
||||
import { combinedFonts } from '@/assets/fonts'
|
||||
import UIProvider from '../providers/UIProvider'
|
||||
import ThemeProvider from '../providers/ThemeProvider'
|
||||
import Head from './head'
|
||||
|
||||
const version = process.env.version
|
||||
const env = process.env.NODE_ENV
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<Head />
|
||||
<body className={`antialiased ${combinedFonts}`}>
|
||||
<ThemeProvider>
|
||||
<UIProvider>{children}</UIProvider>
|
||||
<Toaster />
|
||||
</ThemeProvider>
|
||||
<Script
|
||||
src={`/scripts/accessibility-only-when-focused.js?nonce=${version}`}
|
||||
data-env={env}
|
||||
/>
|
||||
<Script
|
||||
src={`/scripts/disable-context-menu.js?nonce=${version}`}
|
||||
data-env={env}
|
||||
/>
|
||||
<Script
|
||||
src={`/scripts/disable-zoom.js?nonce=${version}`}
|
||||
data-env={env}
|
||||
/>
|
||||
<Script
|
||||
src={`/scripts/disable-reload.js?nonce=${version}`}
|
||||
data-env={env}
|
||||
/>
|
||||
<div id="portal" />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import localFont from "next/font/local";
|
||||
|
||||
const kayakRegular = localFont({
|
||||
preload: true,
|
||||
variable: "--font-poppins",
|
||||
src: [
|
||||
{
|
||||
path: "./poppins/Poppins-Regular.ttf",
|
||||
weight: "400",
|
||||
style: "normal",
|
||||
},
|
||||
{
|
||||
path: "./poppins/Poppins-Italic.ttf",
|
||||
weight: "400",
|
||||
style: "italic",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const fonts = [kayakRegular];
|
||||
|
||||
export const combinedFonts = fonts
|
||||
.map((font) => `${font.className} ${font.variable}`)
|
||||
.join(" ");
|
||||
|
|
@ -1,28 +1,28 @@
|
|||
import React from 'react'
|
||||
|
||||
import Logo from '@/assets/icons/logo.svg'
|
||||
import Moon from '@/assets/icons/moon.svg'
|
||||
import Sun from '@/assets/icons/sun.svg'
|
||||
import VideoFile from '@/assets/icons/video-file.svg'
|
||||
import Star from '@/assets/icons/star.svg'
|
||||
import Cross from '@/assets/icons/cross.svg'
|
||||
import CurvedArrow from '@/assets/icons/curved-arrow.svg'
|
||||
import Save from '@/assets/icons/save.svg'
|
||||
import Tick from '@/assets/icons/tick.svg'
|
||||
import FileExplorer from '@/assets/icons/file-explorer.svg'
|
||||
import Play from '@/assets/icons/play.svg'
|
||||
import Info from '@/assets/icons/info.svg'
|
||||
import LowResHeart from '@/assets/icons/low-res-heart.svg'
|
||||
import Github from '@/assets/icons/github.svg'
|
||||
import Question from '@/assets/icons/question.svg'
|
||||
import Setting from '@/assets/icons/setting.svg'
|
||||
import Trash from '@/assets/icons/trash.svg'
|
||||
import DragAndDrop from '@/assets/icons/drag-and-drop.svg'
|
||||
import Warning from '@/assets/icons/warning.svg'
|
||||
import Error from '@/assets/icons/error.svg'
|
||||
import Redo from '@/assets/icons/redo.svg'
|
||||
import Cross from '@/assets/icons/cross.svg?react'
|
||||
import CurvedArrow from '@/assets/icons/curved-arrow.svg?react'
|
||||
import DragAndDrop from '@/assets/icons/drag-and-drop.svg?react'
|
||||
import Error from '@/assets/icons/error.svg?react'
|
||||
import FileExplorer from '@/assets/icons/file-explorer.svg?react'
|
||||
import Github from '@/assets/icons/github.svg?react'
|
||||
import Info from '@/assets/icons/info.svg?react'
|
||||
import Logo from '@/assets/icons/logo.svg?react'
|
||||
import LowResHeart from '@/assets/icons/low-res-heart.svg?react'
|
||||
import Moon from '@/assets/icons/moon.svg?react'
|
||||
import Play from '@/assets/icons/play.svg?react'
|
||||
import Question from '@/assets/icons/question.svg?react'
|
||||
import Redo from '@/assets/icons/redo.svg?react'
|
||||
import Save from '@/assets/icons/save.svg?react'
|
||||
import Setting from '@/assets/icons/setting.svg?react'
|
||||
import Star from '@/assets/icons/star.svg?react'
|
||||
import Sun from '@/assets/icons/sun.svg?react'
|
||||
import Tick from '@/assets/icons/tick.svg?react'
|
||||
import Trash from '@/assets/icons/trash.svg?react'
|
||||
import VideoFile from '@/assets/icons/video-file.svg?react'
|
||||
import Warning from '@/assets/icons/warning.svg?react'
|
||||
|
||||
type SVGAsComponent = React.FC<React.SVGProps<SVGElement>>
|
||||
type SVGAsComponent = React.FunctionComponent<React.SVGProps<SVGSVGElement>>
|
||||
|
||||
function asRegistry<T extends string>(
|
||||
arg: Record<T, SVGAsComponent>,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
import React, { ComponentProps } from 'react'
|
||||
|
||||
import { cn } from '@/utils/tailwind'
|
||||
import Header from './Header'
|
||||
import Footer from './Footer'
|
||||
import { LayoutContext } from './context'
|
||||
import Image from '../Image'
|
||||
import Footer from './Footer'
|
||||
import Header from './Header'
|
||||
import { LayoutContext } from './context'
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode
|
||||
|
|
@ -49,7 +49,7 @@ const Layout = (props: LayoutProps) => {
|
|||
<section
|
||||
{...(containerProps ?? {})}
|
||||
className={cn([
|
||||
'w-full h-full flex flex-col overflow-y-auto',
|
||||
'w-full h-full flex flex-col overflow-y-auto dark:bg-black1 bg-white1',
|
||||
containerProps?.className ?? '',
|
||||
])}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
import React from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
|
||||
import { ThemeProxy, useTheme } from '@/hooks/useTheme'
|
||||
import Button from '../Button'
|
||||
import Icon from '../Icon'
|
||||
import Tooltip from '../Tooltip'
|
||||
|
||||
interface ThemeSwitcherChildrenProps {
|
||||
theme: string | undefined
|
||||
|
||||
setTheme(theme: string | undefined): void
|
||||
}
|
||||
type ThemeSwitcherChildrenProps = ThemeProxy
|
||||
|
||||
interface ThemeSwitcherProps {
|
||||
children?(props: ThemeSwitcherChildrenProps): React.ReactNode
|
||||
|
|
@ -18,23 +14,14 @@ interface ThemeSwitcherProps {
|
|||
function ThemeSwitcher(props: ThemeSwitcherProps) {
|
||||
const { children } = props
|
||||
|
||||
const { theme, setTheme } = useTheme()
|
||||
const [mounted, setMounted] = React.useState(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
setMounted(true)
|
||||
}, [])
|
||||
|
||||
if (!mounted) {
|
||||
return null
|
||||
}
|
||||
const { theme, setTheme, toggleTheme } = useTheme()
|
||||
|
||||
return children == null ? (
|
||||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setTheme(theme === 'light' ? 'dark' : 'light')
|
||||
onPress={() => {
|
||||
toggleTheme()
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
|
|
@ -46,7 +33,7 @@ function ThemeSwitcher(props: ThemeSwitcherProps) {
|
|||
</Tooltip>
|
||||
</Button>
|
||||
) : (
|
||||
children({ theme, setTheme })
|
||||
children({ theme, setTheme, toggleTheme })
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useTheme } from '@/hooks/useTheme'
|
||||
import React from 'react'
|
||||
import { Toaster as NativeToaster, toast } from 'sonner'
|
||||
import { useTheme } from 'next-themes'
|
||||
|
||||
export function Toaster() {
|
||||
const { theme } = useTheme()
|
||||
|
|
@ -8,13 +8,15 @@ export function Toaster() {
|
|||
<NativeToaster
|
||||
position="bottom-center"
|
||||
richColors
|
||||
theme={theme === 'dark' ? 'dark' : 'light'}
|
||||
theme={theme}
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
default: 'rounded-[3rem] px-4 py-2 w-fit',
|
||||
default:
|
||||
'w-fit rounded-[3rem] px-4 py-2 flex justify-center align-center',
|
||||
},
|
||||
duration: 3000,
|
||||
duration: 2500,
|
||||
}}
|
||||
className="flex justify-center items-center"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
1
src/constants/index.ts
Normal file
1
src/constants/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const theme = 'theme'
|
||||
|
|
@ -2,8 +2,23 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@font-face {
|
||||
font-family: 'Poppins';
|
||||
font-weight: 100 200 300 400 500 600 700 800 900;
|
||||
src: url('./assets/fonts/poppins/Poppins-Regular.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Poppins';
|
||||
font-weight: 100 200 300 400 500 600 700 800 900;
|
||||
src: url('./assets/fonts/poppins/Poppins-Italic.ttf');
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
:root {
|
||||
box-sizing: border-box;
|
||||
--font-poppins: 'Poppins', system-ui, -apple-system, BlinkMacSystemFont,
|
||||
'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
*,
|
||||
|
|
@ -15,13 +30,14 @@
|
|||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scroll-behavior: smooth;
|
||||
font-family: var(--font-poppins);
|
||||
}
|
||||
|
||||
*:focus {
|
||||
outline-color: theme('colors.primary') !important;
|
||||
font-family: var(--font-poppins);
|
||||
}
|
||||
|
||||
:root {
|
||||
|
|
@ -30,7 +46,8 @@
|
|||
touch-action: pan-x pan-y;
|
||||
}
|
||||
|
||||
body {
|
||||
body #app {
|
||||
font-family: var(--font-poppins);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: theme('colors.black1');
|
||||
|
|
@ -38,11 +55,7 @@ body {
|
|||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow-x: auto;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
[class='light'] body {
|
||||
53
src/hooks/useTheme.ts
Normal file
53
src/hooks/useTheme.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import * as constants from '@/constants'
|
||||
import { useEffect } from 'react'
|
||||
import { proxy, subscribe, useSnapshot } from 'valtio'
|
||||
|
||||
export type ThemeVariant = 'light' | 'dark'
|
||||
|
||||
export type ThemeProxy = {
|
||||
theme: ThemeVariant
|
||||
setTheme: (newTheme: ThemeVariant) => void
|
||||
toggleTheme: () => void
|
||||
}
|
||||
|
||||
let persistedTheme: ThemeVariant | null = localStorage.getItem(
|
||||
constants.theme,
|
||||
) as ThemeVariant
|
||||
|
||||
if (persistedTheme && !['dark', 'light'].includes(persistedTheme)) {
|
||||
localStorage.removeItem(constants.theme)
|
||||
persistedTheme = null
|
||||
}
|
||||
|
||||
const themeProxy: ThemeProxy = proxy({
|
||||
theme: persistedTheme ?? 'dark',
|
||||
setTheme(newTheme) {
|
||||
themeProxy.theme = newTheme
|
||||
},
|
||||
toggleTheme() {
|
||||
themeProxy.theme = themeProxy.theme === 'dark' ? 'light' : 'dark'
|
||||
},
|
||||
})
|
||||
|
||||
export function useTheme() {
|
||||
const snapshot = useSnapshot(themeProxy)
|
||||
|
||||
useEffect(() => {
|
||||
if (snapshot.theme === 'dark') {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
}, [snapshot.theme])
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = subscribe(themeProxy, () => {
|
||||
localStorage.setItem(constants.theme, themeProxy.theme)
|
||||
})
|
||||
return () => {
|
||||
unsubscribe()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return snapshot
|
||||
}
|
||||
23
src/main.tsx
Normal file
23
src/main.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { RouterProvider, createRouter } from '@tanstack/react-router'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import './global.css'
|
||||
import { routeTree } from './routeTree.gen'
|
||||
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
defaultPreload: 'intent',
|
||||
})
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface Register {
|
||||
router: typeof router
|
||||
}
|
||||
}
|
||||
|
||||
const rootElement = document.getElementById('app')!
|
||||
|
||||
if (!rootElement.innerHTML) {
|
||||
const root = ReactDOM.createRoot(rootElement)
|
||||
root.render(<RouterProvider router={router} />)
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import React from 'react'
|
||||
import { ThemeProvider as NextThemeProvider } from 'next-themes'
|
||||
|
||||
function ThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<NextThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem={false}
|
||||
>
|
||||
{children}
|
||||
</NextThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThemeProvider
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import { HeroUIProvider } from '@heroui/react'
|
||||
import React from 'react'
|
||||
|
||||
function UIProvider({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
|
|
|
|||
88
src/routeTree.gen.ts
Normal file
88
src/routeTree.gen.ts
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/* eslint-disable */
|
||||
|
||||
// @ts-nocheck
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
// This file was automatically generated by TanStack Router.
|
||||
// You should NOT make any changes in this file as it will be overwritten.
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
// Import Routes
|
||||
|
||||
import { Route as rootIndexImport } from './routes/(root)/index'
|
||||
import { Route as rootRoute } from './routes/__root'
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
const rootIndexRoute = rootIndexImport.update({
|
||||
id: '/(root)/',
|
||||
path: '/',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
// Populate the FileRoutesByPath interface
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface FileRoutesByPath {
|
||||
'/(root)/': {
|
||||
id: '/(root)/'
|
||||
path: '/'
|
||||
fullPath: '/'
|
||||
preLoaderRoute: typeof rootIndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and export the route tree
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof rootIndexRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof rootIndexRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesById {
|
||||
__root__: typeof rootRoute
|
||||
'/(root)/': typeof rootIndexRoute
|
||||
}
|
||||
|
||||
export interface FileRouteTypes {
|
||||
fileRoutesByFullPath: FileRoutesByFullPath
|
||||
fullPaths: '/'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to: '/'
|
||||
id: '__root__' | '/(root)/'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
|
||||
export interface RootRouteChildren {
|
||||
rootIndexRoute: typeof rootIndexRoute
|
||||
}
|
||||
|
||||
const rootRouteChildren: RootRouteChildren = {
|
||||
rootIndexRoute: rootIndexRoute,
|
||||
}
|
||||
|
||||
export const routeTree = rootRoute
|
||||
._addFileChildren(rootRouteChildren)
|
||||
._addFileTypes<FileRouteTypes>()
|
||||
|
||||
/* ROUTE_MANIFEST_START
|
||||
{
|
||||
"routes": {
|
||||
"__root__": {
|
||||
"filePath": "__root.tsx",
|
||||
"children": [
|
||||
"/(root)/"
|
||||
]
|
||||
},
|
||||
"/(root)/": {
|
||||
"filePath": "(root)/index.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
ROUTE_MANIFEST_END */
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { proxy } from 'valtio'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import { proxy } from 'valtio'
|
||||
|
||||
import { Video, VideoConfig } from './types'
|
||||
import { Video, VideoConfig } from './-types'
|
||||
|
||||
const videoConfigInitialState: VideoConfig = {
|
||||
convertToExtension: 'mp4',
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { extensions, compressionPresets } from '@/types/compression'
|
||||
import { compressionPresets, extensions } from '@/types/compression'
|
||||
|
||||
export type VideoConfig = {
|
||||
convertToExtension: keyof typeof extensions.video
|
||||
|
|
@ -1,28 +1,30 @@
|
|||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { core } from '@tauri-apps/api'
|
||||
import { motion } from 'framer-motion'
|
||||
import React from 'react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
import VideoPicker from '@/tauri/components/VideoPicker'
|
||||
import Icon from '@/components/Icon'
|
||||
import Layout from '@/components/Layout'
|
||||
import { toast } from '@/components/Toast'
|
||||
import { formatBytes } from '@/utils/fs'
|
||||
import {
|
||||
generateVideoThumbnail,
|
||||
getVideoDuration,
|
||||
} from '@/tauri/commands/ffmpeg'
|
||||
import { getFileMetadata } from '@/tauri/commands/fs'
|
||||
import VideoPicker from '@/tauri/components/VideoPicker'
|
||||
import { extensions } from '@/types/compression'
|
||||
import { formatBytes } from '@/utils/fs'
|
||||
import { convertDurationToMilliseconds } from '@/utils/string'
|
||||
import Layout from '@/components/Layout'
|
||||
import Setting from './ui/Setting'
|
||||
import { videoProxy } from './-state'
|
||||
import DragAndDrop from './ui/DragAndDrop'
|
||||
import { videoProxy } from './state'
|
||||
import Setting from './ui/Setting'
|
||||
import VideoConfig from './ui/VideoConfig'
|
||||
|
||||
export const Route = createFileRoute('/(root)/')({
|
||||
component: Root,
|
||||
})
|
||||
|
||||
function Root() {
|
||||
const { state, resetProxy } = useSnapshot(videoProxy)
|
||||
|
||||
|
|
@ -134,4 +136,4 @@ function Root() {
|
|||
)
|
||||
}
|
||||
|
||||
export default dynamic(() => Promise.resolve(Root), { ssr: false })
|
||||
export default Root
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import React from 'react'
|
||||
import { open } from '@tauri-apps/plugin-shell'
|
||||
import React from 'react'
|
||||
|
||||
import Image from '@/components/Image'
|
||||
import Icon from '@/components/Icon'
|
||||
import TauriLink from '@/tauri/components/Link'
|
||||
import Image from '@/components/Image'
|
||||
import Title from '@/components/Title'
|
||||
import TauriLink from '@/tauri/components/Link'
|
||||
|
||||
function About() {
|
||||
return (
|
||||
|
|
@ -17,7 +17,13 @@ function About() {
|
|||
<h2 className="text-3xl mr-2 font-bold bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
|
||||
compressO
|
||||
</h2>
|
||||
<Image src="/logo.png" alt="logo" width={50} height={50} />
|
||||
<Image
|
||||
disableAnimation
|
||||
src="/logo.png"
|
||||
alt="logo"
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-center italic text-gray-600 dark:text-gray-400 text-sm my-1">
|
||||
Compress any video to a tiny size.
|
||||
|
|
@ -63,7 +69,7 @@ function About() {
|
|||
</p>
|
||||
</section>
|
||||
<p className="self-end text-gray-400 ml-2 text-lg font-bold text-center">
|
||||
v{process.env.version}
|
||||
v{window.__appVersion ?? ''}
|
||||
</p>
|
||||
</section>
|
||||
)
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { event } from '@tauri-apps/api'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { snapshot, useSnapshot } from 'valtio'
|
||||
import { emitTo } from '@tauri-apps/api/event'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import React from 'react'
|
||||
import { snapshot, useSnapshot } from 'valtio'
|
||||
|
||||
import { CustomEvents, VideoCompressionProgress } from '@/types/compression'
|
||||
import { convertDurationToMilliseconds } from '@/utils/string'
|
||||
import Button from '@/components/Button'
|
||||
import { toast } from '@/components/Toast'
|
||||
import { videoProxy } from '../state'
|
||||
import { CustomEvents, VideoCompressionProgress } from '@/types/compression'
|
||||
import { convertDurationToMilliseconds } from '@/utils/string'
|
||||
import { videoProxy } from '../-state'
|
||||
|
||||
function CancelCompression() {
|
||||
const {
|
||||
|
|
@ -79,7 +79,7 @@ function CancelCompression() {
|
|||
color="danger"
|
||||
size="lg"
|
||||
variant={confirmCancellation ? 'solid' : 'flat'}
|
||||
onClick={() => {
|
||||
onPress={() => {
|
||||
if (!confirmCancellation) {
|
||||
setConfirmCancellation(true)
|
||||
} else {
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import React from 'react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
import Progress from '@/components/Progress'
|
||||
import Image from '@/components/Image'
|
||||
import { videoProxy } from '../state'
|
||||
import Progress from '@/components/Progress'
|
||||
import { videoProxy } from '../-state'
|
||||
|
||||
function Compressing() {
|
||||
const {
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react'
|
||||
import { snapshot, useSnapshot } from 'valtio'
|
||||
|
||||
import Slider from '@/components/Slider/Slider'
|
||||
import Checkbox from '@/components/Checkbox'
|
||||
import { videoProxy } from '../state'
|
||||
import Slider from '@/components/Slider/Slider'
|
||||
import { videoProxy } from '../-state'
|
||||
|
||||
function CompressionQuality() {
|
||||
const {
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import React from 'react'
|
||||
import { event } from '@tauri-apps/api'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
|
||||
import Icon from '@/components/Icon'
|
||||
import { toast } from '@/components/Toast'
|
||||
import { extensions } from '@/types/compression'
|
||||
import Icon from '@/components/Icon'
|
||||
import { zoomInTransition } from '@/utils/animation'
|
||||
|
||||
const videoExtensions = Object.keys(extensions?.video)
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { useDisclosure, UseDisclosureProps } from '@heroui/modal'
|
||||
import React from 'react'
|
||||
import { snapshot, useSnapshot } from 'valtio'
|
||||
|
||||
import Button from '@/components/Button'
|
||||
import Code from '@/components/Code'
|
||||
import Icon from '@/components/Icon'
|
||||
import AlertDialog, { AlertDialogButton } from '@/ui/Dialogs/AlertDialog'
|
||||
import Tooltip from '@/components/Tooltip'
|
||||
import { deleteFile } from '@/tauri/commands/fs'
|
||||
import { videoProxy } from '../state'
|
||||
import AlertDialog, { AlertDialogButton } from '@/ui/Dialogs/AlertDialog'
|
||||
import { videoProxy } from '../-state'
|
||||
|
||||
function FileName() {
|
||||
const {
|
||||
|
|
@ -77,7 +77,7 @@ function FileName() {
|
|||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
onClick={handleReconfigure}
|
||||
onPress={handleReconfigure}
|
||||
className="bg-transparent"
|
||||
>
|
||||
<Tooltip content="Reconfigure" aria-label="Reconfigure">
|
||||
|
|
@ -89,7 +89,7 @@ function FileName() {
|
|||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
onClick={handleCancelCompression}
|
||||
onPress={handleCancelCompression}
|
||||
className="bg-transparent"
|
||||
>
|
||||
<Icon name="cross" size={22} />
|
||||
|
|
@ -102,10 +102,10 @@ function FileName() {
|
|||
description="Your compressed video is not yet saved. Are you sure you want to discard it?"
|
||||
renderFooter={({ closeModal }) => (
|
||||
<>
|
||||
<AlertDialogButton onClick={closeModal}>Go Back</AlertDialogButton>
|
||||
<AlertDialogButton onPress={closeModal}>Go Back</AlertDialogButton>
|
||||
<AlertDialogButton
|
||||
color="danger"
|
||||
onClick={() => handleDiscard({ closeModal })}
|
||||
onPress={() => handleDiscard({ closeModal })}
|
||||
>
|
||||
Yes
|
||||
</AlertDialogButton>
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { save } from '@tauri-apps/plugin-dialog'
|
||||
import React from 'react'
|
||||
import { snapshot, useSnapshot } from 'valtio'
|
||||
|
||||
import Button from '@/components/Button'
|
||||
import Icon from '@/components/Icon'
|
||||
import { toast } from '@/components/Toast'
|
||||
|
||||
import { moveFile, showItemInFileManager } from '@/tauri/commands/fs'
|
||||
import Tooltip from '@/components/Tooltip'
|
||||
import { videoProxy } from '../state'
|
||||
import { moveFile, showItemInFileManager } from '@/tauri/commands/fs'
|
||||
import { videoProxy } from '../-state'
|
||||
|
||||
function Success() {
|
||||
const {
|
||||
|
|
@ -65,7 +65,7 @@ function Success() {
|
|||
<Button
|
||||
className="flex justify-center items-center"
|
||||
color="success"
|
||||
onClick={handleCompressedVideoSave}
|
||||
onPress={handleCompressedVideoSave}
|
||||
isLoading={compressedVideo?.isSaving}
|
||||
isDisabled={compressedVideo?.isSaving || compressedVideo?.isSaved}
|
||||
fullWidth
|
||||
|
|
@ -85,7 +85,7 @@ function Success() {
|
|||
<Button
|
||||
isIconOnly
|
||||
className="ml-2 text-green-500"
|
||||
onClick={openInFileManager}
|
||||
onPress={openInFileManager}
|
||||
>
|
||||
<Icon name="fileExplorer" />
|
||||
</Button>
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
import React from 'react'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { DropdownItem } from '@heroui/dropdown'
|
||||
import { useDisclosure } from '@heroui/modal'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import React from 'react'
|
||||
|
||||
import ThemeSwitcher from '@/components/ThemeSwitcher'
|
||||
import Divider from '@/components/Divider'
|
||||
import Button from '@/components/Button'
|
||||
import Icon from '@/components/Icon'
|
||||
import Tooltip from '@/components/Tooltip'
|
||||
import { deleteCache as invokeDeleteCache } from '@/tauri/commands/fs'
|
||||
import { toast } from '@/components/Toast'
|
||||
import Title from '@/components/Title'
|
||||
import Modal, { ModalContent } from '@/components/Modal'
|
||||
import Divider from '@/components/Divider'
|
||||
import Dropdown, { DropdownMenu, DropdownTrigger } from '@/components/Dropdown'
|
||||
import Icon from '@/components/Icon'
|
||||
import Modal, { ModalContent } from '@/components/Modal'
|
||||
import ThemeSwitcher from '@/components/ThemeSwitcher'
|
||||
import Title from '@/components/Title'
|
||||
import { toast } from '@/components/Toast'
|
||||
import Tooltip from '@/components/Tooltip'
|
||||
import { usePlatform } from '@/hooks/usePlatform'
|
||||
import { deleteCache as invokeDeleteCache } from '@/tauri/commands/fs'
|
||||
import About from './About'
|
||||
|
||||
type DropdownKey = 'settings' | 'about'
|
||||
|
|
@ -111,7 +111,7 @@ function AppSetting() {
|
|||
size="sm"
|
||||
color="danger"
|
||||
variant={confirmClearCache ? 'solid' : 'flat'}
|
||||
onClick={() => {
|
||||
onPress={() => {
|
||||
if (!confirmClearCache) {
|
||||
setConfirmClearCache(true)
|
||||
} else {
|
||||
|
|
@ -4,7 +4,7 @@ import React from 'react'
|
|||
import { useSnapshot } from 'valtio'
|
||||
|
||||
import Icon from '@/components/Icon'
|
||||
import { videoProxy } from '../state'
|
||||
import { videoProxy } from '../-state'
|
||||
|
||||
function Success() {
|
||||
const {
|
||||
|
|
@ -1,34 +1,34 @@
|
|||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { core } from '@tauri-apps/api'
|
||||
import { SelectItem } from '@heroui/select'
|
||||
import { core } from '@tauri-apps/api'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { useSnapshot, snapshot } from 'valtio'
|
||||
import React from 'react'
|
||||
import { snapshot, useSnapshot } from 'valtio'
|
||||
|
||||
import Button from '@/components/Button'
|
||||
import Checkbox from '@/components/Checkbox'
|
||||
import Divider from '@/components/Divider'
|
||||
import Icon from '@/components/Icon'
|
||||
import Image from '@/components/Image'
|
||||
import Layout from '@/components/Layout'
|
||||
import Select from '@/components/Select'
|
||||
import Spinner from '@/components/Spinner'
|
||||
import Divider from '@/components/Divider'
|
||||
import Image from '@/components/Image'
|
||||
import Icon from '@/components/Icon'
|
||||
import { toast } from '@/components/Toast'
|
||||
import { formatBytes } from '@/utils/fs'
|
||||
import Tooltip from '@/components/Tooltip'
|
||||
import { compressVideo } from '@/tauri/commands/ffmpeg'
|
||||
import { getFileMetadata } from '@/tauri/commands/fs'
|
||||
import { compressionPresets, extensions } from '@/types/compression'
|
||||
import Tooltip from '@/components/Tooltip'
|
||||
import Checkbox from '@/components/Checkbox'
|
||||
import { cn } from '@/utils/tailwind'
|
||||
import { zoomInTransition } from '@/utils/animation'
|
||||
import Layout from '@/components/Layout'
|
||||
import { videoProxy } from '../state'
|
||||
import Compressing from './Compressing'
|
||||
import FileName from './FileName'
|
||||
import Success from './Success'
|
||||
import { formatBytes } from '@/utils/fs'
|
||||
import { cn } from '@/utils/tailwind'
|
||||
import { videoProxy } from '../-state'
|
||||
import CancelCompression from './CancelCompression'
|
||||
import SaveVideo from './SaveVideo'
|
||||
import Compressing from './Compressing'
|
||||
import CompressionQuality from './CompressionQuality'
|
||||
import FileName from './FileName'
|
||||
import SaveVideo from './SaveVideo'
|
||||
import Success from './Success'
|
||||
import styles from './styles.module.css'
|
||||
|
||||
const videoExtensions = Object.keys(extensions?.video)
|
||||
|
|
@ -213,24 +213,26 @@ function VideoConfig() {
|
|||
<span className="text-gray-600 dark:text-gray-400 block mr-2 text-sm">
|
||||
Disable Compression
|
||||
</span>
|
||||
<Tooltip
|
||||
delay={0}
|
||||
content={
|
||||
<div className="max-w-[10rem] p-2">
|
||||
<p>
|
||||
You can disable the compression if you just want to
|
||||
change the extension of the video.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
aria-label="You can disable the compression if you just
|
||||
want to change the extension of the video"
|
||||
className="flex justify-center items-center"
|
||||
>
|
||||
<Icon name="question" className="block" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Checkbox>
|
||||
<div className="z-10">
|
||||
<Tooltip
|
||||
delay={0}
|
||||
content={
|
||||
<div className="max-w-[10rem] p-2">
|
||||
<p>
|
||||
You can disable the compression if you just want to
|
||||
change the extension of the video.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
aria-label="You can disable the compression if you just
|
||||
want to change the extension of the video"
|
||||
className="flex justify-center items-center"
|
||||
>
|
||||
<Icon name="question" className="block" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<Divider className="my-3" />
|
||||
<Select
|
||||
|
|
@ -311,9 +313,10 @@ function VideoConfig() {
|
|||
<Button
|
||||
as={motion.button}
|
||||
color="primary"
|
||||
onClick={handleCompression}
|
||||
onPress={handleCompression}
|
||||
fullWidth
|
||||
size="lg"
|
||||
className="text-primary"
|
||||
>
|
||||
Compress <Icon name="logo" size={25} />
|
||||
</Button>
|
||||
22
src/routes/__root.tsx
Normal file
22
src/routes/__root.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { Outlet, createRootRoute } from '@tanstack/react-router'
|
||||
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
|
||||
import * as React from 'react'
|
||||
|
||||
import { Toaster } from '@/components/Toast'
|
||||
import UIProvider from '../providers/UIProvider'
|
||||
|
||||
export const Route = createRootRoute({
|
||||
component: RootComponent,
|
||||
})
|
||||
|
||||
function RootComponent() {
|
||||
return (
|
||||
<>
|
||||
<UIProvider>
|
||||
<Outlet />
|
||||
</UIProvider>
|
||||
<Toaster />
|
||||
<TanStackRouterDevtools position="bottom-right" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
10
src/vite.env.d.ts
vendored
Normal file
10
src/vite.env.d.ts
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite-plugin-svgr/client" />
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__appVersion: string
|
||||
}
|
||||
}
|
||||
|
||||
export {}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Config } from 'tailwindcss'
|
||||
import { heroui } from "@heroui/react"
|
||||
import { heroui } from '@heroui/react'
|
||||
|
||||
const WIDTHS = Object.freeze({
|
||||
xs: '320px',
|
||||
|
|
@ -33,7 +33,7 @@ const config: Config = {
|
|||
content: [
|
||||
'./src/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
// NextUI Components
|
||||
"./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}",
|
||||
'./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}',
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
|
|
@ -23,19 +19,9 @@
|
|||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"./dist/types/**/*.ts",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"include": ["**/*.ts", "**/*.tsx", "./dist/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
|
|||
26
vite.config.ts
Normal file
26
vite.config.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { resolve } from 'path'
|
||||
import { defineConfig } from 'vite'
|
||||
import eslint from 'vite-plugin-eslint'
|
||||
import svgr from 'vite-plugin-svgr'
|
||||
import packageJSON from './package.json'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
TanStackRouterVite({
|
||||
routeFileIgnorePattern: '(^[A-Z].*)',
|
||||
}),
|
||||
react(),
|
||||
svgr(),
|
||||
eslint(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve('./src'),
|
||||
},
|
||||
},
|
||||
define: {
|
||||
__appVersion: JSON.stringify(packageJSON.version),
|
||||
},
|
||||
})
|
||||
Loading…
Reference in a new issue