Compare commits
2 Commits
782f3bf029
...
fc8b3164d8
Author | SHA1 | Date | |
---|---|---|---|
fc8b3164d8 | |||
932cc78bcf |
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -3,5 +3,8 @@
|
|||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"Itertools",
|
"Itertools",
|
||||||
"Leds"
|
"Leds"
|
||||||
]
|
],
|
||||||
|
"idf.customExtraVars": {
|
||||||
|
"OPENOCD_SCRIPTS": "/Users/ivan/.espressif/tools/openocd-esp32/v0.11.0-esp32-20211220/openocd-esp32/share/openocd/scripts"
|
||||||
|
}
|
||||||
}
|
}
|
18
.vscode/tasks.json
vendored
18
.vscode/tasks.json
vendored
@ -3,14 +3,23 @@
|
|||||||
// for the documentation about the tasks.json format
|
// for the documentation about the tasks.json format
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "dev",
|
||||||
|
"type": "shell",
|
||||||
|
"isBackground": true,
|
||||||
|
"command": "pnpm",
|
||||||
|
"args": [
|
||||||
|
"tauri",
|
||||||
|
"dev"
|
||||||
|
],
|
||||||
|
"problemMatcher": [
|
||||||
|
"$eslint-stylish"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "ui:dev",
|
"label": "ui:dev",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
// `dev` keeps running in the background
|
|
||||||
// ideally you should also configure a `problemMatcher`
|
|
||||||
// see https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
|
|
||||||
"isBackground": true,
|
"isBackground": true,
|
||||||
// change this to your `beforeDevCommand`:
|
|
||||||
"command": "pnpm",
|
"command": "pnpm",
|
||||||
"args": [
|
"args": [
|
||||||
"dev"
|
"dev"
|
||||||
@ -19,7 +28,6 @@
|
|||||||
{
|
{
|
||||||
"label": "ui:build",
|
"label": "ui:build",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
// change this to your `beforeBuildCommand`:
|
|
||||||
"command": "pnpm",
|
"command": "pnpm",
|
||||||
"args": [
|
"args": [
|
||||||
"build"
|
"build"
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@solidjs/router": "^0.8.2",
|
||||||
"@tauri-apps/api": "^1.2.0",
|
"@tauri-apps/api": "^1.2.0",
|
||||||
"solid-js": "^1.4.7",
|
"solid-js": "^1.4.7",
|
||||||
"solid-tippy": "^0.2.1",
|
"solid-tippy": "^0.2.1",
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
lockfileVersion: '6.0'
|
lockfileVersion: '6.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@solidjs/router':
|
||||||
|
specifier: ^0.8.2
|
||||||
|
version: 0.8.2(solid-js@1.6.14)
|
||||||
'@tauri-apps/api':
|
'@tauri-apps/api':
|
||||||
specifier: ^1.2.0
|
specifier: ^1.2.0
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
@ -621,6 +624,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==}
|
resolution: {integrity: sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@solidjs/router@0.8.2(solid-js@1.6.14):
|
||||||
|
resolution: {integrity: sha512-gUKW+LZqxtX6y/Aw6JKyy4gQ9E7dLqp513oB9pSYJR1HM5c56Pf7eijzyXX+b3WuXig18Cxqah4tMtF0YGu80w==}
|
||||||
|
peerDependencies:
|
||||||
|
solid-js: ^1.5.3
|
||||||
|
dependencies:
|
||||||
|
solid-js: 1.6.14
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@tauri-apps/api@1.2.0:
|
/@tauri-apps/api@1.2.0:
|
||||||
resolution: {integrity: sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==}
|
resolution: {integrity: sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==}
|
||||||
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
||||||
|
@ -57,7 +57,11 @@ impl LedColorsPublisher {
|
|||||||
let internal_tasks_version = self.inner_tasks_version.clone();
|
let internal_tasks_version = self.inner_tasks_version.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let colors = screenshot_manager::get_display_colors(display_id, &sample_points, bound_scale_factor);
|
let colors = screenshot_manager::get_display_colors(
|
||||||
|
display_id,
|
||||||
|
&sample_points,
|
||||||
|
bound_scale_factor,
|
||||||
|
);
|
||||||
|
|
||||||
if let Err(err) = colors {
|
if let Err(err) = colors {
|
||||||
warn!("Failed to get colors: {}", err);
|
warn!("Failed to get colors: {}", err);
|
||||||
@ -86,7 +90,11 @@ impl LedColorsPublisher {
|
|||||||
|
|
||||||
// log::info!("tick: {}ms", start.elapsed().as_millis());
|
// log::info!("tick: {}ms", start.elapsed().as_millis());
|
||||||
start = tokio::time::Instant::now();
|
start = tokio::time::Instant::now();
|
||||||
let colors = screenshot_manager::get_display_colors(display_id, &sample_points, bound_scale_factor);
|
let colors = screenshot_manager::get_display_colors(
|
||||||
|
display_id,
|
||||||
|
&sample_points,
|
||||||
|
bound_scale_factor,
|
||||||
|
);
|
||||||
|
|
||||||
if let Err(err) = colors {
|
if let Err(err) = colors {
|
||||||
warn!("Failed to get colors: {}", err);
|
warn!("Failed to get colors: {}", err);
|
||||||
@ -117,14 +125,18 @@ impl LedColorsPublisher {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_all_colors_worker(&self, display_ids: Vec<u32>, mappers: Vec<SamplePointMapper>, mut display_colors_rx: broadcast::Receiver<(u32, Vec<u8>)>) {
|
fn start_all_colors_worker(
|
||||||
|
&self,
|
||||||
|
display_ids: Vec<u32>,
|
||||||
|
mappers: Vec<SamplePointMapper>,
|
||||||
|
mut display_colors_rx: broadcast::Receiver<(u32, Vec<u8>)>,
|
||||||
|
) {
|
||||||
let sorted_colors_tx = self.sorted_colors_tx.clone();
|
let sorted_colors_tx = self.sorted_colors_tx.clone();
|
||||||
let colors_tx = self.colors_tx.clone();
|
let colors_tx = self.colors_tx.clone();
|
||||||
log::debug!("start all_colors_worker");
|
log::debug!("start all_colors_worker");
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
|
|
||||||
let sorted_colors_tx = sorted_colors_tx.write().await;
|
let sorted_colors_tx = sorted_colors_tx.write().await;
|
||||||
let colors_tx = colors_tx.write().await;
|
let colors_tx = colors_tx.write().await;
|
||||||
|
|
||||||
@ -212,13 +224,12 @@ impl LedColorsPublisher {
|
|||||||
|
|
||||||
let configs = configs.unwrap();
|
let configs = configs.unwrap();
|
||||||
|
|
||||||
|
|
||||||
let mut inner_tasks_version = inner_tasks_version.write().await;
|
let mut inner_tasks_version = inner_tasks_version.write().await;
|
||||||
*inner_tasks_version = inner_tasks_version.overflowing_add(1).0;
|
*inner_tasks_version = inner_tasks_version.overflowing_add(1).0;
|
||||||
drop(inner_tasks_version);
|
drop(inner_tasks_version);
|
||||||
|
|
||||||
|
let (display_colors_tx, display_colors_rx) =
|
||||||
let (display_colors_tx, display_colors_rx) = broadcast::channel::<(u32, Vec<u8>)>(8);
|
broadcast::channel::<(u32, Vec<u8>)>(8);
|
||||||
|
|
||||||
for sample_point_group in configs.sample_point_groups.clone() {
|
for sample_point_group in configs.sample_point_groups.clone() {
|
||||||
let display_id = sample_point_group.display_id;
|
let display_id = sample_point_group.display_id;
|
||||||
@ -343,7 +354,11 @@ impl LedColorsPublisher {
|
|||||||
|
|
||||||
let bound_scale_factor = screenshot.bound_scale_factor;
|
let bound_scale_factor = screenshot.bound_scale_factor;
|
||||||
|
|
||||||
let colors_config = DisplaySamplePointGroup { display_id, points, bound_scale_factor };
|
let colors_config = DisplaySamplePointGroup {
|
||||||
|
display_id,
|
||||||
|
points,
|
||||||
|
bound_scale_factor,
|
||||||
|
};
|
||||||
|
|
||||||
colors_configs.push(colors_config);
|
colors_configs.push(colors_config);
|
||||||
}
|
}
|
||||||
|
108
src/App.tsx
108
src/App.tsx
@ -1,104 +1,18 @@
|
|||||||
import { createEffect, onCleanup } from 'solid-js';
|
import { Routes, Route } from '@solidjs/router';
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { LedStripConfiguration } from './components/led-strip-configuration/led-strip-configuration';
|
||||||
import { DisplayView } from './components/display-view';
|
import { WhiteBalance } from './components/white-balance/white-balance';
|
||||||
import { DisplayListContainer } from './components/display-list-container';
|
|
||||||
import { displayStore, setDisplayStore } from './stores/display.store';
|
|
||||||
import { LedStripConfigContainer } from './models/led-strip-config';
|
|
||||||
import { setLedStripStore } from './stores/led-strip.store';
|
|
||||||
import { listen } from '@tauri-apps/api/event';
|
|
||||||
import { LedStripPartsSorter } from './components/led-strip-parts-sorter';
|
|
||||||
import { createStore } from 'solid-js/store';
|
|
||||||
import {
|
|
||||||
LedStripConfigurationContext,
|
|
||||||
LedStripConfigurationContextType,
|
|
||||||
} from './contexts/led-strip-configuration.context';
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
createEffect(() => {
|
|
||||||
invoke<string>('list_display_info').then((displays) => {
|
|
||||||
setDisplayStore({
|
|
||||||
displays: JSON.parse(displays),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
invoke<LedStripConfigContainer>('read_led_strip_configs').then((configs) => {
|
|
||||||
console.log(configs);
|
|
||||||
setLedStripStore(configs);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// listen to config_changed event
|
|
||||||
createEffect(() => {
|
|
||||||
const unlisten = listen('config_changed', (event) => {
|
|
||||||
const { strips, mappers } = event.payload as LedStripConfigContainer;
|
|
||||||
console.log(event.payload);
|
|
||||||
setLedStripStore({
|
|
||||||
strips,
|
|
||||||
mappers,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
onCleanup(() => {
|
|
||||||
unlisten.then((unlisten) => unlisten());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// listen to led_colors_changed event
|
|
||||||
createEffect(() => {
|
|
||||||
const unlisten = listen<Uint8ClampedArray>('led_colors_changed', (event) => {
|
|
||||||
const colors = event.payload;
|
|
||||||
|
|
||||||
setLedStripStore({
|
|
||||||
colors,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
onCleanup(() => {
|
|
||||||
unlisten.then((unlisten) => unlisten());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// listen to led_sorted_colors_changed event
|
|
||||||
createEffect(() => {
|
|
||||||
const unlisten = listen<Uint8ClampedArray>('led_sorted_colors_changed', (event) => {
|
|
||||||
const sortedColors = event.payload;
|
|
||||||
|
|
||||||
setLedStripStore({
|
|
||||||
sortedColors,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
onCleanup(() => {
|
|
||||||
unlisten.then((unlisten) => unlisten());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const [ledStripConfiguration, setLedStripConfiguration] = createStore<
|
|
||||||
LedStripConfigurationContextType[0]
|
|
||||||
>({
|
|
||||||
selectedStripPart: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ledStripConfigurationContextValue: LedStripConfigurationContextType = [
|
|
||||||
ledStripConfiguration,
|
|
||||||
{
|
|
||||||
setSelectedStripPart: (v) => {
|
|
||||||
setLedStripConfiguration({
|
|
||||||
selectedStripPart: v,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<LedStripConfigurationContext.Provider value={ledStripConfigurationContextValue}>
|
<div>
|
||||||
<LedStripPartsSorter />
|
<a href="/led-strips-configuration">灯条配置</a>
|
||||||
<DisplayListContainer>
|
<a href="/white-balance">白平衡</a>
|
||||||
{displayStore.displays.map((display) => {
|
</div>
|
||||||
return <DisplayView display={display} />;
|
<Routes>
|
||||||
})}
|
<Route path="/led-strips-configuration" component={LedStripConfiguration} />
|
||||||
</DisplayListContainer>
|
<Route path="/white-balance" component={WhiteBalance} />
|
||||||
</LedStripConfigurationContext.Provider>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, JSX, ParentComponent, splitProps } from 'solid-js';
|
import { Component, JSX, ParentComponent, splitProps } from 'solid-js';
|
||||||
import { DisplayInfo } from '../models/display-info.model';
|
import { DisplayInfo } from '../../models/display-info.model';
|
||||||
|
|
||||||
type DisplayInfoItemProps = {
|
type DisplayInfoItemProps = {
|
||||||
label: string;
|
label: string;
|
@ -6,8 +6,8 @@ import {
|
|||||||
onMount,
|
onMount,
|
||||||
ParentComponent,
|
ParentComponent,
|
||||||
} from 'solid-js';
|
} from 'solid-js';
|
||||||
import { displayStore, setDisplayStore } from '../stores/display.store';
|
import { displayStore, setDisplayStore } from '../../stores/display.store';
|
||||||
import background from '../assets/transparent-grid-background.svg?url';
|
import background from '../../assets/transparent-grid-background.svg?url';
|
||||||
|
|
||||||
export const DisplayListContainer: ParentComponent = (props) => {
|
export const DisplayListContainer: ParentComponent = (props) => {
|
||||||
let root: HTMLElement;
|
let root: HTMLElement;
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, createMemo } 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 { displayStore } from '../../stores/display.store';
|
||||||
import { ledStripStore } from '../stores/led-strip.store';
|
import { ledStripStore } from '../../stores/led-strip.store';
|
||||||
import { DisplayInfoPanel } from './display-info-panel';
|
import { DisplayInfoPanel } from './display-info-panel';
|
||||||
import { LedStripPart } from './led-strip-part';
|
import { LedStripPart } from './led-strip-part';
|
||||||
import { ScreenView } from './screen-view';
|
import { ScreenView } from './screen-view';
|
@ -0,0 +1,106 @@
|
|||||||
|
import { createEffect, onCleanup } from 'solid-js';
|
||||||
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
import { DisplayView } from './display-view';
|
||||||
|
import { DisplayListContainer } from './display-list-container';
|
||||||
|
import { displayStore, setDisplayStore } from '../../stores/display.store';
|
||||||
|
import { LedStripConfigContainer } from '../../models/led-strip-config';
|
||||||
|
import { setLedStripStore } from '../../stores/led-strip.store';
|
||||||
|
import { listen } from '@tauri-apps/api/event';
|
||||||
|
import { LedStripPartsSorter } from './led-strip-parts-sorter';
|
||||||
|
import { createStore } from 'solid-js/store';
|
||||||
|
import {
|
||||||
|
LedStripConfigurationContext,
|
||||||
|
LedStripConfigurationContextType,
|
||||||
|
} from '../../contexts/led-strip-configuration.context';
|
||||||
|
|
||||||
|
export const LedStripConfiguration = () => {
|
||||||
|
createEffect(() => {
|
||||||
|
invoke<string>('list_display_info').then((displays) => {
|
||||||
|
setDisplayStore({
|
||||||
|
displays: JSON.parse(displays),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
invoke<LedStripConfigContainer>('read_led_strip_configs').then((configs) => {
|
||||||
|
console.log(configs);
|
||||||
|
setLedStripStore(configs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// listen to config_changed event
|
||||||
|
createEffect(() => {
|
||||||
|
const unlisten = listen('config_changed', (event) => {
|
||||||
|
const { strips, mappers } = event.payload as LedStripConfigContainer;
|
||||||
|
console.log(event.payload);
|
||||||
|
setLedStripStore({
|
||||||
|
strips,
|
||||||
|
mappers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onCleanup(() => {
|
||||||
|
unlisten.then((unlisten) => unlisten());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// listen to led_colors_changed event
|
||||||
|
createEffect(() => {
|
||||||
|
const unlisten = listen<Uint8ClampedArray>('led_colors_changed', (event) => {
|
||||||
|
if (!window.document.hidden) {
|
||||||
|
const colors = event.payload;
|
||||||
|
setLedStripStore({
|
||||||
|
colors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onCleanup(() => {
|
||||||
|
unlisten.then((unlisten) => unlisten());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// listen to led_sorted_colors_changed event
|
||||||
|
createEffect(() => {
|
||||||
|
const unlisten = listen<Uint8ClampedArray>('led_sorted_colors_changed', (event) => {
|
||||||
|
if (!window.document.hidden) {
|
||||||
|
const sortedColors = event.payload;
|
||||||
|
setLedStripStore({
|
||||||
|
sortedColors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onCleanup(() => {
|
||||||
|
unlisten.then((unlisten) => unlisten());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const [ledStripConfiguration, setLedStripConfiguration] = createStore<
|
||||||
|
LedStripConfigurationContextType[0]
|
||||||
|
>({
|
||||||
|
selectedStripPart: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ledStripConfigurationContextValue: LedStripConfigurationContextType = [
|
||||||
|
ledStripConfiguration,
|
||||||
|
{
|
||||||
|
setSelectedStripPart: (v) => {
|
||||||
|
setLedStripConfiguration({
|
||||||
|
selectedStripPart: v,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<LedStripConfigurationContext.Provider value={ledStripConfigurationContextValue}>
|
||||||
|
<LedStripPartsSorter />
|
||||||
|
<DisplayListContainer>
|
||||||
|
{displayStore.displays.map((display) => {
|
||||||
|
return <DisplayView display={display} />;
|
||||||
|
})}
|
||||||
|
</DisplayListContainer>
|
||||||
|
</LedStripConfigurationContext.Provider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -12,9 +12,9 @@ import {
|
|||||||
} from 'solid-js';
|
} from 'solid-js';
|
||||||
import { useTippy } from 'solid-tippy';
|
import { useTippy } from 'solid-tippy';
|
||||||
import { followCursor } from 'tippy.js';
|
import { followCursor } from 'tippy.js';
|
||||||
import { LedStripConfig } from '../models/led-strip-config';
|
import { LedStripConfig } from '../../models/led-strip-config';
|
||||||
import { LedStripConfigurationContext } from '../contexts/led-strip-configuration.context';
|
import { LedStripConfigurationContext } from '../../contexts/led-strip-configuration.context';
|
||||||
import { ledStripStore } from '../stores/led-strip.store';
|
import { ledStripStore } from '../../stores/led-strip.store';
|
||||||
|
|
||||||
type LedStripPartProps = {
|
type LedStripPartProps = {
|
||||||
config?: LedStripConfig | null;
|
config?: LedStripConfig | null;
|
@ -14,11 +14,11 @@ import {
|
|||||||
untrack,
|
untrack,
|
||||||
useContext,
|
useContext,
|
||||||
} from 'solid-js';
|
} from 'solid-js';
|
||||||
import { LedStripConfig, LedStripPixelMapper } from '../models/led-strip-config';
|
import { LedStripConfig, LedStripPixelMapper } from '../../models/led-strip-config';
|
||||||
import { ledStripStore } from '../stores/led-strip.store';
|
import { ledStripStore } from '../../stores/led-strip.store';
|
||||||
import { invoke } from '@tauri-apps/api';
|
import { invoke } from '@tauri-apps/api';
|
||||||
import { LedStripConfigurationContext } from '../contexts/led-strip-configuration.context';
|
import { LedStripConfigurationContext } from '../../contexts/led-strip-configuration.context';
|
||||||
import background from '../assets/transparent-grid-background.svg?url';
|
import background from '../../assets/transparent-grid-background.svg?url';
|
||||||
|
|
||||||
const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper }> = (
|
const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper }> = (
|
||||||
props,
|
props,
|
17
src/components/white-balance/color-slider.tsx
Normal file
17
src/components/white-balance/color-slider.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Component, JSX } from 'solid-js';
|
||||||
|
|
||||||
|
type Props = {} & JSX.HTMLAttributes<HTMLInputElement>;
|
||||||
|
|
||||||
|
export const ColorSlider: Component<Props> = (props) => {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
value="50"
|
||||||
|
{...props}
|
||||||
|
class={
|
||||||
|
'w-full h-2 bg-gradient-to-r rounded-lg appearance-none cursor-pointer dark:bg-gray-700 drop-shadow ' +
|
||||||
|
props.class
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
99
src/components/white-balance/test-colors-bg.tsx
Normal file
99
src/components/white-balance/test-colors-bg.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import { Component, createSignal } from 'solid-js';
|
||||||
|
|
||||||
|
const ColorItem: Component<{
|
||||||
|
color: string;
|
||||||
|
position: [number, number];
|
||||||
|
size?: [number, number];
|
||||||
|
onClick?: (color: string) => void;
|
||||||
|
}> = (props) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: props.color,
|
||||||
|
'grid-row-start': props.position[0],
|
||||||
|
'grid-column-start': props.position[1],
|
||||||
|
'grid-row-end': props.position[0] + (props.size ? props.size[0] : 1),
|
||||||
|
'grid-column-end': props.position[1] + (props.size ? props.size[1] : 1),
|
||||||
|
cursor: props.onClick ? 'pointer' : 'default',
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
props.onClick?.(props.color);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TestColorsBg: Component = () => {
|
||||||
|
const [singleColor, setSingleColor] = createSignal<string | null>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section
|
||||||
|
class="grid grid-cols-[8] grid-rows-[8] h-full w-full"
|
||||||
|
classList={{
|
||||||
|
hidden: singleColor() !== null,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ColorItem color="#ff0000" position={[1, 1]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ffff00" position={[1, 2]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#00ff00" position={[1, 3]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#00ffff" position={[1, 4]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#0000ff" position={[1, 5]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ff00ff" position={[1, 6]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ffffff" position={[1, 7]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#000000" position={[1, 8]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ffff00" position={[2, 1]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#00ff00" position={[3, 1]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#00ffff" position={[4, 1]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#0000ff" position={[5, 1]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ff00ff" position={[6, 1]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ffffff" position={[7, 1]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#000000" position={[8, 1]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ffffff" position={[2, 8]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ff00ff" position={[3, 8]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#0000ff" position={[4, 8]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#00ffff" position={[5, 8]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#00ff00" position={[6, 8]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ffff00" position={[7, 8]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ff0000" position={[8, 8]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ffffff" position={[8, 2]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ff00ff" position={[8, 3]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#0000ff" position={[8, 4]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#00ffff" position={[8, 5]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#00ff00" position={[8, 6]} onClick={setSingleColor} />
|
||||||
|
<ColorItem color="#ffff00" position={[8, 7]} onClick={setSingleColor} />
|
||||||
|
</section>
|
||||||
|
<section
|
||||||
|
class="grid grid-cols-[8] grid-rows-[8] h-full w-full"
|
||||||
|
classList={{
|
||||||
|
hidden: singleColor() === null,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ColorItem
|
||||||
|
color={singleColor()!}
|
||||||
|
position={[1, 1]}
|
||||||
|
size={[1, 7]}
|
||||||
|
onClick={() => setSingleColor(null)}
|
||||||
|
/>
|
||||||
|
<ColorItem
|
||||||
|
color={singleColor()!}
|
||||||
|
position={[8, 2]}
|
||||||
|
size={[1, 7]}
|
||||||
|
onClick={() => setSingleColor(null)}
|
||||||
|
/>
|
||||||
|
<ColorItem
|
||||||
|
color={singleColor()!}
|
||||||
|
position={[2, 1]}
|
||||||
|
size={[7, 1]}
|
||||||
|
onClick={() => setSingleColor(null)}
|
||||||
|
/>
|
||||||
|
<ColorItem
|
||||||
|
color={singleColor()!}
|
||||||
|
position={[1, 8]}
|
||||||
|
size={[7, 1]}
|
||||||
|
onClick={() => setSingleColor(null)}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
43
src/components/white-balance/white-balance.tsx
Normal file
43
src/components/white-balance/white-balance.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { ColorSlider } from './color-slider';
|
||||||
|
import { TestColorsBg } from './test-colors-bg';
|
||||||
|
|
||||||
|
export const WhiteBalance = () => {
|
||||||
|
const exit = () => {
|
||||||
|
window.history.back();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section class="select-none">
|
||||||
|
<div class="absolute top-0 left-0 right-0 bottom-0">
|
||||||
|
<TestColorsBg />
|
||||||
|
</div>
|
||||||
|
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-10/12 max-w-lg bg-stone-200 p-5 rounded-xl drop-shadow">
|
||||||
|
<label class="flex items-center gap-2">
|
||||||
|
<span class="w-3 block">R:</span>
|
||||||
|
<ColorSlider class="from-cyan-500 to-red-500" />
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center gap-2">
|
||||||
|
<span class="w-3 block">G:</span>
|
||||||
|
<ColorSlider class="from-pink-500 to-green-500" />
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center gap-2">
|
||||||
|
<span class="w-3 block">B:</span>
|
||||||
|
<ColorSlider class="from-yellow-500 to-blue-500" />
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center gap-2">
|
||||||
|
<span class="w-3 block">W:</span>
|
||||||
|
<ColorSlider class="from-yellow-50 to-cyan-50" />
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
class="absolute -right-4 -top-4 rounded-full aspect-square bg-stone-300 p-1 shadow border border-stone-400"
|
||||||
|
onClick={exit}
|
||||||
|
>
|
||||||
|
X
|
||||||
|
</button>
|
||||||
|
<button class="absolute -right-4 -bottom-4 rounded-full aspect-square bg-stone-300 p-1 shadow border border-stone-400">
|
||||||
|
R
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
@ -3,5 +3,13 @@ import { render } from "solid-js/web";
|
|||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
import { Router } from '@solidjs/router';
|
||||||
|
|
||||||
render(() => <App />, document.getElementById("root") as HTMLElement);
|
render(
|
||||||
|
() => (
|
||||||
|
<Router>
|
||||||
|
<App />
|
||||||
|
</Router>
|
||||||
|
),
|
||||||
|
document.getElementById('root') as HTMLElement,
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user