diff --git a/.vscode/settings.json b/.vscode/settings.json index eef649d84..fbfba239a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -78,7 +78,13 @@ "eslint.workingDirectories": [ "libraries/*", ], + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" } } diff --git a/apps/demo/package.json b/apps/demo/package.json index 17f218a09..ecc643ddf 100644 --- a/apps/demo/package.json +++ b/apps/demo/package.json @@ -3,14 +3,14 @@ "version": "0.1.0", "private": true, "scripts": { - "postinstall": "fetch-scrcpy-server 1.24", + "postinstall": "fetch-scrcpy-server 1.25", "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { - "@fluentui/react": "^8.103.10", + "@fluentui/react": "^8.104.0", "@fluentui/react-file-type-icons": "^8.8.4", "@fluentui/react-hooks": "^8.6.14", "@fluentui/react-icons": "^2.0.190", @@ -33,20 +33,20 @@ "@yume-chan/struct": "workspace:^0.0.17", "mobx": "^6.7.0", "mobx-react-lite": "^3.4.0", - "next": "13.0.7", + "next": "13.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "xterm": "^5.1.0", - "xterm-addon-fit": "^0.6.0", - "xterm-addon-search": "^0.10.0", + "xterm-addon-fit": "^0.7.0", + "xterm-addon-search": "^0.11.0", "xterm-addon-webgl": "^0.14.0" }, "devDependencies": { "@mdx-js/loader": "^2.2.1", - "@next/mdx": "^13.0.7", + "@next/mdx": "^13.1.0", "@types/react": "18.0.26", "eslint": "^8.30.0", - "eslint-config-next": "13.0.7", + "eslint-config-next": "13.1.0", "source-map-loader": "^4.0.1", "typescript": "^4.9.4" } diff --git a/apps/demo/src/components/device-view.tsx b/apps/demo/src/components/device-view.tsx index c5cd85ae8..ad88df69f 100644 --- a/apps/demo/src/components/device-view.tsx +++ b/apps/demo/src/components/device-view.tsx @@ -1,14 +1,27 @@ -import { mergeStyleSets, StackItem } from '@fluentui/react'; -import { ComponentType, CSSProperties, ReactNode, useImperativeHandle, useMemo, useRef, useState } from 'react'; -import { forwardRef } from '../utils/with-display-name'; -import { ResizeObserver, Size } from './resize-observer'; +import { StackItem } from "@fluentui/react"; +import { makeStyles } from "@griffel/react"; +import { + CSSProperties, + ComponentType, + ReactNode, + useImperativeHandle, + useMemo, + useRef, + useState, +} from "react"; +import { forwardRef } from "../utils/with-display-name"; +import { ResizeObserver, Size } from "./resize-observer"; export interface DeviceViewProps { width: number; height: number; - BottomElement?: ComponentType<{ className: string, style: CSSProperties, children: ReactNode; }>; + BottomElement?: ComponentType<{ + className: string; + style: CSSProperties; + children: ReactNode; + }>; children?: ReactNode; } @@ -17,114 +30,128 @@ export interface DeviceViewRef { enterFullscreen(): void; } -export const DeviceView = forwardRef('DeviceView')(({ - width, - height, - BottomElement, - children, -}: DeviceViewProps, ref) => { - const styles = mergeStyleSets({ - outer: { - width: '100%', - height: '100%', - backgroundColor: 'black', - }, - inner: { - position: 'absolute', - transformOrigin: 'top left', - }, - bottom: { - position: 'absolute', - }, - }); - - const [containerSize, setContainerSize] = useState({ width: 0, height: 0 }); - const [bottomSize, setBottomSize] = useState({ width: 0, height: 0 }); - - // Container size minus bottom element size - const usableSize = useMemo(() => ({ - width: containerSize.width, - height: containerSize.height - bottomSize.height, - }), [containerSize, bottomSize]); - - // Compute sizes after scaling - const childrenStyle = useMemo(() => { - let scale: number; - let childrenWidth: number; - let childrenHeight: number; - let childrenTop: number; - let childrenLeft: number; - - if (width === 0 || usableSize.width === 0) { - scale = 1; - childrenWidth = 0; - childrenHeight = 0; - childrenTop = 0; - childrenLeft = 0; - } else { - const videoRatio = width / height; - const containerRatio = usableSize.width / usableSize.height; - - if (videoRatio > containerRatio) { - scale = usableSize.width / width; - childrenWidth = usableSize.width; - childrenHeight = height * scale; - childrenTop = (usableSize.height - childrenHeight) / 2; +const useClasses = makeStyles({ + outer: { + width: "100%", + height: "100%", + backgroundColor: "black", + }, + inner: { + position: "absolute", + transformOrigin: "top left", + }, + bottom: { + position: "absolute", + }, +}); + +export const DeviceView = forwardRef("DeviceView")( + ({ width, height, BottomElement, children }: DeviceViewProps, ref) => { + const classes = useClasses(); + + const [containerSize, setContainerSize] = useState({ + width: 0, + height: 0, + }); + const [bottomSize, setBottomSize] = useState({ + width: 0, + height: 0, + }); + + // Container size minus bottom element size + const usableSize = useMemo( + () => ({ + width: containerSize.width, + height: containerSize.height - bottomSize.height, + }), + [containerSize, bottomSize] + ); + + // Compute sizes after scaling + const childrenStyle = useMemo(() => { + let scale: number; + let childrenWidth: number; + let childrenHeight: number; + let childrenTop: number; + let childrenLeft: number; + + if (width === 0 || usableSize.width === 0) { + scale = 1; + childrenWidth = 0; + childrenHeight = 0; + childrenTop = 0; childrenLeft = 0; } else { - scale = usableSize.height / height; - childrenWidth = width * scale; - childrenHeight = usableSize.height; - childrenTop = 0; - childrenLeft = (usableSize.width - childrenWidth) / 2; + const videoRatio = width / height; + const containerRatio = usableSize.width / usableSize.height; + + if (videoRatio > containerRatio) { + scale = usableSize.width / width; + childrenWidth = usableSize.width; + childrenHeight = height * scale; + childrenTop = (usableSize.height - childrenHeight) / 2; + childrenLeft = 0; + } else { + scale = usableSize.height / height; + childrenWidth = width * scale; + childrenHeight = usableSize.height; + childrenTop = 0; + childrenLeft = (usableSize.width - childrenWidth) / 2; + } } - } - - return { - scale, - width: childrenWidth, - height: childrenHeight, - top: childrenTop, - left: childrenLeft, - }; - }, [width, height, usableSize]); - - const containerRef = useRef(null); - useImperativeHandle(ref, () => ({ - enterFullscreen() { containerRef.current!.requestFullscreen(); }, - }), []); - - return ( - -
- - -
- {children} -
- {(!!width && !!BottomElement) && ( - (null); + useImperativeHandle( + ref, + () => ({ + enterFullscreen() { + containerRef.current!.requestFullscreen(); + }, + }), + [] + ); + + return ( + +
+ + +
- - - )} -
- - ); -}); + {children} +
+ + {!!width && !!BottomElement && ( + + + + )} +
+
+ ); + } +); diff --git a/apps/demo/src/pages/_app.tsx b/apps/demo/src/pages/_app.tsx index c82a2cf96..cbdc07602 100644 --- a/apps/demo/src/pages/_app.tsx +++ b/apps/demo/src/pages/_app.tsx @@ -1,80 +1,92 @@ -import { IComponentAsProps, IconButton, INavButtonProps, mergeStyles, mergeStyleSets, Nav, Stack, StackItem } from "@fluentui/react"; -import type { AppProps } from 'next/app'; +import { + IComponentAsProps, + INavButtonProps, + IconButton, + Nav, + Stack, + StackItem, +} from "@fluentui/react"; +import { makeStyles, mergeClasses, shorthands } from "@griffel/react"; +import type { AppProps } from "next/app"; import Head from "next/head"; -import Link from 'next/link'; -import { useRouter } from 'next/router'; +import Link from "next/link"; +import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; import { Connect, ErrorDialogProvider } from "../components"; -import '../styles/globals.css'; +import "../styles/globals.css"; import { Icons } from "../utils"; -import { register as registerIcons } from '../utils/icons'; +import { register as registerIcons } from "../utils/icons"; registerIcons(); const ROUTES = [ { - url: '/', + url: "/", icon: Icons.Bookmark, - name: 'README', + name: "README", }, { - url: '/device-info', + url: "/device-info", icon: Icons.Phone, - name: 'Device Info', + name: "Device Info", }, { - url: '/file-manager', + url: "/file-manager", icon: Icons.Folder, - name: 'File Manager', + name: "File Manager", }, { - url: '/framebuffer', + url: "/framebuffer", icon: Icons.Camera, - name: 'Screen Capture', + name: "Screen Capture", }, { - url: '/shell', + url: "/shell", icon: Icons.WindowConsole, - name: 'Interactive Shell', + name: "Interactive Shell", }, { - url: '/scrcpy', + url: "/scrcpy", icon: Icons.PhoneLaptop, - name: 'Scrcpy', + name: "Scrcpy", }, { - url: '/tcpip', + url: "/tcpip", icon: Icons.WifiSettings, - name: 'ADB over WiFi', + name: "ADB over WiFi", }, { - url: '/install', + url: "/install", icon: Icons.Box, - name: 'Install APK', + name: "Install APK", }, { - url: '/logcat', + url: "/logcat", icon: Icons.BookSearch, - name: 'Logcat', + name: "Logcat", }, { - url: '/power', + url: "/power", icon: Icons.Power, - name: 'Power Menu', + name: "Power Menu", }, { - url: '/bug-report', + url: "/bug-report", icon: Icons.Bug, - name: 'Bug Report', + name: "Bug Report", }, { - url: '/packet-log', + url: "/packet-log", icon: Icons.TextGrammarError, - name: 'Packet Log', + name: "Packet Log", }, ]; -function NavLink({ link, defaultRender: DefaultRender, ...props }: IComponentAsProps) { +function NavLink({ + link, + defaultRender: DefaultRender, + ...props +}: IComponentAsProps) { if (!link) { return null; } @@ -86,30 +98,32 @@ function NavLink({ link, defaultRender: DefaultRender, ...props }: IComponentAsP ); } +const useClasses = makeStyles({ + titleContainer: { + ...shorthands.borderBottom("1px", "solid", "rgb(243, 242, 241)"), + }, + hidden: { + display: "none", + }, + title: { + ...shorthands.padding("4px", "0"), + fontSize: "20px", + textAlign: "center", + }, + leftColumn: { + width: "270px", + paddingRight: "8px", + ...shorthands.borderRight("1px", "solid", "rgb(243, 242, 241)"), + overflowY: "auto", + }, +}); + function App({ Component, pageProps }: AppProps) { - const classNames = mergeStyleSets({ - 'title-container': { - borderBottom: '1px solid rgb(243, 242, 241)', - }, - title: { - padding: '4px 0', - fontSize: 20, - textAlign: 'center', - }, - 'left-column': { - width: 270, - paddingRight: 8, - borderRight: '1px solid rgb(243, 242, 241)', - overflow: 'auto', - }, - 'right-column': { - borderLeft: '1px solid rgb(243, 242, 241)', - } - }); + const classes = useClasses(); const [leftPanelVisible, setLeftPanelVisible] = useState(false); const toggleLeftPanel = useCallback(() => { - setLeftPanelVisible(value => !value); + setLeftPanelVisible((value) => !value); }, []); useEffect(() => { setLeftPanelVisible(innerWidth > 650); @@ -124,7 +138,11 @@ function App({ Component, pageProps }: AppProps) { - + -
Android Web Toolbox
+
Android Web Toolbox
- - + +