mirror of
https://github.com/4yn/slidershim.git
synced 2024-11-14 09:47:40 +01:00
basic ui
This commit is contained in:
parent
08186c0fc1
commit
511a6a605d
@ -2,62 +2,131 @@ html, body {
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
background-color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #ddd;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
color: #333;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 8px;
|
padding: 1rem;
|
||||||
box-sizing: border-box;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
.main {
|
||||||
color: rgb(0,100,200);
|
display: flex;
|
||||||
text-decoration: none;
|
flex-flow: column nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
.header {
|
||||||
text-decoration: underline;
|
font-size: 2rem;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:visited {
|
.row, .row-2 {
|
||||||
color: rgb(0,80,160);
|
margin: 0 0 0.5rem 0;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
.row .label {
|
||||||
display: block;
|
flex: 1 1 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
input, button, select, textarea {
|
.row .input {
|
||||||
font-family: inherit;
|
flex: 2 2 0;
|
||||||
font-size: inherit;
|
|
||||||
-webkit-padding: 0.4em 0;
|
|
||||||
padding: 0.4em;
|
|
||||||
margin: 0 0 0.5em 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input:disabled {
|
input, select {
|
||||||
color: #ccc;
|
width: 100%;
|
||||||
|
background-color: #444;
|
||||||
|
color: #ddd;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
color: #333;
|
font-size: 1rem;
|
||||||
background-color: #f4f4f4;
|
margin: 0.25rem;
|
||||||
outline: none;
|
padding: 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
border: none;
|
||||||
|
background-color: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:disabled {
|
button:hover {
|
||||||
color: #999;
|
background: #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:not(:disabled):active {
|
button:active {
|
||||||
background-color: #ddd;
|
background: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:focus {
|
.preview {
|
||||||
border-color: #666;
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground {
|
||||||
|
position: relative;
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground-btn, .ground-led {
|
||||||
|
height: 3rem;
|
||||||
|
position:absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground-row {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground-btn > .ground-row > div {
|
||||||
|
text-align: center;
|
||||||
|
flex: 1 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground-led-0 {
|
||||||
|
flex: 1 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground-led-1 {
|
||||||
|
flex: 0.4rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground-led-2 {
|
||||||
|
flex: 0.2rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground-btn {
|
||||||
|
background-color: #0008;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ground-data {
|
||||||
|
padding: 0.1rem 0;
|
||||||
|
font-size: 0.8rem;
|
||||||
}
|
}
|
@ -4,9 +4,21 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
CustomMenuItem, Event, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu,
|
AppHandle, CustomMenuItem, Event, Manager, Runtime, SystemTray, SystemTrayEvent, SystemTrayMenu,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn show_window<R: Runtime>(handle: &AppHandle<R>) {
|
||||||
|
handle.get_window("main").unwrap().show().ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide_window<R: Runtime>(handle: &AppHandle<R>) {
|
||||||
|
handle.get_window("main").unwrap().hide().ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quit_app() {
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.system_tray(
|
.system_tray(
|
||||||
@ -17,26 +29,20 @@ fn main() {
|
|||||||
.add_item(CustomMenuItem::new("quit".to_string(), "Quit")),
|
.add_item(CustomMenuItem::new("quit".to_string(), "Quit")),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.on_system_tray_event(|app, event| match event {
|
.on_system_tray_event(|app_handle, event| match event {
|
||||||
SystemTrayEvent::LeftClick {
|
SystemTrayEvent::LeftClick {
|
||||||
position: _,
|
position: _,
|
||||||
size: _,
|
size: _,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
app
|
show_window(app_handle);
|
||||||
.get_window("main")
|
|
||||||
.unwrap()
|
|
||||||
.show().ok();
|
|
||||||
}
|
}
|
||||||
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
|
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
|
||||||
"show" => {
|
"show" => {
|
||||||
app
|
show_window(app_handle);
|
||||||
.get_window("main")
|
|
||||||
.unwrap()
|
|
||||||
.show().ok();
|
|
||||||
}
|
}
|
||||||
"quit" => {
|
"quit" => {
|
||||||
std::process::exit(0);
|
quit_app();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("Unexpected menu item click {}", id.as_str());
|
panic!("Unexpected menu item click {}", id.as_str());
|
||||||
@ -44,15 +50,28 @@ fn main() {
|
|||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
})
|
})
|
||||||
|
.setup(|app| {
|
||||||
|
app.listen_global("setConfig", |event| {
|
||||||
|
println!("Setting config to {}", event.payload().unwrap());
|
||||||
|
});
|
||||||
|
|
||||||
|
let handle = app.handle();
|
||||||
|
app.listen_global("hide", move |_| {
|
||||||
|
hide_window(&handle);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen_global("quit", |_| {
|
||||||
|
quit_app();
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
.build(tauri::generate_context!())
|
.build(tauri::generate_context!())
|
||||||
.expect("error while running tauri application")
|
.expect("error while running tauri application")
|
||||||
.run(|app_handle, event| match event {
|
.run(|app_handle, event| match event {
|
||||||
Event::CloseRequested { label, api, .. } if label.as_str() == "main" => {
|
Event::CloseRequested { label, api, .. } if label.as_str() == "main" => {
|
||||||
api.prevent_close();
|
api.prevent_close();
|
||||||
app_handle
|
hide_window(app_handle);
|
||||||
.get_window("main")
|
|
||||||
.unwrap()
|
|
||||||
.hide().ok();
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
});
|
});
|
||||||
|
@ -54,8 +54,8 @@
|
|||||||
"windows": [
|
"windows": [
|
||||||
{
|
{
|
||||||
"title": "slidershim",
|
"title": "slidershim",
|
||||||
"width": 800,
|
"width": 500,
|
||||||
"height": 600,
|
"height": 400,
|
||||||
"resizable": false,
|
"resizable": false,
|
||||||
"fullscreen": false
|
"fullscreen": false
|
||||||
}
|
}
|
||||||
|
164
src/App.svelte
164
src/App.svelte
@ -1,30 +1,148 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let name: string;
|
import { onMount } from "svelte";
|
||||||
|
import { emit, listen } from "@tauri-apps/api/event";
|
||||||
|
|
||||||
|
import Preview from "./Preview.svelte"
|
||||||
|
|
||||||
|
let deviceMode = "none";
|
||||||
|
let outputMode = "none";
|
||||||
|
let lightingMode = "none";
|
||||||
|
|
||||||
|
let keyboardSensitivity = 20;
|
||||||
|
let websocketOutputUrl = "http://localhost:3000";
|
||||||
|
let websocketLedUrl = "http://localhost:3001";
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
await listen("showConfig", (event) => {
|
||||||
|
const payload: any = event.payload;
|
||||||
|
deviceMode = payload.deviceMode;
|
||||||
|
outputMode = payload.outputMode;
|
||||||
|
lightingMode = payload.lightingMode;
|
||||||
|
keyboardSensitivity = payload.keyboardSensitivity;
|
||||||
|
websocketOutputUrl = payload.websocketOutputUrl;
|
||||||
|
websocketLedUrl = payload.websocketLedUrl;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
async function setConfig() {
|
||||||
|
console.log("Updating config");
|
||||||
|
await emit("setConfig", JSON.stringify({
|
||||||
|
deviceMode,
|
||||||
|
outputMode,
|
||||||
|
lightingMode,
|
||||||
|
keyboardSensitivity,
|
||||||
|
websocketOutputUrl,
|
||||||
|
websocketLedUrl
|
||||||
|
}));
|
||||||
|
console.log("Done");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hide() {
|
||||||
|
await emit("hide", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
async function quit() {
|
||||||
|
await emit("quit", "")
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main class="main">
|
||||||
<h1>Hello {name}!</h1>
|
<div class="row">
|
||||||
<p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
|
<div class="header">
|
||||||
|
slidershim
|
||||||
|
<!-- slidershim by @4yn -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<Preview />
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="label">Input Device</div>
|
||||||
|
<div class="input">
|
||||||
|
<select bind:value={deviceMode}>
|
||||||
|
<option value="none">None</option>
|
||||||
|
<option value="tasoller">GAMO2 Tasoller, HID Firmware</option>
|
||||||
|
<option value="yuancon">Yuancon Laverita, HID Firmware</option>
|
||||||
|
<option value="brokenithm">Brokenithm</option>
|
||||||
|
<option value="brokenithm-ground">Brokenithm, Ground only</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="label">Output Mode</div>
|
||||||
|
<div class="input">
|
||||||
|
<select bind:value={outputMode}>
|
||||||
|
<option value="none">None</option>
|
||||||
|
<option value="kb-32-tasoller">Keyboard 32-zone, Tasoller Layout</option
|
||||||
|
>
|
||||||
|
<option value="kb-32-yuancon">Keyboard 32-zone, Yuancon Layout</option>
|
||||||
|
<option value="kb-6-deemo">Keyboard 6-zone, Deemo Layout</option>
|
||||||
|
<option value="websocket">Websocket</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if outputMode.slice(0, 2) === "kb"}
|
||||||
|
<div class="row">
|
||||||
|
<div class="label">Sensitivity</div>
|
||||||
|
<div class="input">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="255"
|
||||||
|
step="1"
|
||||||
|
bind:value={keyboardSensitivity}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="label"></div>
|
||||||
|
<div class="input">
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="1"
|
||||||
|
max="255"
|
||||||
|
step="1"
|
||||||
|
bind:value={keyboardSensitivity}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if outputMode === "websocket"}
|
||||||
|
<div class="row">
|
||||||
|
<div class="label">Output URL</div>
|
||||||
|
<div class="input">
|
||||||
|
<input placeholder="URL" bind:value={websocketOutputUrl} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="row">
|
||||||
|
<div class="label">LED Mode</div>
|
||||||
|
<div class="input">
|
||||||
|
<select bind:value={lightingMode}>
|
||||||
|
<option value="none">None</option>
|
||||||
|
<option value="reactive-4">Reactive, 4-Zone</option>
|
||||||
|
<option value="reactive-8">Reactive, 8-Zone</option>
|
||||||
|
<option value="reactive-16">Reactive, 16-Zone</option>
|
||||||
|
<option value="attract">Rainbow Attract Mode</option>
|
||||||
|
<option value="test">LED Test</option>
|
||||||
|
<option value="websocket">Websocket</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if lightingMode === "websocket"}
|
||||||
|
<div class="row">
|
||||||
|
<div class="label">LED URL</div>
|
||||||
|
<div class="input">
|
||||||
|
<input placeholder="URL" bind:value={websocketLedUrl} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="row">
|
||||||
|
<button on:click={async () => await setConfig()}>Apply</button>
|
||||||
|
<button on:click={async () => await hide()}>Hide</button>
|
||||||
|
<button on:click={async () => await quit()}>Quit</button>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
main {
|
|
||||||
text-align: center;
|
|
||||||
padding: 1em;
|
|
||||||
max-width: 240px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #ff3e00;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 4em;
|
|
||||||
font-weight: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 640px) {
|
|
||||||
main {
|
|
||||||
max-width: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
35
src/Preview.svelte
Normal file
35
src/Preview.svelte
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let topDatas = Array(16).fill(0);
|
||||||
|
let botDatas = Array(16).fill(0);
|
||||||
|
let ledDatas = Array(31).fill(0).map((_, idx) => ({
|
||||||
|
color: !!(idx % 2) ? "f0f" : "ff0",
|
||||||
|
spec: idx % 2
|
||||||
|
}))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<main class="preview">
|
||||||
|
<div class="air"></div>
|
||||||
|
<div class="ground">
|
||||||
|
<div class="ground-led">
|
||||||
|
<div class="ground-row">
|
||||||
|
<div class="ground-led-2"></div>
|
||||||
|
{#each ledDatas as {color, spec}, idx (idx)}
|
||||||
|
<div class={`ground-led-${spec}`} style={`background-color: #${color}`}></div>
|
||||||
|
{/each}
|
||||||
|
<div class="ground-led-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ground-btn">
|
||||||
|
<div class="ground-row">
|
||||||
|
{#each topDatas as topData, idx (idx)}
|
||||||
|
<div class="ground-data">{topData}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="ground-row">
|
||||||
|
{#each botDatas as botData, idx (idx)}
|
||||||
|
<div class="ground-data">{botData}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
@ -1,10 +1,7 @@
|
|||||||
import App from './App.svelte';
|
import App from './App.svelte';
|
||||||
|
|
||||||
const app = new App({
|
const app = new App({
|
||||||
target: document.body,
|
target: document.body
|
||||||
props: {
|
|
||||||
name: 'world'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default app;
|
export default app;
|
Loading…
Reference in New Issue
Block a user