mirror of
https://github.com/4yn/slidershim.git
synced 2024-11-30 16:24:27 +01:00
add brokestalgia controller
This commit is contained in:
parent
8fbb9e4d9f
commit
d89de5e6fc
@ -3,7 +3,9 @@ extern crate slider_io;
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use slider_io::{
|
use slider_io::{
|
||||||
device::brokenithm::BrokenithmJob, shared::worker::AsyncHaltableWorker, state::SliderState,
|
device::{brokenithm::BrokenithmJob, config::BrokenithmSpec},
|
||||||
|
shared::worker::AsyncHaltableWorker,
|
||||||
|
state::SliderState,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@ -14,7 +16,10 @@ async fn main() {
|
|||||||
|
|
||||||
let state = SliderState::new();
|
let state = SliderState::new();
|
||||||
|
|
||||||
let _worker = AsyncHaltableWorker::new("brokenithm", BrokenithmJob::new(&state, &false, &false));
|
let _worker = AsyncHaltableWorker::new(
|
||||||
|
"brokenithm",
|
||||||
|
BrokenithmJob::new(&state, &BrokenithmSpec::Nostalgia, &false),
|
||||||
|
);
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
io::stdin().read_line(&mut input).unwrap();
|
io::stdin().read_line(&mut input).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -40,14 +40,14 @@ impl Context {
|
|||||||
match &config.device_mode {
|
match &config.device_mode {
|
||||||
DeviceMode::None => (None, None, None),
|
DeviceMode::None => (None, None, None),
|
||||||
DeviceMode::Brokenithm {
|
DeviceMode::Brokenithm {
|
||||||
ground_only,
|
spec,
|
||||||
lights_enabled,
|
lights_enabled,
|
||||||
} => (
|
} => (
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(AsyncHaltableWorker::new(
|
Some(AsyncHaltableWorker::new(
|
||||||
"brokenithm",
|
"brokenithm",
|
||||||
BrokenithmJob::new(&state, ground_only, lights_enabled),
|
BrokenithmJob::new(&state, spec, lights_enabled),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
DeviceMode::Hardware { spec, disable_air } => (
|
DeviceMode::Hardware { spec, disable_air } => (
|
||||||
|
File diff suppressed because one or more lines are too long
135
src-slider_io/src/device/brokenithm-www/index-ns.html
Normal file
135
src-slider_io/src/device/brokenithm-www/index-ns.html
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>slidershim-brokenithm</title>
|
||||||
|
<meta charset="utf8" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||||
|
/>
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<link rel="apple-touch-icon" sizes="192x192" href="/icon.png" />
|
||||||
|
<style>
|
||||||
|
#fullscreen {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
background: #000000;
|
||||||
|
color: hotpink;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
touch-action: none;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.air-container {
|
||||||
|
/* display: flex; */
|
||||||
|
display: none;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.touch-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grow > * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key {
|
||||||
|
flex: 1;
|
||||||
|
border: 1px solid green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key[data-active] {
|
||||||
|
background-color: hotpink;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key.air[data-active] {
|
||||||
|
background-color: skyblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
-ms-interpolation-mode: nearest-neighbor;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
touch-action: none;
|
||||||
|
margin: 0px -1.5625vw;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="fullscreen">
|
||||||
|
<!-- Offset for LED display -->
|
||||||
|
<div class="container">
|
||||||
|
<div class="air-container grow"></div>
|
||||||
|
<div class="touch-container grow">
|
||||||
|
<canvas id="canvas" width="33" height="1"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Hitbox Divs -->
|
||||||
|
<div class="container" id="main">
|
||||||
|
<div class="air-container grow">
|
||||||
|
<div class="air key" data-air="1" data-kflag="5"></div>
|
||||||
|
<div class="air key" data-air="1" data-kflag="4"></div>
|
||||||
|
<div class="air key" data-air="1" data-kflag="3"></div>
|
||||||
|
<div class="air key" data-air="1" data-kflag="2"></div>
|
||||||
|
<div class="air key" data-air="1" data-kflag="1"></div>
|
||||||
|
<div class="air key" data-air="1" data-kflag="0"></div>
|
||||||
|
</div>
|
||||||
|
<div class="touch-container grow">
|
||||||
|
<div class="key" data-kflag="0"></div>
|
||||||
|
<div class="key" data-kflag="1"></div>
|
||||||
|
<div class="key" data-kflag="2"></div>
|
||||||
|
<div class="key" data-kflag="3"></div>
|
||||||
|
<div class="key" data-kflag="4"></div>
|
||||||
|
<div class="key" data-kflag="5"></div>
|
||||||
|
<div class="key" data-kflag="6"></div>
|
||||||
|
<div class="key" data-kflag="7"></div>
|
||||||
|
<div class="key" data-kflag="8"></div>
|
||||||
|
<div class="key" data-kflag="9"></div>
|
||||||
|
<div class="key" data-kflag="10"></div>
|
||||||
|
<div class="key" data-kflag="11"></div>
|
||||||
|
<div class="key" data-kflag="12"></div>
|
||||||
|
<div class="key" data-kflag="13"></div>
|
||||||
|
<div class="key" data-kflag="14"></div>
|
||||||
|
<div class="key" data-kflag="15"></div>
|
||||||
|
<div class="key" data-kflag="16"></div>
|
||||||
|
<div class="key" data-kflag="17"></div>
|
||||||
|
<div class="key" data-kflag="18"></div>
|
||||||
|
<div class="key" data-kflag="19"></div>
|
||||||
|
<div class="key" data-kflag="20"></div>
|
||||||
|
<div class="key" data-kflag="21"></div>
|
||||||
|
<div class="key" data-kflag="22"></div>
|
||||||
|
<div class="key" data-kflag="23"></div>
|
||||||
|
<div class="key" data-kflag="24"></div>
|
||||||
|
<div class="key" data-kflag="25"></div>
|
||||||
|
<div class="key" data-kflag="26"></div>
|
||||||
|
<div class="key" data-kflag="27"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="/config.js"></script>
|
||||||
|
<script>
|
||||||
|
var allAir = true;
|
||||||
|
</script>
|
||||||
|
<script src="/app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -46,7 +46,7 @@ const compileKey = (key) => {
|
|||||||
almostLeft: !!prev ? key.offsetLeft + key.offsetWidth / 4 : -99999,
|
almostLeft: !!prev ? key.offsetLeft + key.offsetWidth / 4 : -99999,
|
||||||
almostRight: !!next ? key.offsetLeft + (key.offsetWidth * 3) / 4 : 99999,
|
almostRight: !!next ? key.offsetLeft + (key.offsetWidth * 3) / 4 : 99999,
|
||||||
kflag: parseInt(key.dataset.kflag) + (parseInt(key.dataset.air) ? 32 : 0),
|
kflag: parseInt(key.dataset.kflag) + (parseInt(key.dataset.air) ? 32 : 0),
|
||||||
isAir: parseInt(key.dataset.air) ? true : false,
|
isAir: parseInt(key.dataset.air) ? true : window.allAir || false,
|
||||||
prevKeyRef: prev,
|
prevKeyRef: prev,
|
||||||
prevKeyKflag: prev
|
prevKeyKflag: prev
|
||||||
? parseInt(prev.dataset.kflag) + (parseInt(prev.dataset.air) ? 32 : 0)
|
? parseInt(prev.dataset.kflag) + (parseInt(prev.dataset.air) ? 32 : 0)
|
||||||
@ -70,9 +70,9 @@ const compileKeys = () => {
|
|||||||
keys = document.getElementsByClassName("key");
|
keys = document.getElementsByClassName("key");
|
||||||
airKeys = [];
|
airKeys = [];
|
||||||
touchKeys = [];
|
touchKeys = [];
|
||||||
for (var i = 0, key; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
const compiledKey = compileKey(keys[i]);
|
const compiledKey = compileKey(keys[i]);
|
||||||
if (!compiledKey.isAir) {
|
if (compiledKey.kflag < 32) {
|
||||||
touchKeys.push(compiledKey);
|
touchKeys.push(compiledKey);
|
||||||
} else {
|
} else {
|
||||||
airKeys.push(compiledKey);
|
airKeys.push(compiledKey);
|
||||||
@ -80,6 +80,38 @@ const compileKeys = () => {
|
|||||||
allKeys.push(compiledKey);
|
allKeys.push(compiledKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
touchKeys.memo = {};
|
||||||
|
airKeys.memo = {};
|
||||||
|
|
||||||
|
touchKeys.getAxis = (x, y) => x;
|
||||||
|
airKeys.getAxis = (x, y) => y;
|
||||||
|
|
||||||
|
var getKey = function (x, y) {
|
||||||
|
var c = this.getAxis(x, y);
|
||||||
|
var res = this.memo[c];
|
||||||
|
if (res === undefined) {
|
||||||
|
for (var i = 0; i < this.length; i++) {
|
||||||
|
if (isInside(x, y, this[i])) {
|
||||||
|
res = this[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.memo[c] = res;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
touchKeys.getKey = getKey;
|
||||||
|
airKeys.getKey = getKey;
|
||||||
|
|
||||||
|
for (var i = 0; i < window.outerWidth; i++) {
|
||||||
|
touchKeys.getKey(i, touchKeys[0].top);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < window.outerHeight; i++) {
|
||||||
|
airKeys.getKey(airKeys[0].left, i);
|
||||||
|
}
|
||||||
|
|
||||||
if (!config.invert) {
|
if (!config.invert) {
|
||||||
// Not inverted
|
// Not inverted
|
||||||
topKeys = airKeys;
|
topKeys = airKeys;
|
||||||
@ -95,15 +127,9 @@ const compileKeys = () => {
|
|||||||
|
|
||||||
const getKey = (x, y) => {
|
const getKey = (x, y) => {
|
||||||
if (y < midline) {
|
if (y < midline) {
|
||||||
for (var i = 0; i < topKeys.length; i++) {
|
return topKeys.getKey(x, y);
|
||||||
if (isInside(x, y, topKeys[i])) return topKeys[i];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (var i = 0; i < bottomKeys.length; i++) {
|
return bottomKeys.getKey(x, y);
|
||||||
if (isInside(x, y, bottomKeys[i])) {
|
|
||||||
return bottomKeys[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
@ -241,9 +267,9 @@ const updateLed = (data) => {
|
|||||||
canvasData.data[i * 4 + 5] = buf[i * 3 + 1]; // g
|
canvasData.data[i * 4 + 5] = buf[i * 3 + 1]; // g
|
||||||
canvasData.data[i * 4 + 6] = buf[i * 3 + 2]; // b
|
canvasData.data[i * 4 + 6] = buf[i * 3 + 2]; // b
|
||||||
}
|
}
|
||||||
canvasData.data[0] = buf[0]
|
canvasData.data[0] = buf[0];
|
||||||
canvasData.data[1] = buf[1]
|
canvasData.data[1] = buf[1];
|
||||||
canvasData.data[2] = buf[2]
|
canvasData.data[2] = buf[2];
|
||||||
canvasData.data[128] = buf[90];
|
canvasData.data[128] = buf[90];
|
||||||
canvasData.data[129] = buf[91];
|
canvasData.data[129] = buf[91];
|
||||||
canvasData.data[130] = buf[92];
|
canvasData.data[130] = buf[92];
|
||||||
|
@ -18,7 +18,7 @@ use tokio::{
|
|||||||
use tokio_tungstenite::WebSocketStream;
|
use tokio_tungstenite::WebSocketStream;
|
||||||
use tungstenite::{handshake, Message};
|
use tungstenite::{handshake, Message};
|
||||||
|
|
||||||
use crate::{shared::worker::AsyncHaltableJob, state::SliderState};
|
use crate::{device::config::BrokenithmSpec, shared::worker::AsyncHaltableJob, state::SliderState};
|
||||||
|
|
||||||
// https://levelup.gitconnected.com/handling-websocket-and-http-on-the-same-port-with-rust-f65b770722c9
|
// https://levelup.gitconnected.com/handling-websocket-and-http-on-the-same-port-with-rust-f65b770722c9
|
||||||
|
|
||||||
@ -36,6 +36,7 @@ async fn error_response() -> Result<Response<Body>, Infallible> {
|
|||||||
static BROKENITHM_STR_FILES: phf::Map<&'static str, (&'static str, &'static str)> = phf_map! {
|
static BROKENITHM_STR_FILES: phf::Map<&'static str, (&'static str, &'static str)> = phf_map! {
|
||||||
"app.js" => (include_str!("./brokenithm-www/app.js"), "text/javascript"),
|
"app.js" => (include_str!("./brokenithm-www/app.js"), "text/javascript"),
|
||||||
"config.js" => (include_str!("./brokenithm-www/config.js"), "text/javascript"),
|
"config.js" => (include_str!("./brokenithm-www/config.js"), "text/javascript"),
|
||||||
|
"index-ns.html" => (include_str!("./brokenithm-www/index-ns.html"), "text/html"),
|
||||||
"index-go.html" => (include_str!("./brokenithm-www/index-go.html"), "text/html"),
|
"index-go.html" => (include_str!("./brokenithm-www/index-go.html"), "text/html"),
|
||||||
"index.html" => (include_str!("./brokenithm-www/index.html"), "text/html"),
|
"index.html" => (include_str!("./brokenithm-www/index.html"), "text/html"),
|
||||||
};
|
};
|
||||||
@ -234,7 +235,7 @@ async fn handle_request(
|
|||||||
request: Request<Body>,
|
request: Request<Body>,
|
||||||
remote_addr: SocketAddr,
|
remote_addr: SocketAddr,
|
||||||
state: SliderState,
|
state: SliderState,
|
||||||
ground_only: bool,
|
spec: BrokenithmSpec,
|
||||||
lights_enabled: bool,
|
lights_enabled: bool,
|
||||||
) -> Result<Response<Body>, Infallible> {
|
) -> Result<Response<Body>, Infallible> {
|
||||||
let method = request.method();
|
let method = request.method();
|
||||||
@ -252,9 +253,10 @@ async fn handle_request(
|
|||||||
request.uri().path(),
|
request.uri().path(),
|
||||||
request.headers().contains_key(header::UPGRADE),
|
request.headers().contains_key(header::UPGRADE),
|
||||||
) {
|
) {
|
||||||
("/", false) | ("/index.html", false) => match ground_only {
|
("/", false) | ("/index.html", false) => match spec {
|
||||||
false => serve_file("index.html").await,
|
BrokenithmSpec::Basic => serve_file("index.html").await,
|
||||||
true => serve_file("index-go.html").await,
|
BrokenithmSpec::GroundOnly => serve_file("index-go.html").await,
|
||||||
|
BrokenithmSpec::Nostalgia => serve_file("index-ns.html").await,
|
||||||
},
|
},
|
||||||
(filename, false) => serve_file(&filename[1..]).await,
|
(filename, false) => serve_file(&filename[1..]).await,
|
||||||
("/ws", true) => handle_websocket(request, state, lights_enabled).await,
|
("/ws", true) => handle_websocket(request, state, lights_enabled).await,
|
||||||
@ -264,15 +266,15 @@ async fn handle_request(
|
|||||||
|
|
||||||
pub struct BrokenithmJob {
|
pub struct BrokenithmJob {
|
||||||
state: SliderState,
|
state: SliderState,
|
||||||
ground_only: bool,
|
spec: BrokenithmSpec,
|
||||||
lights_enabled: bool,
|
lights_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BrokenithmJob {
|
impl BrokenithmJob {
|
||||||
pub fn new(state: &SliderState, ground_only: &bool, lights_enabled: &bool) -> Self {
|
pub fn new(state: &SliderState, spec: &BrokenithmSpec, lights_enabled: &bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
ground_only: *ground_only,
|
spec: spec.clone(),
|
||||||
lights_enabled: *lights_enabled,
|
lights_enabled: *lights_enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,15 +284,17 @@ impl BrokenithmJob {
|
|||||||
impl AsyncHaltableJob for BrokenithmJob {
|
impl AsyncHaltableJob for BrokenithmJob {
|
||||||
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
|
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
|
||||||
let state = self.state.clone();
|
let state = self.state.clone();
|
||||||
let ground_only = self.ground_only;
|
let spec = self.spec.clone();
|
||||||
let lights_enabled = self.lights_enabled;
|
let lights_enabled = self.lights_enabled;
|
||||||
let make_svc = make_service_fn(|conn: &AddrStream| {
|
let make_svc = make_service_fn(|conn: &AddrStream| {
|
||||||
let remote_addr = conn.remote_addr();
|
let remote_addr = conn.remote_addr();
|
||||||
let make_svc_state = state.clone();
|
let make_svc_state = state.clone();
|
||||||
|
let make_spec = spec.clone();
|
||||||
async move {
|
async move {
|
||||||
Ok::<_, Infallible>(service_fn(move |request: Request<Body>| {
|
Ok::<_, Infallible>(service_fn(move |request: Request<Body>| {
|
||||||
let svc_state = make_svc_state.clone();
|
let svc_state = make_svc_state.clone();
|
||||||
handle_request(request, remote_addr, svc_state, ground_only, lights_enabled)
|
let spec = make_spec.clone();
|
||||||
|
handle_request(request, remote_addr, svc_state, spec, lights_enabled)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -7,6 +7,13 @@ pub enum HardwareSpec {
|
|||||||
Yuancon,
|
Yuancon,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum BrokenithmSpec {
|
||||||
|
Basic,
|
||||||
|
GroundOnly,
|
||||||
|
Nostalgia,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum DeviceMode {
|
pub enum DeviceMode {
|
||||||
None,
|
None,
|
||||||
@ -15,7 +22,7 @@ pub enum DeviceMode {
|
|||||||
disable_air: bool,
|
disable_air: bool,
|
||||||
},
|
},
|
||||||
Brokenithm {
|
Brokenithm {
|
||||||
ground_only: bool,
|
spec: BrokenithmSpec,
|
||||||
lights_enabled: bool,
|
lights_enabled: bool,
|
||||||
},
|
},
|
||||||
DivaSlider {
|
DivaSlider {
|
||||||
@ -45,13 +52,23 @@ impl DeviceMode {
|
|||||||
brightness: u8::try_from(v["divaBrightness"].as_i64()?).ok()?,
|
brightness: u8::try_from(v["divaBrightness"].as_i64()?).ok()?,
|
||||||
},
|
},
|
||||||
"brokenithm" => DeviceMode::Brokenithm {
|
"brokenithm" => DeviceMode::Brokenithm {
|
||||||
ground_only: v["disableAirStrings"].as_bool()?,
|
spec: match v["disableAirStrings"].as_bool()? {
|
||||||
|
false => BrokenithmSpec::Basic,
|
||||||
|
true => BrokenithmSpec::GroundOnly,
|
||||||
|
},
|
||||||
lights_enabled: false,
|
lights_enabled: false,
|
||||||
},
|
},
|
||||||
"brokenithm-led" => DeviceMode::Brokenithm {
|
"brokenithm-led" => DeviceMode::Brokenithm {
|
||||||
ground_only: v["disableAirStrings"].as_bool()?,
|
spec: match v["disableAirStrings"].as_bool()? {
|
||||||
|
false => BrokenithmSpec::Basic,
|
||||||
|
true => BrokenithmSpec::GroundOnly,
|
||||||
|
},
|
||||||
lights_enabled: true,
|
lights_enabled: true,
|
||||||
},
|
},
|
||||||
|
"brokenithm-nostalgia" => DeviceMode::Brokenithm {
|
||||||
|
spec: BrokenithmSpec::Nostalgia,
|
||||||
|
lights_enabled: false,
|
||||||
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -177,10 +177,11 @@
|
|||||||
<option value="diva">Slider over Serial</option>
|
<option value="diva">Slider over Serial</option>
|
||||||
<option value="brokenithm">Brokenithm</option>
|
<option value="brokenithm">Brokenithm</option>
|
||||||
<option value="brokenithm-led">Brokenithm + Led</option>
|
<option value="brokenithm-led">Brokenithm + Led</option>
|
||||||
|
<option value="brokenithm-nostalgia">Brokestalgia (28k)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if deviceMode.slice(0, 8) === "tasoller" || deviceMode.slice(0, 7) === "yuancon" || deviceMode.slice(0, 10) === "brokenithm"}
|
{#if deviceMode.slice(0, 8) === "tasoller" || deviceMode.slice(0, 7) === "yuancon" || (deviceMode.slice(0, 10) === "brokenithm" && deviceMode !== "brokenithm-nostalgia")}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="label" />
|
<div class="label" />
|
||||||
<div class="input">
|
<div class="input">
|
||||||
|
Loading…
Reference in New Issue
Block a user