feat(ui): 界面支持按显示器位置预览。
This commit is contained in:
parent
86d4ab6e6a
commit
5df7f54bed
@ -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": {
|
||||||
|
17
src/App.tsx
17
src/App.tsx
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
47
src/components/display-list-container.tsx
Normal file
47
src/components/display-list-container.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
7
src/stores/display.store.tsx
Normal file
7
src/stores/display.store.tsx
Normal 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,
|
||||||
|
});
|
@ -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: [],
|
||||||
}
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user