4 Commits

Author SHA1 Message Date
Jack Kingsman
fa1c086f5f Updating changelog + build for 3.0.0 2026-03-10 21:41:04 -07:00
Jack Kingsman
d8bb747152 Reorder themes 2026-03-10 21:27:05 -07:00
Jack Kingsman
18a465fde8 Fix ordering 2026-03-10 21:06:50 -07:00
Jack Kingsman
c52e00d2b7 Merge pull request #50 from jkingsman/notifications
Notifications
2026-03-10 20:49:12 -07:00
10 changed files with 148 additions and 17 deletions

View File

@@ -1,3 +1,28 @@
## [3.0.0] - 2026-03-10
Feature: Custom regions per-channel
Feature: Add custom contact pathing
Feature: Corrupt packets are more clear that they're corrupt
Feature: Better, faster patterns around background fetching with explicit opt-in for recurring sync if the app detects you need it
Feature: More consistent icons
Feature: Add per-channel local notifications
Feature: New themes
Feature: Massive codebase refactor and overhaul
Bugfix: Fix packet parsing for trace packets
Bugfix: Refetch channels on reconnect
Bugfix: Load All on repeater pane on mobile doesn't etend into lower text
Bugfix: Timestamps in logs
Bugfix: Correct wrong clock sync command
Misc: Improve bot error bubble up
Misc: Update to non-lib-included meshcore-decoder version
Misc: Revise refactors to be more LLM friendly
Misc: Fix script executability
Misc: Better logging format with timestamp
Misc: Repeater advert buttons separate flood and one-hop
Misc: Preserve repeater pane on navigation away
Misc: Clearer iconography and coloring for status bar buttons
Misc: Search bar to top bar
## [2.7.9] - 2026-03-08
Bugfix: Don't obscure new integration dropdown on session boundary

View File

@@ -1,7 +1,7 @@
{
"name": "remoteterm-meshcore-frontend",
"private": true,
"version": "2.7.9",
"version": "3.0.0",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -150,7 +150,7 @@ describe('Sidebar section summaries', () => {
expect(screen.queryByText(opsChannel.name)).not.toBeInTheDocument();
expect(screen.queryByText(aliceName)).not.toBeInTheDocument();
const search = screen.getByPlaceholderText('Search...');
const search = screen.getByLabelText('Search conversations');
fireEvent.change(search, { target: { value: 'alice' } });
await waitFor(() => {

View File

@@ -696,3 +696,102 @@
[data-theme='paper-grove'] ::-webkit-scrollbar-thumb:hover {
background: linear-gradient(180deg, hsl(157 34% 46%), hsl(227 34% 52%));
}
/* ── Monochrome ("Workbench") ─────────────────────────────── */
:root[data-theme='monochrome'] {
--background: 0 0% 98%;
--foreground: 0 0% 8%;
--card: 0 0% 100%;
--card-foreground: 0 0% 8%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 8%;
--primary: 0 0% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96%;
--secondary-foreground: 0 0% 10%;
--muted: 0 0% 97%;
--muted-foreground: 0 0% 18%;
--accent: 0 0% 94%;
--accent-foreground: 0 0% 8%;
--destructive: 0 0% 18%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 72%;
--input: 0 0% 72%;
--ring: 0 0% 10%;
--radius: 0.2rem;
--msg-outgoing: 0 0% 92%;
--msg-incoming: 0 0% 98%;
--status-connected: 0 0% 12%;
--status-disconnected: 0 0% 24%;
--warning: 0 0% 22%;
--warning-foreground: 0 0% 98%;
--success: 0 0% 12%;
--success-foreground: 0 0% 98%;
--info: 0 0% 18%;
--info-foreground: 0 0% 98%;
--region-override: 0 0% 14%;
--favorite: 0 0% 10%;
--console: 0 0% 18%;
--console-command: 0 0% 8%;
--console-bg: 0 0% 96%;
--toast-error: 0 0% 96%;
--toast-error-foreground: 0 0% 12%;
--toast-error-border: 0 0% 70%;
--code-editor-bg: 0 0% 96%;
--font-sans: 'Inter', 'Segoe UI', sans-serif;
--font-mono: 'IBM Plex Mono', 'Cascadia Mono', 'SFMono-Regular', monospace;
--scrollbar: 0 0% 18%;
--scrollbar-hover: 0 0% 8%;
--overlay: 0 0% 6%;
}
[data-theme='monochrome'] body {
background: hsl(0 0% 98%);
}
[data-theme='monochrome'] .bg-card,
[data-theme='monochrome'] .bg-popover {
background: hsl(0 0% 100%);
}
[data-theme='monochrome'] .bg-msg-outgoing {
background: hsl(0 0% 92%);
border-left: 2px solid hsl(0 0% 12% / 0.9);
}
[data-theme='monochrome'] .bg-msg-incoming {
background: hsl(0 0% 98%);
border-left: 2px solid hsl(0 0% 12% / 0.35);
}
[data-theme='monochrome'] .bg-primary {
background: hsl(0 0% 10%);
}
[data-theme='monochrome'] button {
border-radius: 0.2rem;
box-shadow: none;
filter: none;
transition:
background-color 0.12s ease,
color 0.12s ease,
border-color 0.12s ease;
}
[data-theme='monochrome'] button:hover {
transform: none;
box-shadow: none;
filter: none;
}
[data-theme='monochrome'] button:active {
transform: none;
}
[data-theme='monochrome'] ::-webkit-scrollbar-thumb {
background: hsl(0 0% 18%);
}
[data-theme='monochrome'] ::-webkit-scrollbar-thumb:hover {
background: hsl(0 0% 8%);
}

View File

@@ -22,18 +22,18 @@ export const THEMES: Theme[] = [
swatches: ['#F8F7F4', '#FFFFFF', '#1B7D4E', '#EDEBE7', '#D97706', '#3B82F6'],
metaThemeColor: '#F8F7F4',
},
{
id: 'paper-grove',
name: 'Paper Grove',
swatches: ['#F7F1E4', '#FFF9EE', '#2F9E74', '#E7DEC8', '#E76F51', '#5C7CFA'],
metaThemeColor: '#F7F1E4',
},
{
id: 'cyberpunk',
name: 'Cyberpunk',
swatches: ['#07080A', '#0D1112', '#00FF41', '#141E17', '#FAFF00', '#FF2E6C'],
metaThemeColor: '#07080A',
},
{
id: 'high-contrast',
name: 'High Contrast',
swatches: ['#000000', '#141414', '#3B9EFF', '#1E1E1E', '#FFB800', '#FF4757'],
metaThemeColor: '#000000',
},
{
id: 'obsidian-glass',
name: 'Obsidian Glass',
@@ -59,10 +59,16 @@ export const THEMES: Theme[] = [
metaThemeColor: '#140F24',
},
{
id: 'paper-grove',
name: 'Paper Grove',
swatches: ['#F7F1E4', '#FFF9EE', '#2F9E74', '#E7DEC8', '#E76F51', '#5C7CFA'],
metaThemeColor: '#F7F1E4',
id: 'high-contrast',
name: 'High Contrast',
swatches: ['#000000', '#141414', '#3B9EFF', '#1E1E1E', '#FFB800', '#FF4757'],
metaThemeColor: '#000000',
},
{
id: 'monochrome',
name: 'Monochrome',
swatches: ['#FAFAFA', '#FFFFFF', '#111111', '#EAEAEA', '#8A8A8A', '#4A4A4A'],
metaThemeColor: '#FAFAFA',
},
];

View File

@@ -1,6 +1,6 @@
[project]
name = "remoteterm-meshcore"
version = "2.7.9"
version = "3.0.0"
description = "RemoteTerm - Web interface for MeshCore radio mesh networks"
readme = "README.md"
requires-python = ">=3.10"

View File

@@ -71,7 +71,8 @@ echo -n " package.json: "
grep '"version"' frontend/package.json | head -1 | sed 's/.*"version": "\(.*\)".*/\1/'
echo
read -p "Enter new version (e.g., 1.2.3): " VERSION
read -r -p "Enter new version (e.g., 1.2.3): " VERSION
VERSION="$(printf '%s' "$VERSION" | tr -d '\r' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
if [[ ! $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo -e "${RED}Error: Version must be in format X.Y.Z${NC}"

View File

@@ -8,7 +8,7 @@ test.describe('Health & UI basics', () => {
await expect(page.getByRole('status', { name: 'Radio OK' })).toBeVisible();
// Sidebar is visible with key sections
await expect(page.getByRole('heading', { name: 'Conversations' })).toBeVisible();
await expect(page.getByRole('navigation', { name: 'Conversations' })).toBeVisible();
await expect(page.getByText('Packet Feed')).toBeVisible();
await expect(page.getByText('Node Map')).toBeVisible();
});

View File

@@ -34,7 +34,7 @@ test.describe('Sidebar search/filter', () => {
await expect(page.getByText(nameB, { exact: true })).toBeVisible();
// Type partial name to filter
const searchInput = page.getByPlaceholder('Search...');
const searchInput = page.getByLabel('Search conversations');
await searchInput.fill(`alpha${suffix}`);
// Only nameA should be visible

2
uv.lock generated
View File

@@ -1049,7 +1049,7 @@ wheels = [
[[package]]
name = "remoteterm-meshcore"
version = "2.7.9"
version = "3.0.0"
source = { virtual = "." }
dependencies = [
{ name = "aiomqtt" },