feat(ui): 界面支持按显示器位置预览。

This commit is contained in:
Ivan Li 2023-03-19 11:19:20 +08:00
parent 86d4ab6e6a
commit 5df7f54bed
7 changed files with 80 additions and 19 deletions

View File

@ -8,7 +8,7 @@
}, },
"package": { "package": {
"productName": "test-demo", "productName": "test-demo",
"version": "0.0.0" "version": "0.0.1"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {
@ -27,7 +27,7 @@
"icons/icon.icns", "icons/icon.icns",
"icons/icon.ico" "icons/icon.ico"
], ],
"identifier": "cc.ivanli.take-screenshot-test-demo", "identifier": "cc.ivanli.ambient-light.desktop",
"targets": "all" "targets": "all"
}, },
"security": { "security": {

View File

@ -1,24 +1,25 @@
import { createEffect, createSignal } from "solid-js"; import { createEffect } from 'solid-js';
import { invoke } from '@tauri-apps/api/tauri'; import { invoke } from '@tauri-apps/api/tauri';
import { DisplayInfo } from './models/display-info.model';
import { DisplayView } from './components/\u0016display-view'; import { DisplayView } from './components/\u0016display-view';
import { DisplayListContainer } from './components/display-list-container';
import { displayStore, setDisplayStore } from './stores/display.store';
function App() { function App() {
const [displays, setDisplays] = createSignal<DisplayInfo[]>([]);
createEffect(() => { createEffect(() => {
invoke<string>('list_display_info').then((displays) => { invoke<string>('list_display_info').then((displays) => {
setDisplays(JSON.parse(displays)); setDisplayStore({
displays: JSON.parse(displays),
});
}); });
}); });
return ( return (
<div class="container"> <div class="container">
<ol> <DisplayListContainer>
{displays().map((display) => { {displayStore.displays.map((display) => {
return <DisplayView display={display} />; return <DisplayView display={display} />;
})} })}
</ol> </DisplayListContainer>
</div> </div>
); );
} }

View File

@ -1,5 +1,6 @@
import { Component } from 'solid-js'; import { Component, createMemo } from 'solid-js';
import { DisplayInfo } from '../models/display-info.model'; import { DisplayInfo } from '../models/display-info.model';
import { displayStore } from '../stores/display.store';
import { DisplayInfoPanel } from './display-info-panel'; import { DisplayInfoPanel } from './display-info-panel';
import { ScreenView } from './screen-view'; import { ScreenView } from './screen-view';
@ -8,12 +9,18 @@ type DisplayViewProps = {
}; };
export const DisplayView: Component<DisplayViewProps> = (props) => { export const DisplayView: Component<DisplayViewProps> = (props) => {
const style = createMemo(() => ({
width: `${props.display.width * displayStore.viewScale}px`,
height: `${props.display.height * displayStore.viewScale}px`,
top: `${props.display.y * displayStore.viewScale}px`,
left: `${props.display.x * displayStore.viewScale}px`,
}));
return ( return (
<section class="relative"> <section class="absolute bg-gray-300" style={style()}>
<ScreenView displayId={props.display.id} /> <ScreenView displayId={props.display.id} />
<DisplayInfoPanel <DisplayInfoPanel
display={props.display} display={props.display}
class="absolute bg-slate-50/10 top-1/4 left-1/4 rounded backdrop-blur w-1/3 min-w-fit text-black" class="absolute bg-slate-50/10 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded backdrop-blur w-1/3 min-w-[300px] text-black"
/> />
</section> </section>
); );

View File

@ -8,8 +8,8 @@ type DisplayInfoItemProps = {
export const DisplayInfoItem: ParentComponent<DisplayInfoItemProps> = (props) => { export const DisplayInfoItem: ParentComponent<DisplayInfoItemProps> = (props) => {
return ( return (
<dl class="px-3 py-1 flex hover:bg-gray-100/50 gap-2 text-black rounded"> <dl class="px-3 py-1 flex hover:bg-gray-100/50 gap-2 text-black rounded">
<dt class="uppercase w-1/2 select-all">{props.label}</dt> <dt class="uppercase w-1/2 select-all whitespace-nowrap">{props.label}</dt>
<dd class="select-all">{props.children}</dd> <dd class="select-all w-1/2 whitespace-nowrap">{props.children}</dd>
</dl> </dl>
); );
}; };

View File

@ -0,0 +1,47 @@
import { createEffect, createMemo, createSignal, on, ParentComponent } from 'solid-js';
import { displayStore, setDisplayStore } from '../stores/display.store';
export const DisplayListContainer: ParentComponent = (props) => {
const [olStyle, setOlStyle] = createSignal({
top: '0px',
left: '0px',
});
const [rootStyle, setRootStyle] = createSignal({
width: '100%',
height: '100%',
});
createEffect(() => {
const boundLeft = Math.min(0, ...displayStore.displays.map((display) => display.x));
const boundTop = Math.min(0, ...displayStore.displays.map((display) => display.y));
const boundRight = Math.max(
0,
...displayStore.displays.map((display) => display.x + display.width),
);
const boundBottom = Math.max(
0,
...displayStore.displays.map((display) => display.y + display.height),
);
setDisplayStore({
viewScale: 1200 / (boundRight - boundLeft),
});
setOlStyle({
top: `${-boundTop * displayStore.viewScale}px`,
left: `${-boundLeft * displayStore.viewScale}px`,
});
setRootStyle({
width: `${(boundRight - boundLeft) * displayStore.viewScale}px`,
height: `${(boundBottom - boundTop) * displayStore.viewScale}px`,
});
});
return (
<section class="relative bg-gray-400/30" style={rootStyle()}>
<ol class="absolute bg-gray-700" style={olStyle()}>
{props.children}
</ol>
</section>
);
};

View File

@ -0,0 +1,7 @@
import { createStore } from 'solid-js/store';
import { DisplayInfo } from '../models/display-info.model';
export const [displayStore, setDisplayStore] = createStore({
displays: new Array<DisplayInfo>(),
viewScale: 0.2,
});

View File

@ -1,10 +1,9 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
module.exports = { module.exports = {
content: [ mode: 'jit',
"./src/**/*.{js,jsx,ts,tsx}", content: ['./src/**/*.{js,jsx,ts,tsx}'],
],
theme: { theme: {
extend: {}, extend: {},
}, },
plugins: [], plugins: [],
} };