mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-04-19 20:59:00 +00:00
feat: enable stricter type checking options
feat: make the app more fault tolerant
This commit is contained in:
@@ -22,8 +22,7 @@
|
|||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
"test": "vitest run --coverage",
|
"test": "vitest run --coverage",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
|
|
||||||
"minify-icons": "node src/tools/minify-icon-font.js",
|
"minify-icons": "node src/tools/minify-icon-font.js",
|
||||||
"version": "node src/tools/version.js && git add src-tauri/Cargo.toml && git add src-tauri/tauri.conf.json",
|
"version": "node src/tools/version.js && git add src-tauri/Cargo.toml && git add src-tauri/tauri.conf.json",
|
||||||
"lint": "prettier --check .",
|
"lint": "prettier --check .",
|
||||||
|
|||||||
2
src/env.d.ts
vendored
2
src/env.d.ts
vendored
@@ -11,7 +11,7 @@ interface ImportMetaEnv {
|
|||||||
readonly VITE_HOMEPAGE_URL: string;
|
readonly VITE_HOMEPAGE_URL: string;
|
||||||
readonly VITE_BUGS_URL: string;
|
readonly VITE_BUGS_URL: string;
|
||||||
readonly VITE_DOCS_URL: string;
|
readonly VITE_DOCS_URL: string;
|
||||||
readonly VIET_LEARN_URL: string;
|
readonly VITE_LEARN_URL: string;
|
||||||
readonly VITE_LATEST_FIRMWARE: string;
|
readonly VITE_LATEST_FIRMWARE: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { FormattersInitializer } from "typesafe-i18n";
|
|||||||
import type { Locales, Formatters } from "./i18n-types";
|
import type { Locales, Formatters } from "./i18n-types";
|
||||||
|
|
||||||
export const initFormatters: FormattersInitializer<Locales, Formatters> = (
|
export const initFormatters: FormattersInitializer<Locales, Formatters> = (
|
||||||
locale: Locales,
|
_locale: Locales,
|
||||||
) => {
|
) => {
|
||||||
const formatters: Formatters = {
|
const formatters: Formatters = {
|
||||||
// add your formatter functions here
|
// add your formatter functions here
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ export function restoreFromFile(
|
|||||||
switch (file.type) {
|
switch (file.type) {
|
||||||
case "backup": {
|
case "backup": {
|
||||||
const recent = file.history[0];
|
const recent = file.history[0];
|
||||||
|
if (!recent) return;
|
||||||
if (recent[1].device !== get(serialPort)?.device) {
|
if (recent[1].device !== get(serialPort)?.device) {
|
||||||
alert("Backup is incompatible with this device");
|
alert("Backup is incompatible with this device");
|
||||||
throw new Error("Backup is incompatible with this device");
|
throw new Error("Backup is incompatible with this device");
|
||||||
@@ -177,7 +178,7 @@ export function getChangesFromLayoutFile(file: CharaLayoutFile) {
|
|||||||
const changes: Change[] = [];
|
const changes: Change[] = [];
|
||||||
for (const [layer, keys] of file.layout.entries()) {
|
for (const [layer, keys] of file.layout.entries()) {
|
||||||
for (const [id, action] of keys.entries()) {
|
for (const [id, action] of keys.entries()) {
|
||||||
if (get(layout)[layer][id].action !== action) {
|
if (get(layout)[layer]?.[id]?.action !== action) {
|
||||||
changes.push({
|
changes.push({
|
||||||
type: ChangeType.Layout,
|
type: ChangeType.Layout,
|
||||||
layer,
|
layer,
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ export function csvChordsToJson(csv: string): CharaChordFile {
|
|||||||
.map((line) => {
|
.map((line) => {
|
||||||
const [input, output] = line.split(/,(?=[^,]*$)/, 2);
|
const [input, output] = line.split(/,(?=[^,]*$)/, 2);
|
||||||
return [
|
return [
|
||||||
input
|
input!
|
||||||
.split("+")
|
.split("+")
|
||||||
.map((it) => KEYMAP_IDS.get(it.trim())?.code ?? 0)
|
.map((it) => KEYMAP_IDS.get(it.trim())?.code ?? 0)
|
||||||
.sort((a, b) => a - b),
|
.sort((a, b) => a - b),
|
||||||
output
|
output!
|
||||||
.trim()
|
.trim()
|
||||||
.split("")
|
.split("")
|
||||||
.map((it) => KEYMAP_IDS.get(SPECIAL_KEYS.get(it) ?? it)?.code ?? 0),
|
.map((it) => KEYMAP_IDS.get(SPECIAL_KEYS.get(it) ?? it)?.code ?? 0),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export function csvLayoutToJson(
|
|||||||
for (const layer of csv.trim().split("\n")) {
|
for (const layer of csv.trim().split("\n")) {
|
||||||
const [layerId, key, action] = layer.substring(1).split(",").map(Number);
|
const [layerId, key, action] = layer.substring(1).split(",").map(Number);
|
||||||
|
|
||||||
layout.layout[Number(layerId) - 1][Number(key)] = Number(action);
|
layout.layout[Number(layerId) - 1]![Number(key)] = Number(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
$: info =
|
$: info =
|
||||||
typeof action === "number"
|
typeof action === "number"
|
||||||
? KEYMAP_CODES[action] ?? { code: action }
|
? KEYMAP_CODES.get(action) ?? { code: action }
|
||||||
: action;
|
: action;
|
||||||
$: dynamicMapping = info.keyCode && $osLayout.get(info.keyCode);
|
$: dynamicMapping = info.keyCode && $osLayout.get(info.keyCode);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
export let id: number | KeyInfo;
|
export let id: number | KeyInfo;
|
||||||
|
|
||||||
$: key = (typeof id === "number" ? KEYMAP_CODES[id] ?? id : id) as
|
$: key = (typeof id === "number" ? KEYMAP_CODES.get(id) ?? id : id) as
|
||||||
| number
|
| number
|
||||||
| KeyInfo;
|
| KeyInfo;
|
||||||
</script>
|
</script>
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
{#if key.description}
|
{#if key.description}
|
||||||
<i>{key.description}</i>
|
<i>{key.description}</i>
|
||||||
{/if}
|
{/if}
|
||||||
{#if key.category.name === "ASCII Macros"}
|
{#if key.category?.name === "ASCII Macros"}
|
||||||
<span class="warning">{@html $LL.actionSearch.SHIFT_WARNING()}</span>
|
<span class="warning">{@html $LL.actionSearch.SHIFT_WARNING()}</span>
|
||||||
{/if}
|
{/if}
|
||||||
{#if key.category.name === "CP-1252"}
|
{#if key.category?.name === "CP-1252"}
|
||||||
<span class="warning">{@html $LL.actionSearch.ALT_CODE_WARNING()}</span>
|
<span class="warning">{@html $LL.actionSearch.ALT_CODE_WARNING()}</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
// @ts-expect-error no types here
|
||||||
import { useRegisterSW } from "virtual:pwa-register/svelte";
|
import { useRegisterSW } from "virtual:pwa-register/svelte";
|
||||||
|
|
||||||
const { needRefresh, updateServiceWorker, offlineReady } = useRegisterSW();
|
const { needRefresh, updateServiceWorker, offlineReady } = useRegisterSW();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
function submit(event: Event) {
|
function submit(event: Event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
$serialPort.send(value.trim());
|
$serialPort?.send(0, value.trim());
|
||||||
value = "";
|
value = "";
|
||||||
io.scrollTo({ top: io.scrollHeight });
|
io.scrollTo({ top: io.scrollHeight });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
function search() {
|
function search() {
|
||||||
results = index!.search(searchBox.value);
|
results = index!.search(searchBox.value) as number[];
|
||||||
exact = exactIndex[searchBox.value]?.code;
|
exact = exactIndex[searchBox.value]?.code;
|
||||||
code = Number(searchBox.value);
|
code = Number(searchBox.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,9 +121,11 @@
|
|||||||
|
|
||||||
function edit(index: number) {
|
function edit(index: number) {
|
||||||
const keyInfo = layoutInfo.keys[index];
|
const keyInfo = layoutInfo.keys[index];
|
||||||
|
if (!keyInfo) return;
|
||||||
const clickedGroup = groupParent.children.item(index) as SVGGElement;
|
const clickedGroup = groupParent.children.item(index) as SVGGElement;
|
||||||
const nextAction = get(layout)[get(activeLayer)][keyInfo.id];
|
const nextAction = get(layout)[get(activeLayer)]?.[keyInfo.id];
|
||||||
const currentAction = get(deviceLayout)[get(activeLayer)][keyInfo.id];
|
const currentAction = get(deviceLayout)[get(activeLayer)]?.[keyInfo.id];
|
||||||
|
if (!nextAction || !currentAction) return;
|
||||||
const component = new ActionSelector({
|
const component = new ActionSelector({
|
||||||
target: document.body,
|
target: document.body,
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -23,13 +23,12 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each positions as position, layer}
|
{#each positions as position, layer}
|
||||||
{@const { action: actionId, isApplied } = $layout[layer][key.id] ?? {
|
{@const { action: actionId, isApplied } = $layout[layer]?.[key.id] ?? {
|
||||||
action: 0,
|
action: 0,
|
||||||
isApplied: true,
|
isApplied: true,
|
||||||
}}
|
}}
|
||||||
{@const { code, icon, id, display, title, keyCode, variant } = KEYMAP_CODES[
|
{@const { code, icon, id, display, title, keyCode, variant } =
|
||||||
actionId
|
KEYMAP_CODES.get(actionId) ?? { code: actionId }}
|
||||||
] ?? { code: actionId }}
|
|
||||||
{@const dynamicMapping = keyCode && $osLayout.get(keyCode)}
|
{@const dynamicMapping = keyCode && $osLayout.get(keyCode)}
|
||||||
{@const tooltip =
|
{@const tooltip =
|
||||||
(title ?? id ?? `0x${code.toString(16)}`) +
|
(title ?? id ?? `0x${code.toString(16)}`) +
|
||||||
@@ -53,7 +52,7 @@
|
|||||||
style:scale={isActive ? 1 : `var(--inactive-scale, ${inactiveScale})`}
|
style:scale={isActive ? 1 : `var(--inactive-scale, ${inactiveScale})`}
|
||||||
style:translate={isActive
|
style:translate={isActive
|
||||||
? "0 0 0"
|
? "0 0 0"
|
||||||
: `${direction[0].toPrecision(2)}px ${direction[1].toPrecision(2)}px 0`}
|
: `${direction[0]?.toPrecision(2)}px ${direction[1]?.toPrecision(2)}px 0`}
|
||||||
style:rotate="{rotate}deg"
|
style:rotate="{rotate}deg"
|
||||||
use:action={{ title: tooltip }}
|
use:action={{ title: tooltip }}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -119,17 +119,21 @@
|
|||||||
</label>
|
</label>
|
||||||
</h3>
|
</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{#each layoutChanges
|
{#each layoutChanges as changes, i}
|
||||||
.map((it, i) => /** @type {const} */ ([it, i + 1]))
|
{@const layer = i + 1}
|
||||||
.filter(([it]) => it.length > 0) as [changes, layer]}
|
{#if changes.length > 0}
|
||||||
<li>
|
<li>
|
||||||
<h4>
|
<h4>
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" class="checkbox" />
|
<input type="checkbox" class="checkbox" />
|
||||||
{$LL.changes.layout.LAYER({ changes: changes.length, layer })}
|
{$LL.changes.layout.LAYER({
|
||||||
|
changes: changes.length,
|
||||||
|
layer,
|
||||||
|
})}
|
||||||
</label>
|
</label>
|
||||||
</h4>
|
</h4>
|
||||||
</li>
|
</li>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
export let ports: SerialPort[];
|
export let ports: SerialPort[];
|
||||||
const dispatch = createEventDispatcher<{ confirm: SerialPort | undefined }>();
|
const dispatch = createEventDispatcher<{ confirm: SerialPort | undefined }>();
|
||||||
let selected = ports[0].getInfo().name;
|
let selected = ports[0]?.getInfo().name;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<dialog>
|
<dialog>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export function serializeActions(actions: number[]): bigint {
|
|||||||
let native = 0n;
|
let native = 0n;
|
||||||
for (let i = 1; i <= actions.length; i++) {
|
for (let i = 1; i <= actions.length; i++) {
|
||||||
native |=
|
native |=
|
||||||
BigInt(actions[actions.length - i] & 0x3ff) << BigInt((12 - i) * 10);
|
BigInt(actions[actions.length - i]! & 0x3ff) << BigInt((12 - i) * 10);
|
||||||
}
|
}
|
||||||
return native;
|
return native;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ export async function sync() {
|
|||||||
syncStatus.set("downloading");
|
syncStatus.set("downloading");
|
||||||
|
|
||||||
const max =
|
const max =
|
||||||
Object.keys(settingInfo.settings).length + device.keyCount * 3 + chordCount;
|
Object.keys(settingInfo["settings"]).length +
|
||||||
|
device.keyCount * 3 +
|
||||||
|
chordCount;
|
||||||
let current = 0;
|
let current = 0;
|
||||||
syncProgress.set({ max, current });
|
syncProgress.set({ max, current });
|
||||||
function progressTick() {
|
function progressTick() {
|
||||||
@@ -76,7 +78,7 @@ export async function sync() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const parsedSettings: number[] = [];
|
const parsedSettings: number[] = [];
|
||||||
for (const key in settingInfo.settings) {
|
for (const key in settingInfo["settings"]) {
|
||||||
try {
|
try {
|
||||||
parsedSettings[Number.parseInt(key)] = await device.getSetting(
|
parsedSettings[Number.parseInt(key)] = await device.getSetting(
|
||||||
Number.parseInt(key),
|
Number.parseInt(key),
|
||||||
@@ -89,7 +91,7 @@ export async function sync() {
|
|||||||
const parsedLayout: CharaLayout = [[], [], []];
|
const parsedLayout: CharaLayout = [[], [], []];
|
||||||
for (let layer = 1; layer <= 3; layer++) {
|
for (let layer = 1; layer <= 3; layer++) {
|
||||||
for (let i = 0; i < device.keyCount; i++) {
|
for (let i = 0; i < device.keyCount; i++) {
|
||||||
parsedLayout[layer - 1][i] = await device.getLayoutKey(layer, i);
|
parsedLayout[layer - 1]![i] = await device.getLayoutKey(layer, i);
|
||||||
progressTick();
|
progressTick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,11 +48,17 @@ export async function getViablePorts(): Promise<SerialPort[]> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LengthArray<T, N extends number, R extends T[] = []> = number extends N
|
||||||
|
? T[]
|
||||||
|
: R["length"] extends N
|
||||||
|
? R
|
||||||
|
: LengthArray<T, N, [T, ...R]>;
|
||||||
|
|
||||||
export async function canAutoConnect() {
|
export async function canAutoConnect() {
|
||||||
return getViablePorts().then((it) => it.length === 1);
|
return getViablePorts().then((it) => it.length === 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function timeout<T>(promise: Promise<T>, ms: number): Promise<T> {
|
async function timeout<T>(promise: Promise<T>, ms: number): Promise<T> {
|
||||||
let timer: number;
|
let timer: number;
|
||||||
return Promise.race([
|
return Promise.race([
|
||||||
promise,
|
promise,
|
||||||
@@ -96,7 +102,7 @@ export class CharaDevice {
|
|||||||
const ports = await getViablePorts();
|
const ports = await getViablePorts();
|
||||||
this.port =
|
this.port =
|
||||||
!manual && ports.length === 1
|
!manual && ports.length === 1
|
||||||
? ports[0]
|
? ports[0]!
|
||||||
: await navigator.serial.requestPort({
|
: await navigator.serial.requestPort({
|
||||||
filters: [...PORT_FILTERS.values()],
|
filters: [...PORT_FILTERS.values()],
|
||||||
});
|
});
|
||||||
@@ -115,9 +121,9 @@ export class CharaDevice {
|
|||||||
await this.port.close();
|
await this.port.close();
|
||||||
|
|
||||||
this.version = new SemVer(
|
this.version = new SemVer(
|
||||||
await this.send("VERSION").then(([version]) => version),
|
await this.send(1, "VERSION").then(([version]) => version),
|
||||||
);
|
);
|
||||||
const [company, device, chipset] = await this.send("ID");
|
const [company, device, chipset] = await this.send(3, "ID");
|
||||||
this.company = company as "CHARACHORDER";
|
this.company = company as "CHARACHORDER";
|
||||||
this.device = device as "ONE" | "LITE" | "X";
|
this.device = device as "ONE" | "LITE" | "X";
|
||||||
this.chipset = chipset as "M0" | "S2";
|
this.chipset = chipset as "M0" | "S2";
|
||||||
@@ -186,6 +192,7 @@ export class CharaDevice {
|
|||||||
return it;
|
return it;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,20 +263,38 @@ export class CharaDevice {
|
|||||||
/**
|
/**
|
||||||
* Send to serial port
|
* Send to serial port
|
||||||
*/
|
*/
|
||||||
async send(...command: string[]) {
|
async send<T extends number>(
|
||||||
|
expectedLength: T,
|
||||||
|
...command: string[]
|
||||||
|
): Promise<LengthArray<string, T>> {
|
||||||
return this.runWith(async (send, read) => {
|
return this.runWith(async (send, read) => {
|
||||||
await send(...command);
|
await send(...command);
|
||||||
const commandString = command
|
const commandString = command
|
||||||
.join(" ")
|
.join(" ")
|
||||||
.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||||
return read().then((it) =>
|
const readResult = await read();
|
||||||
it.replace(new RegExp(`^${commandString} `), "").split(" "),
|
if (readResult === undefined) {
|
||||||
);
|
console.error("No response");
|
||||||
|
return Array(expectedLength).fill("NO_RESPONSE") as LengthArray<
|
||||||
|
string,
|
||||||
|
T
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
const array = readResult
|
||||||
|
.replace(new RegExp(`^${commandString} `), "")
|
||||||
|
.split(" ");
|
||||||
|
if (array.length < expectedLength) {
|
||||||
|
console.error("Response too short");
|
||||||
|
return array.concat(
|
||||||
|
Array(expectedLength - array.length).fill("TOO_SHORT"),
|
||||||
|
) as LengthArray<string, T>;
|
||||||
|
}
|
||||||
|
return array as LengthArray<string, T>;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getChordCount(): Promise<number> {
|
async getChordCount(): Promise<number> {
|
||||||
const [count] = await this.send("CML C0");
|
const [count] = await this.send(1, "CML C0");
|
||||||
return Number.parseInt(count);
|
return Number.parseInt(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +302,7 @@ export class CharaDevice {
|
|||||||
* Retrieves a chord by index
|
* Retrieves a chord by index
|
||||||
*/
|
*/
|
||||||
async getChord(index: number | number[]): Promise<Chord> {
|
async getChord(index: number | number[]): Promise<Chord> {
|
||||||
const [actions, phrase] = await this.send(`CML C1 ${index}`);
|
const [actions, phrase] = await this.send(2, `CML C1 ${index}`);
|
||||||
return {
|
return {
|
||||||
actions: parseChordActions(actions),
|
actions: parseChordActions(actions),
|
||||||
phrase: parsePhrase(phrase),
|
phrase: parsePhrase(phrase),
|
||||||
@@ -289,6 +314,7 @@ export class CharaDevice {
|
|||||||
*/
|
*/
|
||||||
async getChordPhrase(actions: number[]): Promise<number[] | undefined> {
|
async getChordPhrase(actions: number[]): Promise<number[] | undefined> {
|
||||||
const [phrase] = await this.send(
|
const [phrase] = await this.send(
|
||||||
|
1,
|
||||||
`CML C2 ${stringifyChordActions(actions)}`,
|
`CML C2 ${stringifyChordActions(actions)}`,
|
||||||
);
|
);
|
||||||
return phrase === "2" ? undefined : parsePhrase(phrase);
|
return phrase === "2" ? undefined : parsePhrase(phrase);
|
||||||
@@ -296,6 +322,7 @@ export class CharaDevice {
|
|||||||
|
|
||||||
async setChord(chord: Chord) {
|
async setChord(chord: Chord) {
|
||||||
const [status] = await this.send(
|
const [status] = await this.send(
|
||||||
|
1,
|
||||||
"CML",
|
"CML",
|
||||||
"C3",
|
"C3",
|
||||||
stringifyChordActions(chord.actions),
|
stringifyChordActions(chord.actions),
|
||||||
@@ -306,10 +333,10 @@ export class CharaDevice {
|
|||||||
|
|
||||||
async deleteChord(chord: Pick<Chord, "actions">) {
|
async deleteChord(chord: Pick<Chord, "actions">) {
|
||||||
const status = await this.send(
|
const status = await this.send(
|
||||||
|
1,
|
||||||
`CML C4 ${stringifyChordActions(chord.actions)}`,
|
`CML C4 ${stringifyChordActions(chord.actions)}`,
|
||||||
);
|
);
|
||||||
console.log(status);
|
if (status?.at(-1) !== "2" && status?.at(-1) !== "0")
|
||||||
if (status.at(-1) !== "2" && status.at(-1) !== "0")
|
|
||||||
throw new Error(`Failed with status ${status}`);
|
throw new Error(`Failed with status ${status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,8 +347,7 @@ export class CharaDevice {
|
|||||||
* @param action the assigned action id
|
* @param action the assigned action id
|
||||||
*/
|
*/
|
||||||
async setLayoutKey(layer: number, id: number, action: number) {
|
async setLayoutKey(layer: number, id: number, action: number) {
|
||||||
const [status] = await this.send(`VAR B4 A${layer} ${id} ${action}`);
|
const [status] = await this.send(1, `VAR B4 A${layer} ${id} ${action}`);
|
||||||
console.log(status);
|
|
||||||
if (status !== "0") throw new Error(`Failed with status ${status}`);
|
if (status !== "0") throw new Error(`Failed with status ${status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +358,7 @@ export class CharaDevice {
|
|||||||
* @returns the assigned action id
|
* @returns the assigned action id
|
||||||
*/
|
*/
|
||||||
async getLayoutKey(layer: number, id: number) {
|
async getLayoutKey(layer: number, id: number) {
|
||||||
const [position, status] = await this.send(`VAR B3 A${layer} ${id}`);
|
const [position, status] = await this.send(2, `VAR B3 A${layer} ${id}`);
|
||||||
if (status !== "0") throw new Error(`Failed with status ${status}`);
|
if (status !== "0") throw new Error(`Failed with status ${status}`);
|
||||||
return Number(position);
|
return Number(position);
|
||||||
}
|
}
|
||||||
@@ -345,7 +371,7 @@ export class CharaDevice {
|
|||||||
* **This does not need to be called for chords**
|
* **This does not need to be called for chords**
|
||||||
*/
|
*/
|
||||||
async commit() {
|
async commit() {
|
||||||
const [status] = await this.send("VAR B0");
|
const [status] = await this.send(1, "VAR B0");
|
||||||
if (status !== "0") throw new Error(`Failed with status ${status}`);
|
if (status !== "0") throw new Error(`Failed with status ${status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,6 +383,7 @@ export class CharaDevice {
|
|||||||
*/
|
*/
|
||||||
async setSetting(id: number, value: number) {
|
async setSetting(id: number, value: number) {
|
||||||
const [status] = await this.send(
|
const [status] = await this.send(
|
||||||
|
1,
|
||||||
`VAR B2 ${id.toString(16).toUpperCase()} ${value}`,
|
`VAR B2 ${id.toString(16).toUpperCase()} ${value}`,
|
||||||
);
|
);
|
||||||
if (status !== "0") throw new Error(`Failed with status ${status}`);
|
if (status !== "0") throw new Error(`Failed with status ${status}`);
|
||||||
@@ -367,6 +394,7 @@ export class CharaDevice {
|
|||||||
*/
|
*/
|
||||||
async getSetting(id: number): Promise<number> {
|
async getSetting(id: number): Promise<number> {
|
||||||
const [value, status] = await this.send(
|
const [value, status] = await this.send(
|
||||||
|
2,
|
||||||
`VAR B1 ${id.toString(16).toUpperCase()}`,
|
`VAR B1 ${id.toString(16).toUpperCase()}`,
|
||||||
);
|
);
|
||||||
if (status !== "0")
|
if (status !== "0")
|
||||||
@@ -380,14 +408,14 @@ export class CharaDevice {
|
|||||||
* Reboots the device
|
* Reboots the device
|
||||||
*/
|
*/
|
||||||
async reboot() {
|
async reboot() {
|
||||||
await this.send("RST");
|
await this.send(0, "RST");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reboots the device to the bootloader
|
* Reboots the device to the bootloader
|
||||||
*/
|
*/
|
||||||
async bootloader() {
|
async bootloader() {
|
||||||
await this.send("RST BOOTLOADER");
|
await this.send(0, "RST BOOTLOADER");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -396,7 +424,7 @@ export class CharaDevice {
|
|||||||
async reset(
|
async reset(
|
||||||
type: "FACTORY" | "PARAMS" | "KEYMAPS" | "STARTER" | "CLEARCML" | "FUNC",
|
type: "FACTORY" | "PARAMS" | "KEYMAPS" | "STARTER" | "CLEARCML" | "FUNC",
|
||||||
) {
|
) {
|
||||||
await this.send(`RST ${type}`);
|
await this.send(0, `RST ${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -405,6 +433,6 @@ export class CharaDevice {
|
|||||||
* This is useful for debugging when there is a suspected heap or stack issue.
|
* This is useful for debugging when there is a suspected heap or stack issue.
|
||||||
*/
|
*/
|
||||||
async getRamBytesAvailable(): Promise<number> {
|
async getRamBytesAvailable(): Promise<number> {
|
||||||
return Number(await this.send("RAM"));
|
return Number(await this.send(1, "RAM").then(([bytes]) => bytes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { ActionInfo, KeymapCategory } from "$lib/assets/keymaps/keymap";
|
|||||||
|
|
||||||
export interface KeyInfo extends Partial<ActionInfo> {
|
export interface KeyInfo extends Partial<ActionInfo> {
|
||||||
code: number;
|
code: number;
|
||||||
category: KeymapCategory;
|
category?: KeymapCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const KEYMAP_CATEGORIES = (await Promise.all(
|
export const KEYMAP_CATEGORIES = (await Promise.all(
|
||||||
@@ -11,7 +11,7 @@ export const KEYMAP_CATEGORIES = (await Promise.all(
|
|||||||
),
|
),
|
||||||
)) as KeymapCategory[];
|
)) as KeymapCategory[];
|
||||||
|
|
||||||
export const KEYMAP_CODES: Record<number, KeyInfo> = Object.fromEntries(
|
export const KEYMAP_CODES = new Map<number, KeyInfo>(
|
||||||
KEYMAP_CATEGORIES.flatMap((category) =>
|
KEYMAP_CATEGORIES.flatMap((category) =>
|
||||||
Object.entries(category.actions).map(([code, action]) => [
|
Object.entries(category.actions).map(([code, action]) => [
|
||||||
Number(code),
|
Number(code),
|
||||||
@@ -20,7 +20,7 @@ export const KEYMAP_CODES: Record<number, KeyInfo> = Object.fromEntries(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const KEYMAP_KEYCODES: Map<string, number> = new Map(
|
export const KEYMAP_KEYCODES = new Map<string, number>(
|
||||||
KEYMAP_CATEGORIES.flatMap((category) =>
|
KEYMAP_CATEGORIES.flatMap((category) =>
|
||||||
Object.entries(category.actions).map(
|
Object.entries(category.actions).map(
|
||||||
([code, action]) => [action.keyCode!, Number(code)] as const,
|
([code, action]) => [action.keyCode!, Number(code)] as const,
|
||||||
@@ -28,7 +28,7 @@ export const KEYMAP_KEYCODES: Map<string, number> = new Map(
|
|||||||
).filter(([keyCode]) => keyCode !== undefined),
|
).filter(([keyCode]) => keyCode !== undefined),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const KEYMAP_IDS: Map<string, KeyInfo> = new Map(
|
export const KEYMAP_IDS = new Map<string, KeyInfo>(
|
||||||
KEYMAP_CATEGORIES.flatMap((category) =>
|
KEYMAP_CATEGORIES.flatMap((category) =>
|
||||||
Object.entries(category.actions).map(
|
Object.entries(category.actions).map(
|
||||||
([code, action]) =>
|
([code, action]) =>
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ export class SemVer {
|
|||||||
console.error("Invalid version string:", versionString);
|
console.error("Invalid version string:", versionString);
|
||||||
} else {
|
} else {
|
||||||
const [, major, minor, patch, preRelease, meta] = result;
|
const [, major, minor, patch, preRelease, meta] = result;
|
||||||
this.major = Number.parseInt(major);
|
this.major = Number.parseInt(major ?? "NaN");
|
||||||
this.minor = Number.parseInt(minor);
|
this.minor = Number.parseInt(minor ?? "NaN");
|
||||||
this.patch = Number.parseInt(patch);
|
this.patch = Number.parseInt(patch ?? "NaN");
|
||||||
if (preRelease) this.preRelease = preRelease;
|
if (preRelease) this.preRelease = preRelease;
|
||||||
if (meta) this.meta = meta;
|
if (meta) this.meta = meta;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ function NativeSerialPort(info: SerialPortInfo): TauriSerialPort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error polyfill
|
// @ts-expect-error polyfill
|
||||||
// noinspection JSConstantReassignment
|
|
||||||
navigator.serial = {
|
navigator.serial = {
|
||||||
async getPorts(): Promise<SerialPort[]> {
|
async getPorts(): Promise<SerialPort[]> {
|
||||||
return invoke<any[]>("plugin:serial|get_serial_ports").then((ports) =>
|
return invoke<any[]>("plugin:serial|get_serial_ports").then((ports) =>
|
||||||
@@ -69,6 +68,7 @@ navigator.serial = {
|
|||||||
props: { ports },
|
props: { ports },
|
||||||
});
|
});
|
||||||
const port = await new Promise<SerialPort>((resolve) =>
|
const port = await new Promise<SerialPort>((resolve) =>
|
||||||
|
// @ts-expect-error polyfill
|
||||||
dialog.$on("confirm", resolve),
|
dialog.$on("confirm", resolve),
|
||||||
);
|
);
|
||||||
dialog.$destroy();
|
dialog.$destroy();
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
export async function updateDevice(port: SerialPort) {
|
|
||||||
await port.open({
|
|
||||||
baudRate: 115200,
|
|
||||||
dataBits: 8,
|
|
||||||
stopBits: 1,
|
|
||||||
parity: "none",
|
|
||||||
bufferSize: 255,;
|
|
||||||
})
|
|
||||||
|
|
||||||
const writer = port.writable!.getWriter()
|
|
||||||
const reader = port.readable!.getReader()
|
|
||||||
}
|
|
||||||
@@ -23,9 +23,9 @@ export function compressActions(actions: number[]): Uint8Array {
|
|||||||
export function decompressActions(raw: Uint8Array): number[] {
|
export function decompressActions(raw: Uint8Array): number[] {
|
||||||
const actions: number[] = [];
|
const actions: number[] = [];
|
||||||
for (let i = 0; i < raw.length; i++) {
|
for (let i = 0; i < raw.length; i++) {
|
||||||
let action = raw[i];
|
let action = raw[i]!;
|
||||||
if (action > 0 && action < 32) {
|
if (action > 0 && action < 32 && i + 1 < raw.length) {
|
||||||
action = (action << 8) | raw[++i];
|
action = (action << 8) | raw[++i]!;
|
||||||
}
|
}
|
||||||
actions.push(action);
|
actions.push(action);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const setting: Action<
|
|||||||
|
|
||||||
const unsubscribe = settings.subscribe(async (settings) => {
|
const unsubscribe = settings.subscribe(async (settings) => {
|
||||||
if (id in settings) {
|
if (id in settings) {
|
||||||
const { value, isApplied } = settings[id];
|
const { value, isApplied } = settings[id]!;
|
||||||
if (type === "number") {
|
if (type === "number") {
|
||||||
node.value = (
|
node.value = (
|
||||||
inverse !== undefined
|
inverse !== undefined
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export function triggerShare(event: Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const share: Action<Window, (event: Event) => void> = (
|
export const share: Action<Window, (event: Event) => void> = (
|
||||||
node,
|
_node,
|
||||||
callback: (event: Event) => void,
|
callback: (event: Event) => void,
|
||||||
) => {
|
) => {
|
||||||
setCanShare.set(true);
|
setCanShare.set(true);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export const overlay = derived(changes, (changes) => {
|
|||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
switch (change.type) {
|
switch (change.type) {
|
||||||
case ChangeType.Layout:
|
case ChangeType.Layout:
|
||||||
overlay.layout[change.layer].set(change.id, change.action);
|
overlay.layout[change.layer]?.set(change.id, change.action);
|
||||||
break;
|
break;
|
||||||
case ChangeType.Chord:
|
case ChangeType.Chord:
|
||||||
overlay.chords.set(JSON.stringify(change.id), {
|
overlay.chords.set(JSON.stringify(change.id), {
|
||||||
@@ -92,8 +92,8 @@ export const layout = derived([overlay, deviceLayout], ([overlay, layout]) =>
|
|||||||
layout.map(
|
layout.map(
|
||||||
(actions, layer) =>
|
(actions, layer) =>
|
||||||
actions.map<KeyInfo>((action, id) => ({
|
actions.map<KeyInfo>((action, id) => ({
|
||||||
action: overlay.layout[layer].get(id) ?? action,
|
action: overlay.layout[layer]?.get(id) ?? action,
|
||||||
isApplied: !overlay.layout[layer].has(id),
|
isApplied: !overlay.layout[layer]?.has(id),
|
||||||
})) as [KeyInfo, KeyInfo, KeyInfo],
|
})) as [KeyInfo, KeyInfo, KeyInfo],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -118,7 +118,7 @@ export const chords = derived([overlay, deviceChords], ([overlay, chords]) => {
|
|||||||
return {
|
return {
|
||||||
id: chord.actions,
|
id: chord.actions,
|
||||||
// use the old phrase for stable editing
|
// use the old phrase for stable editing
|
||||||
sortBy: chord.phrase.map((it) => KEYMAP_CODES[it]?.id ?? it).join(),
|
sortBy: chord.phrase.map((it) => KEYMAP_CODES.get(it)?.id ?? it).join(),
|
||||||
actions: changedChord.actions,
|
actions: changedChord.actions,
|
||||||
phrase: changedChord.phrase,
|
phrase: changedChord.phrase,
|
||||||
actionsChanged: id !== JSON.stringify(changedChord.actions),
|
actionsChanged: id !== JSON.stringify(changedChord.actions),
|
||||||
@@ -130,7 +130,7 @@ export const chords = derived([overlay, deviceChords], ([overlay, chords]) => {
|
|||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
id: chord.actions,
|
id: chord.actions,
|
||||||
sortBy: chord.phrase.map((it) => KEYMAP_CODES[it]?.id ?? it).join(),
|
sortBy: chord.phrase.map((it) => KEYMAP_CODES.get(it)?.id ?? it).join(),
|
||||||
actions: chord.actions,
|
actions: chord.actions,
|
||||||
phrase: chord.phrase,
|
phrase: chord.phrase,
|
||||||
phraseChanged: false,
|
phraseChanged: false,
|
||||||
|
|||||||
@@ -23,16 +23,6 @@
|
|||||||
powerDialog = false;
|
powerDialog = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateFirmware() {
|
|
||||||
const { usbVendorId: vendorId, usbProductId: productId } =
|
|
||||||
$serialPort!.portInfo;
|
|
||||||
$serialPort!.bootloader();
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
||||||
console.log(
|
|
||||||
await navigator.usb.requestDevice({ filters: [{ vendorId, productId }] }),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let rebootInfo = false;
|
let rebootInfo = false;
|
||||||
let terminal = false;
|
let terminal = false;
|
||||||
let powerDialog = false;
|
let powerDialog = false;
|
||||||
|
|||||||
@@ -32,12 +32,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function redo() {
|
function redo() {
|
||||||
const [change, ...queue] = redoQueue;
|
const change = redoQueue.shift();
|
||||||
|
if (change) {
|
||||||
changes.update((it) => {
|
changes.update((it) => {
|
||||||
it.push(change);
|
it.push(change);
|
||||||
return it;
|
return it;
|
||||||
});
|
});
|
||||||
redoQueue = queue;
|
}
|
||||||
}
|
}
|
||||||
let redoQueue: Change[] = [];
|
let redoQueue: Change[] = [];
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@
|
|||||||
$LL.configure.chords.conflict.TITLE(),
|
$LL.configure.chords.conflict.TITLE(),
|
||||||
$LL.configure.chords.conflict.DESCRIPTION(
|
$LL.configure.chords.conflict.DESCRIPTION(
|
||||||
actions
|
actions
|
||||||
.map((it) => `<kbd>${KEYMAP_CODES[it].id}</kbd>`)
|
.map((it) => `<kbd>${KEYMAP_CODES.get(it)?.id}</kbd>`)
|
||||||
.join(" "),
|
.join(" "),
|
||||||
),
|
),
|
||||||
$LL.configure.chords.conflict.CONFIRM(),
|
$LL.configure.chords.conflict.CONFIRM(),
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<SyncOverlay />
|
<SyncOverlay />
|
||||||
</div>
|
</div>
|
||||||
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
|
||||||
<ul>
|
<ul>
|
||||||
<li class="hide-forced-colors">
|
<li class="hide-forced-colors">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
index.add(
|
index.add(
|
||||||
i,
|
i,
|
||||||
chord.phrase
|
chord.phrase
|
||||||
.map((it) => KEYMAP_CODES[it]?.id)
|
.map((it) => KEYMAP_CODES.get(it)?.id)
|
||||||
.filter((it) => !!it)
|
.filter((it) => !!it)
|
||||||
.join(""),
|
.join(""),
|
||||||
);
|
);
|
||||||
@@ -51,7 +51,9 @@
|
|||||||
function search(event: Event) {
|
function search(event: Event) {
|
||||||
const query = (event.target as HTMLInputElement).value;
|
const query = (event.target as HTMLInputElement).value;
|
||||||
searchFilter.set(
|
searchFilter.set(
|
||||||
query && searchIndex ? searchIndex.search(query) : undefined,
|
query && searchIndex
|
||||||
|
? (searchIndex.search(query) as number[])
|
||||||
|
: undefined,
|
||||||
);
|
);
|
||||||
page = 0;
|
page = 0;
|
||||||
}
|
}
|
||||||
@@ -131,10 +133,12 @@
|
|||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $lastPage !== -1}
|
{#if $lastPage !== -1}
|
||||||
{#each $items.slice(page * $pageSize - (page === 0 ? 0 : 1), (page + 1) * $pageSize - 1) as [chord] (JSON.stringify(chord.id))}
|
{#each $items.slice(page * $pageSize - (page === 0 ? 0 : 1), (page + 1) * $pageSize - 1) as [chord] (JSON.stringify(chord?.id))}
|
||||||
|
{#if chord}
|
||||||
<tr>
|
<tr>
|
||||||
<ChordEdit {chord} />
|
<ChordEdit {chord} />
|
||||||
</tr>
|
</tr>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
<caption>{$LL.configure.chords.search.NO_RESULTS()}</caption>
|
<caption>{$LL.configure.chords.search.NO_RESULTS()}</caption>
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
});
|
});
|
||||||
return changes;
|
return changes;
|
||||||
});
|
});
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSpecial(event: MouseEvent) {
|
function addSpecial(event: MouseEvent) {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
onHidden(instance) {
|
onHidden(instance) {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
},
|
},
|
||||||
onDestroy(instance) {
|
onDestroy(_instance) {
|
||||||
shareComponent.$destroy();
|
shareComponent.$destroy();
|
||||||
},
|
},
|
||||||
}).show();
|
}).show();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
/*******************************
|
/*******************************
|
||||||
* HOLD UP AND READ THIS FIRST *
|
* HOLD UP AND READ THIS FIRST *
|
||||||
*******************************
|
*******************************
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
// @ts-nocheck
|
||||||
let ongoingRequest;
|
let ongoingRequest;
|
||||||
let resolveRequest;
|
let resolveRequest;
|
||||||
let source;
|
let source;
|
||||||
|
|||||||
@@ -48,18 +48,18 @@
|
|||||||
if (next.length === 0) {
|
if (next.length === 0) {
|
||||||
next = Array.from(
|
next = Array.from(
|
||||||
{ length: 5 },
|
{ length: 5 },
|
||||||
() => $chords[Math.floor(Math.random() * $chords.length)],
|
() => $chords[Math.floor(Math.random() * $chords.length)]!,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
next.shift();
|
next.shift();
|
||||||
next.push($chords[Math.floor(Math.random() * $chords.length)]);
|
next.push($chords[Math.floor(Math.random() * $chords.length)]!);
|
||||||
next = next;
|
next = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
userInput ===
|
userInput ===
|
||||||
next[0].phrase
|
next[0]!.phrase
|
||||||
.map((it) => (it === 32 ? " " : KEYMAP_CODES[it]!.id))
|
.map((it) => (it === 32 ? " " : KEYMAP_CODES.get(it)!.id))
|
||||||
.join("") +
|
.join("") +
|
||||||
" "
|
" "
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ for (const icon of icons) {
|
|||||||
.flatMap((it) => [...it])
|
.flatMap((it) => [...it])
|
||||||
.map((it) => it.codePointAt(0).toString(16));
|
.map((it) => it.codePointAt(0).toString(16));
|
||||||
|
|
||||||
const codePoint = config.codePoints[icon];
|
const codePoint = config.codePoints[icon ?? ""];
|
||||||
if (codePoint) {
|
if (codePoint) {
|
||||||
glyphs.push(codePoint);
|
glyphs.push(codePoint);
|
||||||
} else if (codePoints.length === 0) {
|
} else if (codePoints.length === 0) {
|
||||||
|
|||||||
@@ -4,6 +4,14 @@
|
|||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ const { homepage, bugs, repository } = JSON.parse(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
process.env.VITE_HOMEPAGE_URL = repository.url.replace(/\.git$/, "");
|
process.env["VITE_HOMEPAGE_URL"] = repository.url.replace(/\.git$/, "");
|
||||||
process.env.VITE_DOCS_URL = homepage;
|
process.env["VITE_DOCS_URL"] = homepage;
|
||||||
process.env.VITE_BUGS_URL = bugs.url;
|
process.env["VITE_BUGS_URL"] = bugs.url;
|
||||||
process.env.VITE_LEARN_URL = "https://www.iq-eq.io/";
|
process.env["VITE_LEARN_URL"] = "https://www.iq-eq.io/";
|
||||||
process.env.VITE_LATEST_FIRMWARE = "1.1.3";
|
process.env["VITE_LATEST_FIRMWARE"] = "1.1.3";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
|
|||||||
Reference in New Issue
Block a user