style: run eslint and prettier
All checks were successful
TrafficCue CI / check (push) Successful in 58s
TrafficCue CI / build (push) Successful in 47s

This commit is contained in:
Cfp
2025-08-11 18:59:04 +02:00
parent 9d5319aee2
commit d7db55cd29
19 changed files with 1006 additions and 936 deletions

View File

@ -1,2 +1,3 @@
android/
dist/
dist/
src-tauri/

View File

@ -26,7 +26,7 @@ export default tseslint.config(
],
},
},
[globalIgnores(["./android", "./dist"])],
[globalIgnores(["./android", "./dist", "./src-tauri"])],
{
languageOptions: {
globals: {

View File

@ -3,7 +3,10 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<link rel="manifest" href="manifest.json" />
<title>TrafficCue</title>
</head>

View File

@ -1,7 +1,6 @@
{
"version": 8,
"sources": {
},
"sources": {},
"sprite": "https://tiles.openfreemap.org/sprites/ofm_f384/ofm",
"glyphs": "https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf",
"layers": []

View File

@ -10,7 +10,11 @@
import { location } from "./location.svelte";
import { saved } from "$lib/saved.svelte";
import RoutingLayers from "$lib/services/navigation/RoutingLayers.svelte";
import { getPMTilesURL, hasPMTiles, protocol } from "$lib/services/OfflineTiles";
import {
getPMTilesURL,
hasPMTiles,
protocol,
} from "$lib/services/OfflineTiles";
import { layers, worldLayers } from "$lib/mapLayers";
import { PMTilesProtocol } from "svelte-maplibre-gl/pmtiles";
@ -43,32 +47,26 @@
location.locked = true;
// @ts-expect-error - not typed
window.map = map.value;
// const worldUrl = await getPMTiles("world");
// if(worldUrl) {
map.value!.addSource("ne2_shaded", { // TODO: rename to world
type: "vector",
url: await getPMTilesURL("world"),
attribution: "Natural Earth",
// maxzoom: 6
})
// @ts-expect-error - not typed correctly
worldLayers.forEach(l => map.value!.addLayer(l));
// }
map.value!.addSource("ne2_shaded", {
// TODO: rename to world
type: "vector",
url: await getPMTilesURL("world"),
attribution: "Natural Earth",
});
// const url = await getPMTiles("tiles");
// console.log(url)
// if(url) {
map.value!.addSource("openmaptiles", {
type: "vector",
url: await hasPMTiles("tiles") ? await getPMTilesURL("tiles") : "pmtiles://https://trafficcue-tiles.picoscratch.de/germany.pmtiles"
})
// @ts-expect-error - not typed correctly
worldLayers.forEach((l) => map.value!.addLayer(l));
map.value!.addSource("openmaptiles", {
type: "vector",
url: (await hasPMTiles("tiles"))
? await getPMTilesURL("tiles")
: "pmtiles://https://trafficcue-tiles.picoscratch.de/germany.pmtiles",
});
// @ts-expect-error - not typed correctly
layers.forEach(l => map.value!.addLayer(l));
// }
// @ts-expect-error - not typed correctly
layers.forEach((l) => map.value!.addLayer(l));
}}
onclick={(e) => {
if (view.current.type == "main" || view.current.type == "info") {

View File

@ -27,8 +27,6 @@
import * as Popover from "../ui/popover";
import { routing } from "$lib/services/navigation/routing.svelte";
import InRouteSidebar from "./sidebar/InRouteSidebar.svelte";
import say from "$lib/services/navigation/TTS";
import { downloadPMTiles } from "$lib/services/OfflineTiles";
import SettingsSidebar from "./sidebar/settings/SettingsSidebar.svelte";
import AboutSidebar from "./sidebar/settings/AboutSidebar.svelte";
import OfflineMapsSidebar from "./sidebar/settings/OfflineMapsSidebar.svelte";
@ -45,7 +43,7 @@
settings: SettingsSidebar,
about: AboutSidebar,
"offline-maps": OfflineMapsSidebar,
"dev-options": DeveloperSidebar
"dev-options": DeveloperSidebar,
};
let isDragging = false;
@ -164,9 +162,11 @@
<UserIcon />
</button>
</RequiresCapability>
<button onclick={() => {
view.switch("settings");
}}>
<button
onclick={() => {
view.switch("settings");
}}
>
<SettingsIcon />
</button>
<!-- <button onclick={() => {

View File

@ -6,18 +6,21 @@
const dev = getDeveloperToggle();
</script>
<SidebarHeader>
About
</SidebarHeader>
<SidebarHeader>About</SidebarHeader>
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<h1 style="font-size: 2em; font-weight: bold;" onclick={() => {
count--;
if(count == 0) {
dev.current = "true";
}
}}>TrafficCue</h1>
<h1
style="font-size: 2em; font-weight: bold;"
onclick={() => {
count--;
if (count == 0) {
dev.current = "true";
}
}}
>
TrafficCue
</h1>
<span>Powered by:</span>
<ul>
<li>© OpenStreetMap contributors</li>

View File

@ -10,31 +10,42 @@
const dev = getDeveloperToggle();
</script>
<SidebarHeader>
Developer Settings
</SidebarHeader>
<SidebarHeader>Developer Settings</SidebarHeader>
<div id="sections">
<section>
<h2>Test</h2>
<SettingsButton icon={SpeechIcon} text="Test TTS" onclick={async () => {
await say("Test")
}} />
<SettingsButton icon={MapIcon} disabled={!window.__TAURI__} text="Download tiles from URL{window.__TAURI__ ? "" : " (Unavailable)"}" onclick={async () => {
const name = prompt("Name?");
if(!name) return;
const url = prompt("URL?");
if(!url) return;
await downloadPMTiles(url, name);
}} />
<SettingsButton
icon={SpeechIcon}
text="Test TTS"
onclick={async () => {
await say("Test");
}}
/>
<SettingsButton
icon={MapIcon}
disabled={!window.__TAURI__}
text="Download tiles from URL{window.__TAURI__ ? '' : ' (Unavailable)'}"
onclick={async () => {
const name = prompt("Name?");
if (!name) return;
const url = prompt("URL?");
if (!url) return;
await downloadPMTiles(url, name);
}}
/>
</section>
<section>
<h2>Other</h2>
<SettingsButton icon={ToggleLeftIcon} text="Disable Developer Options" onclick={async () => {
dev.current = "false";
view.back();
}} />
<SettingsButton
icon={ToggleLeftIcon}
text="Disable Developer Options"
onclick={async () => {
dev.current = "false";
view.back();
}}
/>
</section>
</div>
@ -50,4 +61,4 @@
flex-direction: column;
gap: 1rem;
}
</style>
</style>

View File

@ -4,12 +4,10 @@
import SettingsButton from "./SettingsButton.svelte";
import SidebarHeader from "../SidebarHeader.svelte";
let progresses: {[key: string]: number} = $state({});
let progresses: Record<string, number> = $state({});
</script>
<SidebarHeader>
Offline Maps
</SidebarHeader>
<SidebarHeader>Offline Maps</SidebarHeader>
{#await getRemoteList()}
<p>Loading...</p>
@ -18,19 +16,29 @@
{#if list.length === 0}
<p>No offline maps available.</p>
{/if}
{#if !window.__TAURI__}
<p>Offline maps are only available on mobile.</p>
{/if}
{#each list as item, _index (item.file)}
<SettingsButton disabled={!window.__TAURI__} icon={DownloadCloudIcon} text={item.name} progress={progresses[item.file] ?? -1} onclick={async () => {
await downloadPMTiles("https://trafficcue-tiles.picoscratch.de/" + item.file, item.name.includes("World") ? "world": "tiles", (progress, total) => {
progresses[item.file] = (progress / total) * 100;
});
alert(`Downloaded ${item.name}`);
location.reload();
}} />
<SettingsButton
disabled={!window.__TAURI__}
icon={DownloadCloudIcon}
text={item.name}
progress={progresses[item.file] ?? -1}
onclick={async () => {
await downloadPMTiles(
"https://trafficcue-tiles.picoscratch.de/" + item.file,
item.name.includes("World") ? "world" : "tiles",
(progress, total) => {
progresses[item.file] = (progress / total) * 100;
},
);
alert(`Downloaded ${item.name}`);
location.reload();
}}
/>
{/each}
</div>
{/await}
{/await}

View File

@ -6,16 +6,31 @@
import Progress from "$lib/components/ui/progress/progress.svelte";
const {
icon: Icon, text, view: viewName, onclick, disabled, progress
icon: Icon,
text,
view: viewName,
onclick,
disabled,
progress,
}: {
icon: Component<IconProps>, text: string, view?: string, onclick?: () => void, disabled?: boolean, progress?: number
icon: Component<IconProps>;
text: string;
view?: string;
onclick?: () => void;
disabled?: boolean;
progress?: number;
} = $props();
</script>
<Button variant="secondary" style="width: 100%; height: 40px;" {disabled} onclick={() => {
if(viewName) view.switch(viewName)
if(onclick) onclick();
}}>
<Button
variant="secondary"
style="width: 100%; height: 40px;"
{disabled}
onclick={() => {
if (viewName) view.switch(viewName);
if (onclick) onclick();
}}
>
<Icon />
{text}
{#if progress == -1}
@ -23,4 +38,4 @@
{:else if progress}
<Progress value={progress} />
{/if}
</Button>
</Button>

View File

@ -1,5 +1,11 @@
<script>
import { CodeIcon, InfoIcon, LanguagesIcon, MapIcon, PaintbrushIcon } from "@lucide/svelte";
import {
CodeIcon,
InfoIcon,
LanguagesIcon,
MapIcon,
PaintbrushIcon,
} from "@lucide/svelte";
import SidebarHeader from "../SidebarHeader.svelte";
import SettingsButton from "./SettingsButton.svelte";
import { getDeveloperToggle } from "./developer.svelte";
@ -7,26 +13,28 @@
const dev = getDeveloperToggle();
</script>
<SidebarHeader>
Settings
</SidebarHeader>
<SidebarHeader>Settings</SidebarHeader>
<div id="sections">
<section>
<h2>General</h2>
<SettingsButton icon={LanguagesIcon} text="Language" disabled />
</section>
<section>
<h2>Map</h2>
<SettingsButton icon={MapIcon} text="Offline Maps" view="offline-maps" />
<SettingsButton icon={PaintbrushIcon} text="Map Style" disabled />
</section>
<section>
<h2>About</h2>
{#if dev.current == "true"}
<SettingsButton icon={CodeIcon} text="Developer Settings" view="dev-options" />
<SettingsButton
icon={CodeIcon}
text="Developer Settings"
view="dev-options"
/>
{/if}
<SettingsButton icon={InfoIcon} text="About" view="about" />
</section>
@ -44,4 +52,4 @@
flex-direction: column;
gap: 1rem;
}
</style>
</style>

View File

@ -1,7 +1,7 @@
export function getDeveloperToggle() {
const value = localStorage.getItem("developer")
const value = localStorage.getItem("developer");
const state = $state({
current: value == null ? "false" : value
current: value == null ? "false" : value,
});
$effect(() => {
@ -9,4 +9,4 @@ export function getDeveloperToggle() {
});
return state;
}
}

View File

@ -14,7 +14,10 @@
<ProgressPrimitive.Root
bind:ref
data-slot="progress"
class={cn("bg-primary/20 relative h-2 w-full overflow-hidden rounded-full", className)}
class={cn(
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
className,
)}
{value}
{max}
{...restProps}

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,33 @@
import { appDataDir, join } from "@tauri-apps/api/path";
import { BaseDirectory, exists, mkdir, open, remove, SeekMode } from "@tauri-apps/plugin-fs";
import {
BaseDirectory,
exists,
mkdir,
open,
remove,
SeekMode,
} from "@tauri-apps/plugin-fs";
import { download } from "@tauri-apps/plugin-upload";
import { PMTiles, TileType, type Source } from "pmtiles";
export async function downloadPMTiles(url: string, name: string, onprogress?: (progress: number, total: number) => any): Promise<void> {
// if(!window.__TAURI__) {
// throw new Error("Tauri environment is not available.");
// }
export async function downloadPMTiles(
url: string,
name: string,
onprogress?: (progress: number, total: number) => void,
): Promise<void> {
// if(!window.__TAURI__) {
// throw new Error("Tauri environment is not available.");
// }
const filename = name + ".pmtiles";
const baseDir = BaseDirectory.AppData;
const appDataDirPath = await appDataDir();
if(!await exists(appDataDirPath)) {
if (!(await exists(appDataDirPath))) {
await mkdir(appDataDirPath, { recursive: true });
}
if(await exists(filename, { baseDir })) {
if (await exists(filename, { baseDir })) {
console.log(`File ${filename} already exists, deleting it.`);
await remove(filename, { baseDir });
}
@ -30,30 +41,36 @@ export async function downloadPMTiles(url: string, name: string, onprogress?: (p
const path = await join(appDataDirPath, filename);
let totalProgress = 0;
let totalProgress = 0;
await download(url, path, ({ progress, total }) => {
totalProgress += progress;
console.log(`Download progress: ${Math.round((totalProgress / total) * 100)}% (${totalProgress}\tof ${total} bytes)`);
if(onprogress) onprogress(totalProgress, total);
totalProgress += progress;
console.log(
`Download progress: ${Math.round((totalProgress / total) * 100)}% (${totalProgress}\tof ${total} bytes)`,
);
if (onprogress) onprogress(totalProgress, total);
});
console.log(`Download completed: ${path}`);
}
export async function getRemoteList(): Promise<{ name: string, file: string }[]> {
return await fetch("https://trafficcue-tiles.picoscratch.de/index.json").then(res => res.json());
export async function getRemoteList(): Promise<
{ name: string; file: string }[]
> {
return await fetch("https://trafficcue-tiles.picoscratch.de/index.json").then(
(res) => res.json(),
);
}
export async function hasPMTiles(name: string): Promise<boolean> {
if(!window.__TAURI__) {
if (!window.__TAURI__) {
return false; // Tauri environment is not available
}
const filename = name + ".pmtiles";
const baseDir = BaseDirectory.AppData;
const appDataDirPath = await appDataDir();
if(!await exists(appDataDirPath)) {
if (!(await exists(appDataDirPath))) {
return false;
}
@ -62,21 +79,21 @@ export async function hasPMTiles(name: string): Promise<boolean> {
}
export async function getPMTilesURL(name: string) {
if(!window.__TAURI__) {
if (!window.__TAURI__) {
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
}
const filename = name + ".pmtiles";
const baseDir = BaseDirectory.AppData;
const appDataDirPath = await appDataDir();
if(!await exists(appDataDirPath)) {
if (!(await exists(appDataDirPath))) {
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
// throw new Error("App data directory does not exist.");
}
const filePath = await join(appDataDirPath, filename);
if(!await exists(filePath, { baseDir })) {
if (!(await exists(filePath, { baseDir }))) {
return `pmtiles://https://trafficcue-tiles.picoscratch.de/${name}.pmtiles`;
// throw new Error(`PMTiles file not found: ${filePath}`);
}
@ -84,8 +101,15 @@ export async function getPMTilesURL(name: string) {
return `tiles://${name}`;
}
async function readBytes(name: string, offset: number, length: number): Promise<Uint8Array> {
const file = await open(name + ".pmtiles", { read: true, baseDir: BaseDirectory.AppData });
async function readBytes(
name: string,
offset: number,
length: number,
): Promise<Uint8Array> {
const file = await open(name + ".pmtiles", {
read: true,
baseDir: BaseDirectory.AppData,
});
const buffer = new Uint8Array(length);
await file.seek(offset, SeekMode.Start);
await file.read(buffer);
@ -100,135 +124,142 @@ export class FSSource implements Source {
this.name = name;
}
async getBytes(offset: number, length: number, _signal?: AbortSignal, _etag?: string) { // TODO: abort signal
async getBytes(
offset: number,
length: number,
_signal?: AbortSignal,
_etag?: string,
) {
// TODO: abort signal
const data = await readBytes(this.name, offset, length);
return {
data: data.buffer as ArrayBuffer,
etag: undefined,
cacheControl: undefined,
expires: undefined
}
expires: undefined,
};
}
getKey = () => this.name;
}
interface RequestParameters {
url: string;
headers?: unknown;
method?: "GET" | "POST" | "PUT";
body?: string;
type?: "string" | "json" | "arrayBuffer" | "image";
credentials?: "same-origin" | "include";
collectResourceTiming?: boolean;
};
url: string;
headers?: unknown;
method?: "GET" | "POST" | "PUT";
body?: string;
type?: "string" | "json" | "arrayBuffer" | "image";
credentials?: "same-origin" | "include";
collectResourceTiming?: boolean;
}
export class Protocol {
/** @hidden */
tiles: Map<string, PMTiles>;
metadata: boolean; errorOnMissingTile: boolean;
/** @hidden */
tiles: Map<string, PMTiles>;
metadata: boolean;
errorOnMissingTile: boolean;
/**
* Initialize the MapLibre PMTiles protocol.
*
* * metadata: also load the metadata section of the PMTiles. required for some "inspect" functionality
* and to automatically populate the map attribution. Requires an extra HTTP request.
* * errorOnMissingTile: When a vector MVT tile is missing from the archive, raise an error instead of
* returning the empty array. Not recommended. This is only to reproduce the behavior of ZXY tile APIs
* which some applications depend on when overzooming.
*/
constructor(options?: { metadata?: boolean; errorOnMissingTile?: boolean }) {
this.tiles = new Map<string, PMTiles>();
this.metadata = options?.metadata || false;
this.errorOnMissingTile = options?.errorOnMissingTile || false;
}
/**
* Initialize the MapLibre PMTiles protocol.
*
* * metadata: also load the metadata section of the PMTiles. required for some "inspect" functionality
* and to automatically populate the map attribution. Requires an extra HTTP request.
* * errorOnMissingTile: When a vector MVT tile is missing from the archive, raise an error instead of
* returning the empty array. Not recommended. This is only to reproduce the behavior of ZXY tile APIs
* which some applications depend on when overzooming.
*/
constructor(options?: { metadata?: boolean; errorOnMissingTile?: boolean }) {
this.tiles = new Map<string, PMTiles>();
this.metadata = options?.metadata || false;
this.errorOnMissingTile = options?.errorOnMissingTile || false;
}
/**
* Add a {@link PMTiles} instance to the global protocol instance.
*
* For remote fetch sources, references in MapLibre styles like pmtiles://http://...
* will resolve to the same instance if the URLs match.
*/
add(p: PMTiles) {
this.tiles.set(p.source.getKey(), p);
}
/**
* Add a {@link PMTiles} instance to the global protocol instance.
*
* For remote fetch sources, references in MapLibre styles like pmtiles://http://...
* will resolve to the same instance if the URLs match.
*/
add(p: PMTiles) {
this.tiles.set(p.source.getKey(), p);
}
/**
* Fetch a {@link PMTiles} instance by URL, for remote PMTiles instances.
*/
get(url: string) {
return this.tiles.get(url);
}
/**
* Fetch a {@link PMTiles} instance by URL, for remote PMTiles instances.
*/
get(url: string) {
return this.tiles.get(url);
}
/** @hidden */
tilev4 = async (
params: RequestParameters,
abortController: AbortController
) => {
if (params.type === "json") {
const pmtilesUrl = params.url.substr(8);
let instance = this.tiles.get(pmtilesUrl);
if (!instance) {
instance = new PMTiles(new FSSource(pmtilesUrl));
this.tiles.set(pmtilesUrl, instance);
}
/** @hidden */
tilev4 = async (
params: RequestParameters,
abortController: AbortController,
) => {
if (params.type === "json") {
const pmtilesUrl = params.url.substr(8);
let instance = this.tiles.get(pmtilesUrl);
if (!instance) {
instance = new PMTiles(new FSSource(pmtilesUrl));
this.tiles.set(pmtilesUrl, instance);
}
if (this.metadata) {
return {
data: await instance.getTileJson(params.url),
};
}
if (this.metadata) {
return {
data: await instance.getTileJson(params.url),
};
}
const h = await instance.getHeader();
const h = await instance.getHeader();
if (h.minLon >= h.maxLon || h.minLat >= h.maxLat) {
console.error(
`Bounds of PMTiles archive ${h.minLon},${h.minLat},${h.maxLon},${h.maxLat} are not valid.`
);
}
if (h.minLon >= h.maxLon || h.minLat >= h.maxLat) {
console.error(
`Bounds of PMTiles archive ${h.minLon},${h.minLat},${h.maxLon},${h.maxLat} are not valid.`,
);
}
return {
data: {
tiles: [`${params.url}/{z}/{x}/{y}`],
minzoom: h.minZoom,
maxzoom: h.maxZoom,
bounds: [h.minLon, h.minLat, h.maxLon, h.maxLat],
},
};
}
const re = new RegExp(/tiles:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/);
const result = params.url.match(re);
if (!result) {
throw new Error("Invalid Tiles protocol URL");
}
const pmtilesUrl = result[1];
return {
data: {
tiles: [`${params.url}/{z}/{x}/{y}`],
minzoom: h.minZoom,
maxzoom: h.maxZoom,
bounds: [h.minLon, h.minLat, h.maxLon, h.maxLat],
},
};
}
const re = new RegExp(/tiles:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/);
const result = params.url.match(re);
if (!result) {
throw new Error("Invalid Tiles protocol URL");
}
const pmtilesUrl = result[1];
let instance = this.tiles.get(pmtilesUrl);
if (!instance) {
instance = new PMTiles(new FSSource(pmtilesUrl));
this.tiles.set(pmtilesUrl, instance);
}
const z = result[2];
const x = result[3];
const y = result[4];
let instance = this.tiles.get(pmtilesUrl);
if (!instance) {
instance = new PMTiles(new FSSource(pmtilesUrl));
this.tiles.set(pmtilesUrl, instance);
}
const z = result[2];
const x = result[3];
const y = result[4];
const header = await instance.getHeader();
const resp = await instance?.getZxy(+z, +x, +y, abortController.signal);
if (resp) {
return {
data: new Uint8Array(resp.data),
cacheControl: resp.cacheControl,
expires: resp.expires,
};
}
if (header.tileType === TileType.Mvt) {
if (this.errorOnMissingTile) {
throw new Error("Tile not found.");
}
return { data: new Uint8Array() };
}
return { data: null };
};
const header = await instance.getHeader();
const resp = await instance?.getZxy(+z, +x, +y, abortController.signal);
if (resp) {
return {
data: new Uint8Array(resp.data),
cacheControl: resp.cacheControl,
expires: resp.expires,
};
}
if (header.tileType === TileType.Mvt) {
if (this.errorOnMissingTile) {
throw new Error("Tile not found.");
}
return { data: new Uint8Array() };
}
return { data: null };
};
}
export const protocol = new Protocol({

View File

@ -60,7 +60,12 @@ out center tags;`,
}).then((res) => res.json() as Promise<OverpassResult>);
}
export async function fetchNearbyPOI(lat: number, lon: number, tags: string[], radius: number) {
export async function fetchNearbyPOI(
lat: number,
lon: number,
tags: string[],
radius: number,
) {
return await fetch(OVERPASS_SERVER, {
method: "POST",
body: `[out:json];

View File

@ -23,7 +23,7 @@ export default async function say(text: string) {
duck();
if (tts !== "web") {
try {
await invoke("plugin:tts|speak", { text })
await invoke("plugin:tts|speak", { text });
} catch (e) {
console.error("Error speaking text", e);
alert(e);

View File

@ -129,7 +129,7 @@ function drawCurrentTrip() {
}
export async function startRoute(trip: Trip) {
if(window.__TAURI__) {
if (window.__TAURI__) {
await keepScreenOn(true);
}
routing.currentTrip = trip;
@ -270,7 +270,7 @@ export function stopNavigation() {
routing.currentTrip = null;
map.updateMapPadding(); // TODO: REMOVE
removeAllRoutes();
if(window.__TAURI__) {
if (window.__TAURI__) {
keepScreenOn(false);
}
}

View File

@ -12,22 +12,23 @@ export default defineConfig({
port: 5173,
strictPort: true,
host: host || false,
hmr: host ? {
protocol: "ws",
host,
port: 1421
} : undefined,
hmr: host
? {
protocol: "ws",
host,
port: 1421,
}
: undefined,
watch: {
ignored: ["**/src-tauri/**"]
}
ignored: ["**/src-tauri/**"],
},
},
envPrefix: ["VITE_", "TAURI_ENV_*"],
build: {
target: process.env.TAURI_ENV_PLATFORM == "windows"
? "chrome105"
: "safari13",
target:
process.env.TAURI_ENV_PLATFORM == "windows" ? "chrome105" : "safari13",
minify: !process.env.TAURI_ENV_DEBUG ? "esbuild" : false,
sourcemap: !!process.env.TAURI_ENV_DEBUG
sourcemap: !!process.env.TAURI_ENV_DEBUG,
},
resolve: {
alias: {