1
0
mirror of https://github.com/4yn/slidershim.git synced 2024-11-14 09:47:40 +01:00
This commit is contained in:
4yn 2022-01-28 00:31:41 +08:00
parent 08186c0fc1
commit 511a6a605d
6 changed files with 320 additions and 82 deletions

View File

@ -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;
} }

View File

@ -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();
} }
_ => {} _ => {}
}); });

View File

@ -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
} }

View File

@ -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
View 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>

View File

@ -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;