Skip to content

Conversation

@danditomaso
Copy link
Collaborator

Description

This will touch most of the components in the UI, if you open a PR relating to any of the UI components this will cause a merge conflict. Hold off until this has been merged.

Related Issues

Changes Made

Testing Done

Screenshots (if applicable)

Checklist

  • Code follows project style guidelines
  • Documentation has been updated or added
  • Tests have been added or updated
  • All i18n translation labels have been added (read
    CONTRIBUTING_I18N_DEVELOPER_GUIDE.md for more details)

@vercel
Copy link

vercel bot commented Nov 29, 2025

@danditomaso is attempting to deploy a commit to the Meshtastic Team on Vercel.

A member of the Team first needs to authorize it.

@danditomaso danditomaso changed the title feat(ui): responsive ui feat(ui): responsive ui updates EVERYONE ELSE = DONT CREATE UI PRs Dec 1, 2025
@rj-xy
Copy link
Contributor

rj-xy commented Dec 4, 2025

How is this going @danditomaso - would you like a hand with anything?

@danditomaso
Copy link
Collaborator Author

danditomaso commented Dec 4, 2025

It's coming (so is Christmas). I had posted screenshots in the linux-native meshtastic discord channel. Just doing an overhaul of the UI and sneaking in some updates along the way. Should be ready soon, if you have any translation updates to share feel free to make those types of changes

How is this going @danditomaso - would you like a hand with anything?

- Replace biome with oxlint for linting and oxfmt for formatting
- Update lint-staged configuration for new tooling
- Add husky pre-commit hook
- Fix lint errors in staged files:
  - Replace biome-ignore comments with eslint-disable-next-line
  - Fix no-explicit-any errors by using `as never` for dynamic config values
  - Fix react-hooks/exhaustive-deps warnings with proper suppression comments
  - Add aria-selected to tab role elements for accessibility
  - Add variant/size to SidebarMenuButton type definition
  - Memoize tabs array in ModuleConfig to prevent re-renders
  - Remove unused imports and fix unused parameter warnings
Inline transport creation directly into ConnectionService, removing
the unnecessary strategy abstraction layer:

- Delete BluetoothStrategy.ts, SerialStrategy.ts, HttpStrategy.ts, types.ts
- Add private methods: createTransport, createHttpTransport,
  createBluetoothTransport, createSerialTransport, disconnectTransport
- Replace ConnectionState.strategy with ConnectionState.connectionType
- Transport logic is now ~180 lines in ConnectionService vs 4 separate files

This reduces indirection without changing behavior.
Split the monolithic BrowserHardware object into two focused modules:
- browserSerial.ts: Web Serial API utilities (hasSerial, getSerialPorts, etc.)
- browserBluetooth.ts: Web Bluetooth API utilities (hasBluetooth, etc.)

Benefits:
- Better tree-shaking: apps only using one transport don't bundle the other
- Clearer responsibility separation
- Functions exported directly instead of object methods

The original BrowserHardware.ts is preserved as a re-export facade for
backward compatibility, marked as deprecated.

ConnectionService.ts updated to import from the new modules directly.
Split config synchronization logic into dedicated ConfigSyncService:
- tryLoadCachedConfig: Load cached config for fast reconnection
- saveConfigToCache: Save fresh config after successful connection
- saveBaseHashes: Compute and save config hashes for change detection
- saveFreshConfig: Combined save operation

This reduces ConnectionService from 917 to 828 lines while creating a
focused 175-line ConfigSyncService for cache and hash management.

The new service uses a ConfigSyncContext interface to receive only
the device properties it needs, improving testability.
Connection Recovery Fixes:
- Add smart auto-reconnect with 30-minute threshold
- Fast recovery mode: skip config sync when < 30 min with cached config
- Full recovery mode: complete config sync when > 30 min or no cache
- Add fallback from fast to full recovery on connection failure
- Add toast notifications for recovery status feedback
- Fix serial stream lock error with forceReleaseStreams() utility
- Detect and cleanup locked streams before creating new transport

Code Quality Migration:
- Remove Biome and migrate to oxlint/oxfmt (already configured at repo root)
- Remove all biome-ignore comments (8 locations)
- Convert MigrationService class to regular functions
- Update all imports from MigrationService to deleteDeviceData
- Remove Biome scripts from package.json

Files Changed:
- ConnectionService.ts: Smart recovery logic with toast notifications
- transportFactory.ts: Stream lock detection and cleanup
- browserSerial.ts: forceReleaseStreams() utility
- migrationService.ts: Convert class to functions
- Multiple dialog components: Update imports
- Remove biome-ignore comments from footer, checkbox test, MessageInput, ConnectPage, store test

Fixes issues:
- Settings page stuck in loading state
- Serial stream lock errors on reconnection
- Duplicate connection attempts wiping config data
@danditomaso danditomaso marked this pull request as ready for review February 10, 2026 18:15
Copilot AI review requested due to automatic review settings February 10, 2026 18:15
@vercel
Copy link

vercel bot commented Feb 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
web-test Ready Ready Preview, Comment Feb 10, 2026 9:52pm

Request Review

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR performs a large UI and architecture reshuffle in packages/web, updates core transport/stream handling (serial + packet decode/queue), adds a new mock transport package, and revises i18n strings and tooling (lint/format + git hooks).

Changes:

  • Migrates web app structure to a new src/app/* layout with TanStack Router, sidebar layout, and updated shared UI imports/mocks.
  • Adds @meshtastic/transport-mock package utilities and updates serial transport + core packet stream/queue behavior.
  • Removes vendored/proxy protobuf/UI package files and updates i18n strings + developer tooling (Oxlint/Oxfmt + Husky).

Reviewed changes

Copilot reviewed 177 out of 754 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
packages/web/src/components/Dialog/TracerouteResponseDialog.tsx Removes legacy dialog component (likely migrated/replaced elsewhere).
packages/web/src/components/Dialog/RefreshKeysDialog/useRefreshKeysDialog.ts Removes hook for legacy refresh keys dialog.
packages/web/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.tsx Removes legacy refresh keys dialog UI.
packages/web/src/components/Dialog/PkiRegenerateDialog.tsx Removes legacy PKI regenerate dialog.
packages/web/src/components/Dialog/PKIBackupDialog.tsx Removes legacy PKI backup dialog UI/print/download logic.
packages/web/src/components/Dialog/NewDeviceDialog.tsx Removes legacy new device dialog UI.
packages/web/src/components/Dialog/LocationResponseDialog.tsx Removes legacy location response dialog UI.
packages/web/src/components/Dialog/ImportDialog.tsx Removes legacy import dialog UI.
packages/web/src/components/Dialog/DialogManager.tsx Removes legacy dialog manager mounting point.
packages/web/src/components/Dialog/ClearAllStoresDialog/ClearAllStoresDialog.tsx Removes “Clear All Stores” dialog wrapper usage.
packages/web/src/components/Dialog/ClearAllStoresDialog/ClearAllStoresDialog.test.tsx Removes tests for removed ClearAllStoresDialog.
packages/web/src/app/routerContext.ts Adds typed router context surface (services/repos/stores).
packages/web/src/app/router.ts Adds TanStack router instance.
packages/web/src/app/layouts/index.ts Exports new app layout components.
packages/web/src/app/layouts/AppLayout.tsx Adds new app layout using sidebar/tooltip/Separator and new DialogManager.
packages/web/src/app/index.ts Adds new app entry exports.
packages/web/src/app/App.tsx Adds new app root wiring ThemeProvider + SidebarProvider + Outlet.
packages/web/src/mocks/components/UI/Link.tsx Updates mock to new shared UI link import path.
packages/web/src/mocks/components/UI/Label.tsx Updates mock to new shared UI label import path.
packages/web/src/mocks/components/UI/Checkbox.tsx Updates mock to new shared UI checkbox import path.
packages/web/src/mocks/components/UI/Button.tsx Updates mock to new shared UI button import path.
packages/web/src/mocks/README.md Updates mock documentation/examples to new import paths.
packages/web/src/DeviceWrapper.tsx Removes legacy CurrentDeviceContext wrapper.
packages/web/src/App.tsx Removes old app root/layout plumbing (dialogs, connections fallback, devtools, etc.).
packages/web/public/i18n/locales/zh-TW/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/zh-TW/dialog.json Removes <br /> from import dialog description string.
packages/web/public/i18n/locales/zh-CN/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/uk-UA/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/tr-TR/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/sv-SE/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/ru-RU/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/ru-RU/dialog.json Removes <br /> from import dialog description string.
packages/web/public/i18n/locales/pt-PT/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/pt-BR/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/pl-PL/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/nl-NL/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/ko-KR/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/ja-JP/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/it-IT/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/hu-HU/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/fr-FR/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/fi-FI/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/es-ES/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/en/ui.json Restructures UI i18n keys and adds large Preferences section + new nav labels.
packages/web/public/i18n/locales/en/nodes.json Expands nodes page/table strings and headings.
packages/web/public/i18n/locales/en/moduleConfig.json Renames moduleConfig page tab keys.
packages/web/public/i18n/locales/en/messages.json Restructures messages i18n keys (input/actions/delivery status).
packages/web/public/i18n/locales/en/map.json Adds “positionTrails” label.
packages/web/public/i18n/locales/en/dialog.json Adds deviceShare/removeDevice; removes clearAllStores section; tweaks import description.
packages/web/public/i18n/locales/en/connections.json Adds status/button strings and adjusts empty-state description.
packages/web/public/i18n/locales/en/config.json Adds extensive settings/config i18n structure and database strings.
packages/web/public/i18n/locales/en/common.json Adds extra button labels and unit strings.
packages/web/public/i18n/locales/en/commandPalette.json Removes commandPalette “clearAllStores” entry.
packages/web/public/i18n/locales/en/channels.json Adds user name validation strings.
packages/web/public/i18n/locales/de-DE/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/cs-CZ/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/bg-BG/ui.json Removes <br /> from error page description string.
packages/web/public/i18n/locales/be-BY/ui.json Removes <br /> from error page description string.
packages/web/index.html Switches favicon SVG from /icon.svg to /logo.svg.
packages/web/drizzle.config.ts Adds drizzle-kit config for SQLite migrations/schema paths.
packages/web/components.json Adds shadcn/ui components config for web package.
packages/ui/vite.config.ts Removes UI package build config (package appears removed).
packages/ui/tsconfig.json Removes UI package TS config.
packages/ui/src/lib/utils.ts Removes UI package cn helper (package appears removed).
packages/ui/src/lib/theme/default.css Removes UI package default theme CSS export.
packages/ui/src/lib/components/theme-toggle.tsx Removes UI package ThemeToggle component.
packages/ui/src/lib/components/index.ts Removes UI package components barrel export.
packages/ui/src/lib/components/Sidebar/AppSidebar.tsx Removes UI package AppSidebar component implementation.
packages/ui/src/index.ts Removes UI package public exports.
packages/ui/src/hooks/use-mobile.ts Removes UI package mobile hook.
packages/ui/src/components/ui/tooltip.tsx Removes UI package tooltip component.
packages/ui/src/components/ui/skeleton.tsx Removes UI package skeleton component.
packages/ui/src/components/ui/sheet.tsx Removes UI package sheet component.
packages/ui/src/components/ui/separator.tsx Removes UI package separator component.
packages/ui/src/components/ui/input.tsx Removes UI package input component.
packages/ui/src/components/ui/dropdown-menu.tsx Removes UI package dropdown menu component.
packages/ui/src/components/ui/collapsible.tsx Removes UI package collapsible component.
packages/ui/src/components/ui/button.tsx Removes UI package button component.
packages/ui/src/components/ui/badge.tsx Removes UI package badge component.
packages/ui/src/components/theme-provider.tsx Removes UI package theme provider.
packages/ui/src/app.css Removes UI package app color-scheme CSS.
packages/ui/package.json Removes UI package manifest (package appears removed).
packages/ui/components.json Removes UI package shadcn config.
packages/transport-web-serial/src/transport.ts Adds extra serial debug logging and tweaks disconnect handling comments/errors.
packages/transport-web-serial/src/transport.test.ts Adds regression test ensuring setSignals is not called during connect.
packages/transport-mock/tsconfig.json Adds TS config for new mock transport package.
packages/transport-mock/src/scenarios.ts Adds scenario definitions + helper for mock transport.
packages/transport-mock/src/generators/packets.ts Adds packet generator helpers for mock data.
packages/transport-mock/src/generators/nodes.ts Adds node generator helpers for mock meshes.
packages/transport-mock/src/generators/index.ts Adds generator barrel exports.
packages/transport-mock/package.json Adds new package manifest and build/publish scripts.
packages/transport-mock/mod.ts Adds public entrypoint exports for mock transport package.
packages/transport-mock/README.md Adds documentation for mock transport usage/scenarios.
packages/protobufs/packages/ts/mod.ts Removes workspace protobuf TS entrypoint (vendored protobufs removed).
packages/protobufs/packages/ts/deno.json Removes protobuf package Deno config.
packages/protobufs/packages/ts/README.md Removes protobuf package readme.
packages/protobufs/package.json Removes workspace protobuf package manifest.
packages/protobufs/nanopb.proto Removes nanopb proto file from workspace.
packages/protobufs/meshtastic/xmodem.proto Removes vendored proto definition.
packages/protobufs/meshtastic/xmodem.options Removes nanopb options.
packages/protobufs/meshtastic/telemetry.options Removes nanopb options.
packages/protobufs/meshtastic/storeforward.proto Removes vendored proto definition.
packages/protobufs/meshtastic/storeforward.options Removes nanopb options.
packages/protobufs/meshtastic/rtttl.proto Removes vendored proto definition.
packages/protobufs/meshtastic/rtttl.options Removes nanopb options.
packages/protobufs/meshtastic/remote_hardware.proto Removes vendored proto definition.
packages/protobufs/meshtastic/powermon.proto Removes vendored proto definition.
packages/protobufs/meshtastic/portnums.proto Removes vendored proto definition.
packages/protobufs/meshtastic/paxcount.proto Removes vendored proto definition.
packages/protobufs/meshtastic/mqtt.proto Removes vendored proto definition.
packages/protobufs/meshtastic/mqtt.options Removes nanopb options.
packages/protobufs/meshtastic/module_config.options Removes nanopb options.
packages/protobufs/meshtastic/mesh.options Removes nanopb options.
packages/protobufs/meshtastic/localonly.proto Removes vendored proto definition.
packages/protobufs/meshtastic/interdevice.proto Removes vendored proto definition.
packages/protobufs/meshtastic/interdevice.options Removes nanopb options.
packages/protobufs/meshtastic/deviceonly.proto Removes vendored proto definition.
packages/protobufs/meshtastic/deviceonly.options Removes nanopb options.
packages/protobufs/meshtastic/device_ui.options Removes nanopb options.
packages/protobufs/meshtastic/connection_status.proto Removes vendored proto definition.
packages/protobufs/meshtastic/connection_status.options Removes nanopb options.
packages/protobufs/meshtastic/config.options Removes nanopb options.
packages/protobufs/meshtastic/clientonly.proto Removes vendored proto definition.
packages/protobufs/meshtastic/clientonly.options Removes nanopb options.
packages/protobufs/meshtastic/channel.proto Removes vendored proto definition.
packages/protobufs/meshtastic/channel.options Removes nanopb options.
packages/protobufs/meshtastic/cannedmessages.proto Removes vendored proto definition.
packages/protobufs/meshtastic/cannedmessages.options Removes nanopb options.
packages/protobufs/meshtastic/atak.proto Removes vendored proto definition.
packages/protobufs/meshtastic/atak.options Removes nanopb options.
packages/protobufs/meshtastic/apponly.proto Removes vendored proto definition.
packages/protobufs/meshtastic/apponly.options Removes nanopb options.
packages/protobufs/meshtastic/admin.options Removes nanopb options.
packages/protobufs/deno.json Removes protobuf package root Deno config.
packages/protobufs/buf.yaml Removes buf workspace config.
packages/protobufs/buf.gen.yaml Removes buf codegen config.
packages/protobufs/README.md Removes protobuf package readme.
packages/protobufs/.vscode/settings.json Removes editor settings for protobuf package.
packages/protobufs/.vscode/extensions.json Removes extension recommendations for protobuf package.
packages/protobufs/.gitmodules Removes protobuf submodule config.
packages/protobufs/.gitignore Removes protobuf package ignore file.
packages/protobufs/.github/workflows/pull_request.yml Removes protobuf package CI workflow.
packages/protobufs/.github/workflows/publish.yml Removes protobuf package publish workflow.
packages/protobufs/.github/workflows/create_tag.yml Removes protobuf package tag workflow.
packages/protobufs/.github/workflows/ci.yml Removes protobuf package CI workflow.
packages/protobufs/.github/pull_request_template.md Removes protobuf package PR template.
packages/protobufs/.gitattributes Removes protobuf package attributes file.
packages/core/src/utils/transform/fromDevice.ts Refactors framing parser to emit debug data and recover from malformed headers.
packages/core/src/utils/transform/fromDevice.test.ts Adds test coverage for garbage/broken header recovery and valid packet parsing.
packages/core/src/utils/transform/decodePacket.ts Adjusts log levels/messages when decoding packets/config/channel.
packages/core/src/utils/queue.ts Changes timeout/ack behavior and adds debug logging for queued/sent packets.
packages/core/src/utils/mod.ts Exports new decodePayload utilities from utils module.
packages/core/src/utils/decodePayload.ts Adds portnum-based payload decoding + JSON conversion utilities.
packages/core/src/types.ts Extends PacketMetadata with reply/emoji and hop fields.
packages/core/src/meshDevice.ts Adds pipeline completion logging, two-stage configure flow, and ACK dispatch logic.
package.json Switches tooling to oxlint/oxfmt and sets up husky + lint-staged; bumps protobufs version.
biome.json Removes Biome config.
.oxlintrc.json Adds oxlint configuration.
.oxfmtrc.json Adds oxfmt configuration.
.husky/pre-commit Adds husky pre-commit hook to run lint-staged.
.githooks/_/pre-commit Removes simple-git-hooks pre-commit hook script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1070 to 1075
rxRssi: meshPacket.rxRssi,
rxSnr: meshPacket.rxSnr,
viaMqtt: meshPacket.viaMqtt,
replyId: dataPacket.replyId,
emoji: dataPacket.emoji,
};
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PacketMetadata was updated to include required hop fields (hopsLimit, hopsStart), but the metadata object constructed here does not supply them. This will either fail TypeScript compilation or produce incomplete metadata at runtime. Populate these fields from the underlying mesh packet (e.g., meshPacket.hopLimit/meshPacket.hopStart`) or make the new fields optional if they are not always available.

Copilot uses AI. Check for mistakes.
this.updateMessageACK(dataPacket.requestId, {
receivedACK: true,
ackError: routingPacket.variant.value,
ackTimestamp: meshPacket.rxTime || Date.now(),
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ackTimestampmixes units:meshPacket.rxTimeappears to be seconds-since-epoch, whileDate.now()is milliseconds. Downstream code multipliesackTimestamp * 1000when creating aDate, which will be incorrect if the fallback path is hit. Use consistent units (preferred: seconds everywhere, e.g. meshPacket.rxTime ?? Math.floor(Date.now() / 1000)) and avoid ||here sincerxTimecould be0` (unlikely but semantically wrong).

Suggested change
ackTimestamp: meshPacket.rxTime || Date.now(),
ackTimestamp: meshPacket.rxTime ?? Math.floor(Date.now() / 1000),

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +33
(async () => {
while (true) {
const { value, done } = await reader.read();
if (done) break;
received.push(value);
}
})();

// 1. Send garbage data (no 0x94)
await writer.write(new Uint8Array([0x01, 0x02, 0x03]));

// 2. Send broken header (0x94 but not 0xc3)
await writer.write(new Uint8Array([0x94, 0x00, 0x04]));

// 3. Send valid packet (0x94 0xc3 0x00 0x01 0xAA) (len 1)
// Header: 94 C3 00 01. Payload: AA.
await writer.write(new Uint8Array([0x94, 0xc3, 0x00, 0x01, 0xAA]));

// Give it a moment to process
await new Promise(resolve => setTimeout(resolve, 100));
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is timing-dependent and may be flaky on slower CI runners: it relies on a fixed setTimeout(100) and does not await the background read loop completion before asserting. Prefer awaiting reads deterministically (e.g., read until you receive a packet output or until reader.read() returns done, with an explicit timeout) to make the test reliable and faster.`

Copilot uses AI. Check for mistakes.
"system": "Automatic",
"changeTheme": "Change Color Scheme"
},
"configProgres": "Loading conifg {{received}}/{{total}}",
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new key/value contains typos: configProgres and conifg. This is likely to leak into UI text and also makes the key easy to mis-reference. Consider renaming the key to configProgress and correcting the string to “Loading config {{received}}/{{total}}”.`

Suggested change
"configProgres": "Loading conifg {{received}}/{{total}}",
"configProgress": "Loading config {{received}}/{{total}}",

Copilot uses AI. Check for mistakes.
Comment on lines +258 to +278
/**
* REGRESSION TEST: setSignals() must NOT be called during connection.
*
* Calling setSignals({ dataTerminalReady: false, requestToSend: false })
* prevents the device from responding to config requests. This was
* discovered when the connection would hang during configureTwoStage().
*
* See: https://github.com/meshtastic/meshtastic-web/issues/XXX
*/
it("does NOT call setSignals during connection (regression)", async () => {
const fake = new FakeSerialPort();
const transport = await TransportWebSerial.createFromPort(fake as any);

// Wait for connection to be established
const reader = transport.fromDevice.getReader();
for (let i = 0; i < 3; i++) {
const { value } = await reader.read();
if (value?.type === "status" && value.data.status === Types.DeviceStatusEnum.DeviceConnected) {
break;
}
}
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues here: (1) the issue link placeholder issues/XXX should be replaced with a real issue or removed; and (2) the for (let i = 0; i < 3; i++) read loop may be flaky if more than 3 status messages are emitted before DeviceConnected (or if timing differs). Consider looping until connected with an explicit timeout (or a helper that waits for a specific status event) to make the test deterministic.`

Copilot uses AI. Check for mistakes.
- Fix i18n locale loading to use base language codes (e.g., 'en' instead of 'en-GB')
  - Prevents 404 errors when browser requests specific locale variants
  - Uses custom loadPath function to extract base language code
- Remove missing logo_black.svg reference from index.html
- Ensure all asset paths are absolute for consistency

Fixes 404 errors:
- /i18n/locales/en-GB/*.json -> now loads from /i18n/locales/en/*.json
- /logo_black.svg (file did not exist) -> removed reference
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants