mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 06:25:41 +00:00
feat(dev): run dev alongside release with shared app data (#866)
* feat(dev): run dev alongside release with shared app data Skip tauri-plugin-single-instance in debug builds so `tauri dev` can run while an installed release instance is open. Keep the same bundle identifier and data directory; label the dev window "Psysonic (Dev)". * fix(dev): gate on_second_instance behind release cfg Avoid dead_code warning in debug builds where single-instance is skipped. * feat(dev): red sidebar brand and monochrome titlebar chrome Tag the document in Vite dev and style the logo header with a red background plus gray window controls so dev is obvious at a glance. * feat(dev): skip OS hotkeys and add mobile DEV markers Debug builds no longer register global shortcuts, MPRIS, or Windows taskbar media controls so release keeps system input when both run. Flip the tray icon horizontally in dev and show a fixed DEV badge on narrow layouts. * docs(changelog): note PR #866 parallel dev alongside release * fix(dev): satisfy clippy needless_return in debug-only paths
This commit is contained in:
@@ -189,6 +189,9 @@ export function AppShell() {
|
||||
onContextMenu={e => e.preventDefault()}
|
||||
>
|
||||
{IS_LINUX && useCustomTitlebar && !isWindowFullscreen && !isTilingWm && <TitleBar />}
|
||||
{import.meta.env.DEV && isMobile && (
|
||||
<span className="dev-build-badge" aria-hidden>DEV</span>
|
||||
)}
|
||||
{!isMobile && (
|
||||
<Sidebar
|
||||
isCollapsed={isSidebarCollapsed}
|
||||
|
||||
@@ -35,10 +35,18 @@ export function pushLoggingModeToBackend(): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Mark the document in Vite dev so CSS can show dev-only chrome. */
|
||||
export function markDevBuildDocument(): void {
|
||||
if (import.meta.env.DEV) {
|
||||
document.documentElement.dataset.devBuild = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
/** Orchestrates everything that must run before React mounts. */
|
||||
export function runPreReactBootstrap(): void {
|
||||
// Pre-warm the window-kind cache so subsequent reads are sync + safe.
|
||||
getWindowKind();
|
||||
markDevBuildDocument();
|
||||
pushUserAgentToBackend();
|
||||
pushLoggingModeToBackend();
|
||||
installQueueUndoHotkey();
|
||||
|
||||
@@ -4,6 +4,9 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
import { MODIFIER_KEY_CODES, formatBinding } from './keybindingsStore';
|
||||
import { DEFAULT_GLOBAL_SHORTCUTS, isGlobalShortcutActionId, type GlobalAction } from '../config/shortcutActions';
|
||||
|
||||
/** Dev builds run alongside release — OS-level grabs stay on the release instance. */
|
||||
const GLOBAL_SHORTCUTS_OS_ENABLED = !import.meta.env.DEV;
|
||||
|
||||
/** Build a Tauri-compatible shortcut string from a KeyboardEvent, or null if invalid. */
|
||||
export function buildGlobalShortcut(e: KeyboardEvent): string | null {
|
||||
if ((MODIFIER_KEY_CODES as readonly string[]).includes(e.code)) return null;
|
||||
@@ -42,15 +45,19 @@ export const useGlobalShortcutsStore = create<GlobalShortcutsState>()(
|
||||
|
||||
setShortcut: async (action, shortcut) => {
|
||||
const prev = get().shortcuts[action];
|
||||
if (prev) {
|
||||
if (GLOBAL_SHORTCUTS_OS_ENABLED && prev) {
|
||||
try { await invoke('unregister_global_shortcut', { shortcut: prev }); } catch {}
|
||||
}
|
||||
if (shortcut) {
|
||||
try {
|
||||
await invoke('register_global_shortcut', { shortcut, action });
|
||||
if (GLOBAL_SHORTCUTS_OS_ENABLED) {
|
||||
try {
|
||||
await invoke('register_global_shortcut', { shortcut, action });
|
||||
set(s => ({ shortcuts: { ...s.shortcuts, [action]: shortcut } }));
|
||||
} catch (e) {
|
||||
console.warn('[GlobalShortcuts] Failed to register:', shortcut, e);
|
||||
}
|
||||
} else {
|
||||
set(s => ({ shortcuts: { ...s.shortcuts, [action]: shortcut } }));
|
||||
} catch (e) {
|
||||
console.warn('[GlobalShortcuts] Failed to register:', shortcut, e);
|
||||
}
|
||||
} else {
|
||||
set(s => {
|
||||
@@ -62,6 +69,7 @@ export const useGlobalShortcutsStore = create<GlobalShortcutsState>()(
|
||||
},
|
||||
|
||||
registerAll: async () => {
|
||||
if (!GLOBAL_SHORTCUTS_OS_ENABLED) return;
|
||||
if (_registerAllCalled) return;
|
||||
_registerAllCalled = true;
|
||||
const { shortcuts } = get();
|
||||
@@ -79,9 +87,11 @@ export const useGlobalShortcutsStore = create<GlobalShortcutsState>()(
|
||||
|
||||
resetAll: async () => {
|
||||
const { shortcuts } = get();
|
||||
for (const shortcut of Object.values(shortcuts)) {
|
||||
if (shortcut) {
|
||||
try { await invoke('unregister_global_shortcut', { shortcut }); } catch {}
|
||||
if (GLOBAL_SHORTCUTS_OS_ENABLED) {
|
||||
for (const shortcut of Object.values(shortcuts)) {
|
||||
if (shortcut) {
|
||||
try { await invoke('unregister_global_shortcut', { shortcut }); } catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
set({ shortcuts: { ...DEFAULT_GLOBAL_SHORTCUTS } });
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Dev-only chrome: shared data dir with prod, but visually unmistakable. */
|
||||
html[data-dev-build] .sidebar-brand {
|
||||
background: #b91c1c;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.22);
|
||||
}
|
||||
|
||||
html[data-dev-build] .sidebar-brand svg {
|
||||
--logo-color-start: #fff;
|
||||
--logo-color-end: #fecaca;
|
||||
}
|
||||
|
||||
html[data-dev-build] .titlebar-btn-close,
|
||||
html[data-dev-build] .titlebar-btn-minimize,
|
||||
html[data-dev-build] .titlebar-btn-maximize {
|
||||
background: #8b8b8b;
|
||||
}
|
||||
|
||||
html[data-dev-build] .titlebar-btn-close:hover,
|
||||
html[data-dev-build] .titlebar-btn-minimize:hover,
|
||||
html[data-dev-build] .titlebar-btn-maximize:hover {
|
||||
background: #a3a3a3;
|
||||
box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
html[data-dev-build] .titlebar-btn-close:hover,
|
||||
html[data-dev-build] .titlebar-btn-minimize:hover,
|
||||
html[data-dev-build] .titlebar-btn-maximize:hover {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
html[data-dev-build] .titlebar-btn:focus-visible {
|
||||
box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.18), 0 0 0 2px rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
|
||||
/* Narrow/mobile: sidebar logo is hidden — fixed red DEV square top-left. */
|
||||
html[data-dev-build] .dev-build-badge {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html[data-dev-build] .app-shell[data-mobile] .dev-build-badge {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10050;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #b91c1c;
|
||||
color: #fff;
|
||||
font-family: var(--font-ui, system-ui, sans-serif);
|
||||
font-size: 9px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.05em;
|
||||
line-height: 1;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html[data-dev-build] .app-shell[data-mobile][data-titlebar] .dev-build-badge {
|
||||
top: var(--titlebar-height);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
@import './_intro.css';
|
||||
@import './dev-build-chrome.css';
|
||||
@import './custom-title-bar-linux-only-decorations-false.css';
|
||||
@import './resizer-handles.css';
|
||||
@import './sidebar.css';
|
||||
|
||||
Reference in New Issue
Block a user